├── LICENSE ├── README.md ├── conf ├── activiti.properties ├── db.sql ├── go-workflow.sql └── init.sql ├── db └── conn.go ├── engine ├── activitiEngineAgenda.go ├── activityBehavior.go ├── behavior │ ├── abstractCommandInterceptor.go │ ├── abstractOperation.go │ ├── command.go │ ├── commandContext.go │ ├── commandContextFactory.go │ ├── commandContextInterceptor.go │ ├── commandExecutor.go │ ├── commandExecutorImpl.go │ ├── commandInterceptor.go │ ├── commandInvoker.go │ ├── context.go │ ├── continueProcessOperation.go │ ├── converter.go │ ├── defaultActivitiEngineAgenda.go │ ├── endExecutionOperation.go │ ├── exclusiveGatewayActivityBehavior.go │ ├── flowNodeActivityBehavior.go │ ├── inclusiveGatewayActivityBehavior.go │ ├── processEngineConfiguration.go │ ├── processUtils.go │ ├── serviceImpl.go │ ├── takeOutgoingSequenceFlowsOperation.go │ ├── tiggerableActivityBehavior.go │ ├── transactionContextInterceptor.go │ ├── triggerExecutionOperation.go │ ├── userAutoTaskActivityBehavior.go │ └── userTaskActivityBehavior.go ├── cmd │ ├── backTaskCmd.go │ ├── completeCmd.go │ ├── deployProcessCmd.go │ ├── getTaskCmd.go │ └── startProcessInstanceByKeyCmd.go ├── common │ └── activitiCommon.go ├── entityImpl │ ├── executionEntityImpl.go │ └── taskEntityImpl.go ├── executionEntity.go ├── handler │ ├── iActiviti.go │ └── iActivitiDemo.go ├── manager │ └── dbManager.go ├── operation.go ├── persistence │ ├── defineManager.go │ ├── deploymentManager.go │ ├── historicActinstManager.go │ ├── historicIdentityLinkManager.go │ ├── historicProcessManager.go │ ├── historicTaskManager.go │ ├── historicVariableManager.go │ ├── identityLinkManager.go │ ├── processInstanceManager.go │ ├── taskManager.go │ └── variableManager.go ├── process.go ├── service │ ├── repositoryService.go │ ├── runtimeService.go │ └── taskService.go ├── utils │ ├── conditionUtil.go │ └── executionGraphUtil.go ├── variable │ ├── boolType.go │ ├── defaultVariableTypes.go │ ├── historicVariable.go │ ├── intType.go │ ├── mapType.go │ ├── stringType.go │ ├── valueFields.go │ ├── variable.go │ ├── variableInstanceEntity.go │ ├── variableType.go │ └── variableTypes.go └── variableScope.go ├── entity ├── identityLinkEntity.go ├── processInstanceEntity.go ├── taskEntity.go └── variableEntity.go ├── errs ├── errs.go └── processError.go ├── event ├── activitiEntityEvent.go ├── activitiEvent.go ├── activitiEventDispatcher.go ├── activitiEventDispatcherImpl.go ├── activitiEventListener.go ├── activitiEventSupport.go └── impl │ ├── activitiEntityEventImpl.go │ ├── activitiEventBuilder.go │ └── activitiEventImpl.go ├── go.mod ├── main.go ├── model ├── bytearry.go ├── deployment.go ├── historicActinst.go ├── historicIdentityLink.go ├── historicProcinst.go ├── historicTask.go ├── identityLink.go ├── procinst.go └── task.go ├── resources ├── process_demo.bpmn20.xml ├── userAuto.bpmn20.xml └── userTest.bpmn20.xml ├── runtime └── runtime.go ├── templates └── index.html ├── test └── process_test.go └── web ├── handlers.go └── response.go /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Go语言流程引擎go-activiti 2 | 项目传送门[go-activiti](https://github.com/lios/go-activiti) 3 | 4 | 参考[Activiti](https://github.com/Activiti/Activiti)实现,满足部分功能。项目还在完善中,欢迎activiti爱好者加入,Go语言她不香么。 5 | 6 | 7 | 现有能力 8 | 9 | - 节点类型,支持用户审批节点、排他网关、包容网关、并行网关 10 | - 流程功能,支持流程部署、流程发起、流程审批,流程驳回 11 | - 支持历史数据回溯 12 | - 全局事务 13 | - 全局事件监听,现支持节点事件处理 14 | - 节点事件回调 15 | 16 | 17 | 18 | BPMN文件解析,先使用的是JSON库,使用方便,但存在缺陷,不支持扩展后续完善件[process](https://github.com/lios/go-activiti/blob/master/engine/process.go)。 19 | 20 | 21 | 22 | ## 全局事务 23 | 24 | 参考activiti设计模式,依赖命令模式和责任链模式,使用gorm的事务能力,不需要关注事务。 25 | 26 | ``` 27 | defer db.ClearTXDB() 28 | db.GORM_DB.Transaction(func(tx *gorm.DB) error { 29 | db.InitTXDB(tx) 30 | value, err = transactionContextInterceptor.Next.Execute(command) 31 | return err 32 | }) 33 | ``` 34 | 35 | ## **流程事件监听* 36 | 需实现ActivitiEventListener,将实现类加入配置文件 37 | 38 | ```java 39 | type ActivitiListener struct { 40 | name string 41 | } 42 | 43 | func (act ActivitiListener) OnEvent(event event.ActivitiEvent) error { 44 | fmt.Println(event) 45 | return nil 46 | } 47 | ``` 48 | 49 | ```go 50 | configuration := behavior.GetProcessEngineConfiguration() 51 | eventListeners := make([]event.ActivitiEventListener, 0) 52 | eventListeners = append(eventListeners, ActivitiListener{}) 53 | configuration.AddEventListeners(eventListeners) 54 | ``` 55 | 56 | ## 节点事件回调 57 | 需实现IActiviti,注册构造器,参考iActivitiDemo.go文件 58 | 59 | ```java 60 | func init() { 61 | RegisterConstructor("userAuto", NewTestIActiviti) 62 | } 63 | 64 | func NewTestIActiviti(entity ExecutionEntity) IActiviti { 65 | return &TestIActiviti{ 66 | Entity: entity, 67 | } 68 | } 69 | ``` 70 | 71 | 后续计划: 72 | 73 | 74 | - 支持更多节点类型 75 | - bpmn解析完善,可扩展 76 | - 流程能力支持:流程跳转,撤销等等 77 | - 日志打印(优先) 78 | - 数据库默认值处理 79 | - 项目结构调整 80 | 81 | 期待您的加入。 82 | 83 | -------------------------------------------------------------------------------- /conf/activiti.properties: -------------------------------------------------------------------------------- 1 | [mysql] 2 | username=root 3 | password=1234 4 | url=127.0.0.1:3306/go-workflow 5 | host=127.0.0.1 6 | port=3306 7 | dbname=go-workflow 8 | charset=utf8 9 | 10 | -------------------------------------------------------------------------------- /conf/db.sql: -------------------------------------------------------------------------------- 1 | /* 2 | Navicat MySQL Data Transfer 3 | 4 | Source Server : 本地 5 | Source Server Version : 50018 6 | Source Host : localhost:3306 7 | Source Database : go-workflow 8 | 9 | Target Server Type : MYSQL 10 | Target Server Version : 50018 11 | File Encoding : 65001 12 | 13 | Date: 2020-07-07 23:57:52 14 | */ 15 | 16 | SET FOREIGN_KEY_CHECKS=0; 17 | 18 | -- ---------------------------- 19 | -- Table structure for bytearry 20 | -- ---------------------------- 21 | DROP TABLE IF EXISTS `bytearry`; 22 | CREATE TABLE `bytearry` ( 23 | `id` bigint(20) NOT NULL auto_increment COMMENT '主键id', 24 | `name` varchar(64) collate utf8_bin default NULL COMMENT '名称', 25 | `key` varchar(64) collate utf8_bin default NULL COMMENT '流程定义key', 26 | `version` bigint(2) default NULL COMMENT '版本', 27 | `deployment_id` bigint(64) default NULL COMMENT '流程部署id', 28 | `bytes` longblob COMMENT '资源文件', 29 | PRIMARY KEY (`id`) 30 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; 31 | 32 | -- ---------------------------- 33 | -- Table structure for deployment 34 | -- ---------------------------- 35 | DROP TABLE IF EXISTS `deployment`; 36 | CREATE TABLE `deployment` ( 37 | `id` bigint(20) NOT NULL auto_increment COMMENT '主键id', 38 | `name` varchar(64) collate utf8_bin default NULL COMMENT '名称', 39 | `key` varchar(64) collate utf8_bin default NULL COMMENT '流程定义key', 40 | `version` bigint(2) default NULL COMMENT '版本', 41 | `tenantI_id` bigint(64) default NULL COMMENT '租户id', 42 | `deploy_time` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP COMMENT '部署时间', 43 | PRIMARY KEY (`id`) 44 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; 45 | 46 | -- ---------------------------- 47 | -- Table structure for identity_link 48 | -- ---------------------------- 49 | DROP TABLE IF EXISTS `identity_link`; 50 | CREATE TABLE `identity_link` ( 51 | `id` bigint(20) NOT NULL auto_increment COMMENT '主键id', 52 | `type` varchar(64) collate utf8_bin default NULL COMMENT '类型', 53 | `task_id` varchar(64) collate utf8_bin default NULL COMMENT '任务ID', 54 | `proc_inst_id` bigint(2) default NULL COMMENT '流程实例id', 55 | `group_id` bigint(64) default NULL COMMENT '组id', 56 | `user_id` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP COMMENT '用户id', 57 | PRIMARY KEY (`id`) 58 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; 59 | 60 | -- ---------------------------- 61 | -- Table structure for process_instance 62 | -- ---------------------------- 63 | DROP TABLE IF EXISTS `process_instance`; 64 | CREATE TABLE `process_instance` ( 65 | `id` bigint(20) NOT NULL auto_increment COMMENT '主键id', 66 | `key` varchar(64) collate utf8_bin default NULL COMMENT '流程定义key', 67 | `name` varchar(64) collate utf8_bin default NULL COMMENT '名称', 68 | `version` bigint(2) default NULL COMMENT '版本', 69 | `business_key` varchar(64) collate utf8_bin default NULL, 70 | `tenant_id` varchar(64) collate utf8_bin default NULL COMMENT '租户id', 71 | `deployment_id` bigint(64) default NULL COMMENT '流程部署id', 72 | `start_time` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP COMMENT '启动时间', 73 | `start_user_id` varchar(64) collate utf8_bin default NULL COMMENT '启动用户', 74 | PRIMARY KEY (`id`) 75 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; 76 | 77 | -- ---------------------------- 78 | -- Table structure for task 79 | -- ---------------------------- 80 | DROP TABLE IF EXISTS `task`; 81 | CREATE TABLE `task` ( 82 | `id` bigint(20) NOT NULL auto_increment COMMENT '主键id', 83 | `task_define_key` varchar(64) collate utf8_bin default NULL COMMENT '任务key', 84 | `task_define_name` varchar(64) collate utf8_bin default NULL COMMENT '任务名称', 85 | `version` bigint(2) default NULL COMMENT '版本', 86 | `tenant_id` varchar(64) collate utf8_bin default NULL COMMENT '租户id', 87 | `deployment_id` bigint(64) default NULL COMMENT '流程部署id', 88 | `start_time` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP COMMENT '启动时间', 89 | `assignee` varchar(64) collate utf8_bin default NULL COMMENT '审批人', 90 | `proc_inst_id` bigint(64) default NULL COMMENT '实例iD', 91 | PRIMARY KEY (`id`) 92 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; 93 | 94 | -- ---------------------------- 95 | -- Table structure for task 96 | -- ---------------------------- 97 | DROP TABLE IF EXISTS `variable`; 98 | CREATE TABLE `variable` ( 99 | `id` bigint(20) NOT NULL auto_increment COMMENT '主键id', 100 | `version` bigint(2) default NULL COMMENT '版本', 101 | `task_id` varchar(64) collate utf8_bin default NULL COMMENT '任务ID', 102 | `proc_inst_id` bigint(2) default NULL COMMENT '流程实例id', 103 | `name` varchar(64) collate utf8_bin default NULL COMMENT '变量名', 104 | `type` varchar(10) default NULL COMMENT '类型', 105 | `number` int default NULL COMMENT '类型', 106 | `date` datetime default NULL COMMENT '时间类型', 107 | `float` double collate utf8_bin default NULL COMMENT 'double', 108 | `text` varchar(4000) default NULL COMMENT '字符', 109 | `blob` longblob default NULL COMMENT '字符串', 110 | PRIMARY KEY (`id`) 111 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; 112 | 113 | -------------------------------------------------------------------------------- /conf/go-workflow.sql: -------------------------------------------------------------------------------- 1 | /* 2 | Navicat MySQL Data Transfer 3 | 4 | Source Server : 本地 5 | Source Server Version : 50018 6 | Source Host : localhost:3306 7 | Source Database : go-workflow 8 | 9 | Target Server Type : MYSQL 10 | Target Server Version : 50018 11 | File Encoding : 65001 12 | 13 | Date: 2020-07-25 22:11:13 14 | */ 15 | 16 | SET FOREIGN_KEY_CHECKS=0; 17 | 18 | -- ---------------------------- 19 | -- Table structure for bytearry 20 | -- ---------------------------- 21 | DROP TABLE IF EXISTS `bytearry`; 22 | CREATE TABLE `bytearry` ( 23 | `id` bigint(20) NOT NULL auto_increment COMMENT '主键id', 24 | `name` varchar(64) collate utf8_bin default NULL COMMENT '名称', 25 | `key` varchar(64) collate utf8_bin default NULL COMMENT '流程定义key', 26 | `version` bigint(2) default NULL COMMENT '版本', 27 | `deployment_id` bigint(64) default NULL COMMENT '流程部署id', 28 | `bytes` longblob COMMENT '资源文件', 29 | PRIMARY KEY (`id`) 30 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; 31 | 32 | -- ---------------------------- 33 | -- Table structure for deployment 34 | -- ---------------------------- 35 | DROP TABLE IF EXISTS `deployment`; 36 | CREATE TABLE `deployment` ( 37 | `id` bigint(20) NOT NULL auto_increment COMMENT '主键id', 38 | `name` varchar(64) collate utf8_bin default NULL COMMENT '名称', 39 | `key` varchar(64) collate utf8_bin default NULL COMMENT '流程定义key', 40 | `version` bigint(2) default NULL COMMENT '版本', 41 | `tenant_id` varchar(64) default NULL COMMENT '租户id', 42 | `deploy_time` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP COMMENT '部署时间', 43 | PRIMARY KEY (`id`) 44 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; 45 | 46 | -- ---------------------------- 47 | -- Table structure for identity_link 48 | -- ---------------------------- 49 | DROP TABLE IF EXISTS `identity_link`; 50 | CREATE TABLE `identity_link` ( 51 | `id` bigint(20) NOT NULL auto_increment COMMENT '主键id', 52 | `type` varchar(64) collate utf8_bin default NULL COMMENT '类型', 53 | `task_id` varchar(64) collate utf8_bin default NULL COMMENT '任务ID', 54 | `proc_inst_id` bigint(2) default NULL COMMENT '流程实例id', 55 | `group_id` bigint(64) default NULL COMMENT '组id', 56 | `user_id` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP COMMENT '用户id', 57 | PRIMARY KEY (`id`) 58 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; 59 | 60 | -- ---------------------------- 61 | -- Table structure for process_instance 62 | -- ---------------------------- 63 | DROP TABLE IF EXISTS `process_instance`; 64 | CREATE TABLE `process_instance` ( 65 | `id` bigint(20) NOT NULL auto_increment COMMENT '主键id', 66 | `key` varchar(64) collate utf8_bin default NULL COMMENT '流程定义key', 67 | `name` varchar(64) collate utf8_bin default NULL COMMENT '名称', 68 | `version` bigint(2) default NULL COMMENT '版本', 69 | `business_key` varchar(64) collate utf8_bin default NULL, 70 | `tenant_id` varchar(64) collate utf8_bin default NULL COMMENT '租户id', 71 | `deployment_id` bigint(20) default NULL COMMENT '流程部署id', 72 | `start_time` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP COMMENT '启动时间', 73 | `start_user_id` varchar(64) collate utf8_bin default NULL COMMENT '启动用户', 74 | `process_define_id` bigint(20) default NULL, 75 | PRIMARY KEY (`id`) 76 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; 77 | 78 | -- ---------------------------- 79 | -- Table structure for task 80 | -- ---------------------------- 81 | DROP TABLE IF EXISTS `task`; 82 | CREATE TABLE `task` ( 83 | `id` bigint(20) NOT NULL auto_increment COMMENT '主键id', 84 | `task_define_key` varchar(64) collate utf8_bin default NULL COMMENT '任务key', 85 | `task_define_name` varchar(64) collate utf8_bin default NULL COMMENT '任务名称', 86 | `version` bigint(2) default NULL COMMENT '版本', 87 | `tenant_id` varchar(64) collate utf8_bin default NULL COMMENT '租户id', 88 | `deployment_id` bigint(64) default NULL COMMENT '流程部署id', 89 | `start_time` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP COMMENT '启动时间', 90 | `assignee` varchar(64) collate utf8_bin default NULL COMMENT '审批人', 91 | `proc_inst_id` bigint(64) default NULL COMMENT '实例iD', 92 | PRIMARY KEY (`id`) 93 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; 94 | 95 | -- ---------------------------- 96 | -- Table structure for variable 97 | -- ---------------------------- 98 | DROP TABLE IF EXISTS `variable`; 99 | CREATE TABLE `variable` ( 100 | `id` bigint(20) NOT NULL auto_increment COMMENT '主键id', 101 | `version` bigint(2) default NULL COMMENT '版本', 102 | `task_id` varchar(64) collate utf8_bin default NULL COMMENT '任务ID', 103 | `proc_inst_id` bigint(2) default NULL COMMENT '流程实例id', 104 | `name` varchar(64) collate utf8_bin default NULL COMMENT '变量名', 105 | `type` varchar(10) collate utf8_bin default NULL COMMENT '类型', 106 | `number` int(11) default NULL COMMENT '类型', 107 | `date` datetime default NULL COMMENT '时间类型', 108 | `float` double default NULL COMMENT 'double', 109 | `text` varchar(4000) collate utf8_bin default NULL COMMENT '字符', 110 | `blob` longblob COMMENT '字符串', 111 | PRIMARY KEY (`id`) 112 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; 113 | 114 | -- ---------------------------- 115 | -- Table structure for hi_identity_link 116 | -- ---------------------------- 117 | DROP TABLE IF EXISTS `hi_identity_link`; 118 | CREATE TABLE `hi_identity_link` ( 119 | `id` bigint(20) NOT NULL auto_increment COMMENT '主键id', 120 | `type` varchar(64) collate utf8_bin default NULL COMMENT '类型', 121 | `task_id` varchar(64) collate utf8_bin default NULL COMMENT '任务ID', 122 | `proc_inst_id` bigint(2) default NULL COMMENT '流程实例id', 123 | `group_id` bigint(64) default NULL COMMENT '组id', 124 | `user_id` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP COMMENT '用户id', 125 | PRIMARY KEY (`id`) 126 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; 127 | 128 | -- ---------------------------- 129 | -- Table structure for hi_process_instance 130 | -- ---------------------------- 131 | DROP TABLE IF EXISTS `hi_process_instance`; 132 | CREATE TABLE `hi_process_instance` ( 133 | `id` bigint(20) NOT NULL auto_increment COMMENT '主键id', 134 | `key` varchar(64) collate utf8_bin default NULL COMMENT '流程定义key', 135 | `name` varchar(64) collate utf8_bin default NULL COMMENT '名称', 136 | `version` bigint(2) default NULL COMMENT '版本', 137 | `business_key` varchar(64) collate utf8_bin default NULL, 138 | `tenant_id` varchar(64) collate utf8_bin default NULL COMMENT '租户id', 139 | `deployment_id` bigint(20) default NULL COMMENT '流程部署id', 140 | `start_time` timestamp NULL default NULL COMMENT '启动时间', 141 | `end_time` timestamp NULL default NULL COMMENT '结束时间', 142 | `start_user_id` varchar(64) collate utf8_bin default NULL COMMENT '启动用户', 143 | `process_define_id` bigint(20) default NULL, 144 | `proc_inst_id` bigint(64) default NULL COMMENT '实例id', 145 | PRIMARY KEY (`id`) 146 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; 147 | 148 | -- ---------------------------- 149 | -- Table structure for hi_task 150 | -- ---------------------------- 151 | DROP TABLE IF EXISTS `hi_task`; 152 | CREATE TABLE `hi_task` ( 153 | `id` bigint(20) NOT NULL auto_increment COMMENT '主键id', 154 | `task_define_key` varchar(64) collate utf8_bin default NULL COMMENT '任务key', 155 | `task_define_name` varchar(64) collate utf8_bin default NULL COMMENT '任务名称', 156 | `version` bigint(2) default NULL COMMENT '版本', 157 | `tenant_id` varchar(64) collate utf8_bin default NULL COMMENT '租户id', 158 | `deployment_id` bigint(64) default NULL COMMENT '流程部署id', 159 | `start_time` timestamp NULL default NULL COMMENT '启动时间', 160 | `end_time` timestamp NULL default NULL COMMENT '结束时间', 161 | `assignee` varchar(64) collate utf8_bin default NULL COMMENT '审批人', 162 | `proc_inst_id` bigint(64) default NULL COMMENT '实例id', 163 | `task_id` bigint(64) default NULL COMMENT '运行任务id', 164 | PRIMARY KEY (`id`) 165 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; 166 | 167 | 168 | -- ---------------------------- 169 | -- Table structure for hi_variable 170 | -- ---------------------------- 171 | DROP TABLE IF EXISTS `hi_variable`; 172 | CREATE TABLE `hi_variable` ( 173 | `id` bigint(20) NOT NULL auto_increment COMMENT '主键id', 174 | `version` bigint(2) default NULL COMMENT '版本', 175 | `task_id` varchar(64) collate utf8_bin default NULL COMMENT '任务ID', 176 | `proc_inst_id` bigint(2) default NULL COMMENT '流程实例id', 177 | `name` varchar(64) collate utf8_bin default NULL COMMENT '变量名', 178 | `type` varchar(10) collate utf8_bin default NULL COMMENT '类型', 179 | `number` int(11) default NULL COMMENT '类型', 180 | `date` datetime default NULL COMMENT '时间类型', 181 | `float` double default NULL COMMENT 'double', 182 | `text` varchar(4000) collate utf8_bin default NULL COMMENT '字符', 183 | `blob` longblob COMMENT '字符串', 184 | PRIMARY KEY (`id`) 185 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; 186 | 187 | -- ---------------------------- 188 | -- Table structure for hi_actinst 189 | -- ---------------------------- 190 | DROP TABLE IF EXISTS `hi_actinst`; 191 | CREATE TABLE `hi_actinst` ( 192 | `id` bigint(20) NOT NULL auto_increment COMMENT '主键id', 193 | `task_id` varchar(64) collate utf8_bin default NULL COMMENT '任务ID', 194 | `proc_inst_id` bigint(2) default NULL COMMENT '流程实例id', 195 | `act_id` varchar(64) collate utf8_bin default NULL COMMENT '实例Id', 196 | `act_name` varchar(64) collate utf8_bin default NULL COMMENT '实例名称', 197 | `act_type` varchar(10) collate utf8_bin default NULL COMMENT '实例类型', 198 | `start_time` timestamp NULL default NULL COMMENT '启动时间', 199 | `end_time` timestamp NULL default NULL COMMENT '结束时间', 200 | `assignee` varchar(64) collate utf8_bin default NULL COMMENT '审批人', 201 | `start_user_id` varchar(64) collate utf8_bin default NULL COMMENT '启动用户', 202 | `process_define_id` bigint(20) default NULL, 203 | `tenant_id` varchar(64) collate utf8_bin default NULL COMMENT '租户id', 204 | PRIMARY KEY (`id`) 205 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; 206 | 207 | -------------------------------------------------------------------------------- /conf/init.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lios/go-activiti/8b75618ebe7d928903c4643a2f9b15ecad9c4c31/conf/init.sql -------------------------------------------------------------------------------- /db/conn.go: -------------------------------------------------------------------------------- 1 | package db 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "github.com/Unknwon/goconfig" 7 | _ "github.com/go-sql-driver/mysql" 8 | "github.com/jinzhu/gorm" 9 | "github.com/lios/go-activiti/runtime" 10 | "os" 11 | "os/exec" 12 | "path/filepath" 13 | "strings" 14 | "sync" 15 | ) 16 | 17 | var GORM_DB *gorm.DB 18 | 19 | var TXDB *sync.Map 20 | 21 | var DNS string 22 | 23 | var ROOT string 24 | 25 | const mainIniPath = "/conf/activiti.properties" 26 | 27 | func init() { 28 | curFilename := os.Args[0] 29 | binaryPath, err := exec.LookPath(curFilename) 30 | if err != nil { 31 | panic(err) 32 | } 33 | 34 | binaryPath, err = filepath.Abs(binaryPath) 35 | if err != nil { 36 | panic(err) 37 | } 38 | 39 | ROOT = filepath.Dir(filepath.Dir(binaryPath)) 40 | 41 | configPath := ROOT + mainIniPath 42 | 43 | if !fileExist(configPath) { 44 | curDir, _ := os.Getwd() 45 | pos := strings.LastIndex(curDir, "src") 46 | if pos == -1 { 47 | // panic("can't find " + mainIniPath) 48 | fmt.Println("can't find " + mainIniPath) 49 | } else { 50 | ROOT = curDir[:pos] 51 | 52 | configPath = ROOT + mainIniPath 53 | } 54 | } 55 | configFile, err := goconfig.LoadConfigFile(configPath) 56 | if err != nil { 57 | panic(err) 58 | } 59 | TXDB = new(sync.Map) 60 | mysqlConfig, err := configFile.GetSection("mysql") 61 | if err != nil { 62 | fmt.Println("get mysql conf error:", err) 63 | return 64 | } 65 | 66 | fillDns(mysqlConfig) 67 | // 启动时就打开数据库连接 68 | if err = initEngine(); err != nil { 69 | panic(err) 70 | } 71 | // 测试数据库连接是否 OK 72 | if err = GORM_DB.DB().Ping(); err != nil { 73 | panic(err) 74 | } 75 | } 76 | 77 | var ( 78 | ConnectDBErr = errors.New("connect db error") 79 | UseDBErr = errors.New("use db error") 80 | ) 81 | 82 | func fillDns(mysqlConfig map[string]string) { 83 | DNS = fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=%s&parseTime=True&loc=Local", 84 | mysqlConfig["username"], 85 | mysqlConfig["password"], 86 | mysqlConfig["host"], 87 | mysqlConfig["port"], 88 | mysqlConfig["dbname"], 89 | mysqlConfig["charset"]) 90 | } 91 | 92 | func initEngine() error { 93 | var err error 94 | GORM_DB, err = gorm.Open("mysql", DNS) 95 | if err != nil { 96 | return err 97 | } 98 | GORM_DB.LogMode(true) 99 | return nil 100 | } 101 | 102 | func InitTXDB(db *gorm.DB) { 103 | TXDB.Store(runtime.GoroutineId(), db) 104 | } 105 | 106 | func ClearTXDB() { 107 | TXDB.Delete(runtime.GoroutineId()) 108 | } 109 | 110 | func DB() *gorm.DB { 111 | db, ok := TXDB.Load(runtime.GoroutineId()) 112 | if !ok { 113 | panic("TXDB not init") 114 | } 115 | return db.(*gorm.DB) 116 | } 117 | func fileExist(filename string) bool { 118 | _, err := os.Stat(filename) 119 | return err == nil || os.IsExist(err) 120 | } 121 | -------------------------------------------------------------------------------- /engine/activitiEngineAgenda.go: -------------------------------------------------------------------------------- 1 | package engine 2 | 3 | type ActivitiEngineAgenda interface { 4 | IsEmpty() bool 5 | 6 | PlanOperation(operation Operation) 7 | 8 | GetNextOperation() Operation 9 | 10 | PlanContinueProcessOperation(execution ExecutionEntity) 11 | 12 | //planContinueProcessSynchronousOperation(execution ExecutionEntity) 13 | // 14 | //planContinueProcessInCompensation(execution ExecutionEntity) 15 | // 16 | //planContinueMultiInstanceOperation(execution ExecutionEntity) 17 | 18 | PlanTakeOutgoingSequenceFlowsOperation(execution ExecutionEntity, evaluateConditions bool) 19 | 20 | PlanEndExecutionOperation(execution ExecutionEntity) 21 | 22 | PlanTriggerExecutionOperation(execution ExecutionEntity) 23 | // 24 | //planDestroyScopeOperation(execution ExecutionEntity) 25 | // 26 | //planExecuteInactiveBehaviorsOperation() 27 | 28 | } 29 | -------------------------------------------------------------------------------- /engine/activityBehavior.go: -------------------------------------------------------------------------------- 1 | package engine 2 | 3 | type ActivityBehavior interface { 4 | Execute(execution ExecutionEntity) error 5 | } 6 | -------------------------------------------------------------------------------- /engine/behavior/abstractCommandInterceptor.go: -------------------------------------------------------------------------------- 1 | package behavior 2 | 3 | type AbstractCommandInterceptor struct { 4 | Next CommandInterceptor 5 | } 6 | -------------------------------------------------------------------------------- /engine/behavior/abstractOperation.go: -------------------------------------------------------------------------------- 1 | package behavior 2 | 3 | import ( 4 | "github.com/lios/go-activiti/engine" 5 | ) 6 | 7 | type AbstractOperation struct { 8 | CommandContext CommandContext 9 | Execution engine.ExecutionEntity 10 | } 11 | -------------------------------------------------------------------------------- /engine/behavior/command.go: -------------------------------------------------------------------------------- 1 | package behavior 2 | 3 | type Command interface { 4 | Execute(interceptor CommandContext) (interface{}, error) 5 | } 6 | -------------------------------------------------------------------------------- /engine/behavior/commandContext.go: -------------------------------------------------------------------------------- 1 | package behavior 2 | 3 | import ( 4 | "github.com/lios/go-activiti/engine" 5 | . "github.com/lios/go-activiti/engine/persistence" 6 | ) 7 | 8 | type CommandContext struct { 9 | Command Command 10 | Agenda engine.ActivitiEngineAgenda 11 | ProcessEngineConfiguration ProcessEngineConfiguration 12 | } 13 | 14 | func GetProcessInstanceManager() ProcessInstanceManager { 15 | return ProcessInstanceManager{} 16 | } 17 | -------------------------------------------------------------------------------- /engine/behavior/commandContextFactory.go: -------------------------------------------------------------------------------- 1 | package behavior 2 | 3 | type CommandContextFactory struct { 4 | } 5 | 6 | func (factory CommandContextFactory) CreateCommandContext(command Command) CommandContext { 7 | context := CommandContext{Command: command, Agenda: &DefaultActivitiEngineAgenda{}} 8 | return context 9 | } 10 | -------------------------------------------------------------------------------- /engine/behavior/commandContextInterceptor.go: -------------------------------------------------------------------------------- 1 | package behavior 2 | 3 | type CommandContextInterceptor struct { 4 | Next CommandInterceptor 5 | ProcessEngineConfiguration *ProcessEngineConfiguration 6 | CommandContextFactory CommandContextFactory 7 | } 8 | 9 | func (commandContext CommandContextInterceptor) Execute(command Command) (interface{}, error) { 10 | context, err := GetCommandContext() 11 | if err != nil { 12 | context = commandContext.CommandContextFactory.CreateCommandContext(command) 13 | } 14 | SetCommandContext(context) 15 | return commandContext.Next.Execute(command) 16 | } 17 | 18 | func (commandContext *CommandContextInterceptor) SetNext(next CommandInterceptor) { 19 | commandContext.Next = next 20 | } 21 | -------------------------------------------------------------------------------- /engine/behavior/commandExecutor.go: -------------------------------------------------------------------------------- 1 | package behavior 2 | 3 | type CommandExecutor interface { 4 | Exe(conf Command) (interface{}, error) 5 | } 6 | -------------------------------------------------------------------------------- /engine/behavior/commandExecutorImpl.go: -------------------------------------------------------------------------------- 1 | package behavior 2 | 3 | type CommandExecutorImpl struct { 4 | First CommandInterceptor 5 | } 6 | 7 | func (comm CommandExecutorImpl) Exe(conf Command) (interface{}, error) { 8 | return comm.First.Execute(conf) 9 | } 10 | -------------------------------------------------------------------------------- /engine/behavior/commandInterceptor.go: -------------------------------------------------------------------------------- 1 | package behavior 2 | 3 | type CommandInterceptor interface { 4 | Execute(command Command) (interface{}, error) 5 | 6 | SetNext(next CommandInterceptor) 7 | } 8 | -------------------------------------------------------------------------------- /engine/behavior/commandInvoker.go: -------------------------------------------------------------------------------- 1 | package behavior 2 | 3 | type CommandInvoker struct { 4 | Next CommandInterceptor 5 | } 6 | 7 | func (commandInvoker CommandInvoker) Execute(command Command) (result interface{}, err error) { 8 | context, err := GetCommandContext() 9 | if err != nil { 10 | return nil, err 11 | } 12 | result, err = command.Execute(context) 13 | if err != nil { 14 | return nil, err 15 | } 16 | err = executeOperations(context) 17 | return result, err 18 | } 19 | 20 | func executeOperations(context CommandContext) (err error) { 21 | for !context.Agenda.IsEmpty() { 22 | err = context.Agenda.GetNextOperation().Run() 23 | if err != nil { 24 | return err 25 | } 26 | } 27 | return err 28 | } 29 | 30 | func (commandInvoker *CommandInvoker) SetNext(next CommandInterceptor) { 31 | commandInvoker.Next = next 32 | } 33 | -------------------------------------------------------------------------------- /engine/behavior/context.go: -------------------------------------------------------------------------------- 1 | package behavior 2 | 3 | import ( 4 | "container/list" 5 | "github.com/lios/go-activiti/engine" 6 | "github.com/lios/go-activiti/errs" 7 | ) 8 | 9 | var ( 10 | Stack list.List 11 | ) 12 | 13 | type Context struct { 14 | } 15 | 16 | func SetCommandContext(commandContext CommandContext) { 17 | Stack.PushFront(commandContext) 18 | } 19 | 20 | func GetCommandContext() (CommandContext, error) { 21 | if Stack.Len() <= 0 { 22 | return CommandContext{}, errs.ProcessError{} 23 | } 24 | return Stack.Front().Value.(CommandContext), nil 25 | } 26 | 27 | func GetAgenda() engine.ActivitiEngineAgenda { 28 | return Stack.Front().Value.(CommandContext).Agenda 29 | } 30 | -------------------------------------------------------------------------------- /engine/behavior/continueProcessOperation.go: -------------------------------------------------------------------------------- 1 | package behavior 2 | 3 | import ( 4 | "github.com/lios/go-activiti/engine" 5 | . "github.com/lios/go-activiti/engine/manager" 6 | ) 7 | 8 | type ContinueProcessOperation struct { 9 | AbstractOperation 10 | } 11 | 12 | func (cont *ContinueProcessOperation) Run() (err error) { 13 | element := cont.Execution.GetCurrentFlowElement() 14 | if element != nil { 15 | flow, ok := element.(engine.SequenceFlow) 16 | if !ok { 17 | err = cont.continueThroughFlowNode(element) 18 | } else { 19 | cont.continueThroughSequenceFlow(flow) 20 | } 21 | } 22 | return err 23 | } 24 | 25 | func (cont *ContinueProcessOperation) continueThroughSequenceFlow(sequenceFlow engine.SequenceFlow) { 26 | flowElement := sequenceFlow.TargetFlowElement 27 | cont.Execution.SetCurrentFlowElement(flowElement) 28 | GetAgenda().PlanContinueProcessOperation(cont.Execution) 29 | } 30 | 31 | func (cont *ContinueProcessOperation) continueThroughFlowNode(element engine.FlowElement) (err error) { 32 | historicActinstManager := GetHistoricActinstManager() 33 | historicActinstManager.RecordActivityStart(cont.Execution) 34 | behavior := element.GetBehavior() 35 | if behavior != nil { 36 | err = behavior.Execute(cont.Execution) 37 | } else { 38 | GetAgenda().PlanTakeOutgoingSequenceFlowsOperation(cont.Execution, true) 39 | } 40 | return err 41 | } 42 | -------------------------------------------------------------------------------- /engine/behavior/converter.go: -------------------------------------------------------------------------------- 1 | package behavior 2 | 3 | import ( 4 | "encoding/xml" 5 | . "github.com/lios/go-activiti/engine" 6 | "github.com/lios/go-activiti/model" 7 | ) 8 | 9 | func FindCurrentTask(bytearries model.Bytearry, taskDefineKey string) FlowElement { 10 | process := ConverterBpmn(bytearries) 11 | flowElement := process.FlowMap[taskDefineKey] 12 | return flowElement 13 | } 14 | func GetBpmn(bytes model.Bytearry) Process { 15 | return ConverterBpmn(bytes) 16 | } 17 | func ConverterBpmn(bytes model.Bytearry) Process { 18 | process, err := GetProcess(bytes.Id) 19 | if err == nil { 20 | return process 21 | } 22 | process = Converter([]byte(bytes.Bytes)) 23 | SetProcess(bytes.Id, process) 24 | return process 25 | } 26 | 27 | func Converter(bytes []byte) Process { 28 | define := new(Definitions) 29 | xml.Unmarshal(bytes, &define) 30 | processes := define.Process 31 | if processes != nil { 32 | for j, p := range processes { 33 | flowMap := make(map[string]FlowElement, 0) 34 | processes[j].FlowMap = flowMap 35 | processes[j].Name = p.Documentation 36 | start := p.StartEvent 37 | if start != nil { 38 | for i, sta := range start { 39 | //flowMap[sta.Id] = start[i] 40 | processes[j].FlowMap[sta.Id] = start[i] 41 | processes[j].InitialFlowElement = start[i] 42 | } 43 | } 44 | se := p.SequenceFlow 45 | if se != nil { 46 | for i, s := range se { 47 | processes[j].FlowMap[s.Id] = se[i] 48 | } 49 | } 50 | user := p.UserTask 51 | if user != nil { 52 | for i, u := range user { 53 | assignments := checkAssignments(u) 54 | var behavior ActivityBehavior 55 | if !assignments { 56 | behavior = UserAutoTaskActivityBehavior{UserTask: user[i], ProcessKey: p.Id} 57 | } else { 58 | behavior = UserTaskActivityBehavior{UserTask: user[i], ProcessKey: p.Id} 59 | } 60 | user[i].SetBehavior(behavior) 61 | processes[j].FlowMap[u.Id] = user[i] 62 | } 63 | } 64 | end := p.EndEvent 65 | if end != nil { 66 | for i, e := range end { 67 | processes[j].FlowMap[e.Id] = end[i] 68 | } 69 | } 70 | exclusiveGateways := p.ExclusiveGateway 71 | if exclusiveGateways != nil { 72 | for i, exclusiveGateway := range exclusiveGateways { 73 | behavior := ExclusiveGatewayActivityBehavior{} 74 | exclusiveGateways[i].SetBehavior(behavior) 75 | processes[j].FlowMap[exclusiveGateway.Id] = exclusiveGateways[i] 76 | } 77 | } 78 | inclusiveGateways := p.InclusiveGateway 79 | if inclusiveGateways != nil { 80 | for i, inclusiveGateway := range inclusiveGateways { 81 | behavior := InclusiveGatewayActivityBehavior{} 82 | inclusiveGateways[i].SetBehavior(behavior) 83 | processes[j].FlowMap[inclusiveGateway.Id] = inclusiveGateways[i] 84 | } 85 | } 86 | flows := make([]FlowElement, len(flowMap)) 87 | count := 0 88 | for _, v := range flowMap { 89 | flows[count] = v 90 | count++ 91 | } 92 | processes[j].Flow = flows 93 | } 94 | } 95 | ConvertXMLToElement(define) 96 | return define.Process[0] 97 | } 98 | 99 | //设置元素的出入口 100 | func ConvertXMLToElement(model *Definitions) { 101 | processes := model.Process 102 | if processes != nil { 103 | for j, p := range processes { 104 | flows := p.Flow 105 | for i := range flows { 106 | value, ok := flows[i].(SequenceFlow) 107 | if ok { 108 | SourceRef := value.SourceRef 109 | //上一个节点 110 | lastFlow := processes[j].FlowMap[SourceRef] 111 | if lastFlow != nil { 112 | var outgoing = lastFlow.GetOutgoing() 113 | if outgoing == nil { 114 | outgoing = make([]FlowElement, 0) 115 | } 116 | newOut := append(outgoing, flows[i]) 117 | //设置上一个节点出口 118 | lastFlow.SetOutgoing(newOut) 119 | //设置当前连线入口 120 | flows[i].SetSourceFlowElement(lastFlow) 121 | 122 | } 123 | //下一个节点 124 | TargetRef := value.TargetRef 125 | nextFlow := processes[j].FlowMap[TargetRef] 126 | if nextFlow != nil { 127 | incoming := nextFlow.GetIncoming() 128 | if incoming == nil { 129 | incoming = make([]FlowElement, 0) 130 | } 131 | newIn := append(incoming, flows[i]) 132 | m := make([]*FlowElement, 1) 133 | m[0] = &nextFlow 134 | //设置当前连线出口 135 | flows[i].SetTargetFlowElement(nextFlow) 136 | //设置下一个节点入口 137 | nextFlow.SetIncoming(newIn) 138 | } 139 | } 140 | } 141 | } 142 | } 143 | } 144 | 145 | func checkAssignments(task UserTask) bool { 146 | users := task.CandidateUsers 147 | groups := task.CandidateGroups 148 | if (users == nil || len(users) < 1) && (groups == nil || len(groups) < 1) { 149 | return false 150 | } 151 | return true 152 | } 153 | -------------------------------------------------------------------------------- /engine/behavior/defaultActivitiEngineAgenda.go: -------------------------------------------------------------------------------- 1 | package behavior 2 | 3 | import ( 4 | "container/list" 5 | "github.com/lios/go-activiti/engine" 6 | ) 7 | 8 | type DefaultActivitiEngineAgenda struct { 9 | Operations list.List 10 | } 11 | 12 | //判断是否为空 13 | func (agenda *DefaultActivitiEngineAgenda) IsEmpty() bool { 14 | return agenda.Operations.Len() == 0 15 | } 16 | 17 | //设置后续操作 18 | func (agenda *DefaultActivitiEngineAgenda) PlanOperation(operation engine.Operation) { 19 | agenda.Operations.PushFront(operation) 20 | } 21 | 22 | func (agenda *DefaultActivitiEngineAgenda) GetNextOperation() engine.Operation { 23 | value := agenda.Operations.Front() 24 | agenda.Operations.Remove(value) 25 | return value.Value.(engine.Operation) 26 | } 27 | 28 | //获取下一步操作 29 | func (agenda *DefaultActivitiEngineAgenda) getNextOperation() engine.Operation { 30 | return agenda.Operations.Front().Value.(engine.Operation) 31 | } 32 | 33 | //连线继续执行 34 | func (agenda *DefaultActivitiEngineAgenda) PlanContinueProcessOperation(execution engine.ExecutionEntity) { 35 | agenda.PlanOperation(&ContinueProcessOperation{AbstractOperation{Execution: execution}}) 36 | } 37 | 38 | //任务出口执行 39 | func (agenda *DefaultActivitiEngineAgenda) PlanTriggerExecutionOperation(execution engine.ExecutionEntity) { 40 | agenda.PlanOperation(&TriggerExecutionOperation{AbstractOperation{Execution: execution}}) 41 | } 42 | 43 | //连线出口设置 44 | func (agenda *DefaultActivitiEngineAgenda) PlanTakeOutgoingSequenceFlowsOperation(execution engine.ExecutionEntity, valuateConditions bool) { 45 | agenda.PlanOperation(&TakeOutgoingSequenceFlowsOperation{AbstractOperation: AbstractOperation{Execution: execution}, EvaluateConditions: valuateConditions}) 46 | } 47 | 48 | //任务结束 49 | func (agenda *DefaultActivitiEngineAgenda) PlanEndExecutionOperation(execution engine.ExecutionEntity) { 50 | agenda.PlanOperation(&EndExecutionOperation{AbstractOperation: AbstractOperation{Execution: execution}}) 51 | } 52 | -------------------------------------------------------------------------------- /engine/behavior/endExecutionOperation.go: -------------------------------------------------------------------------------- 1 | package behavior 2 | 3 | import ( 4 | "github.com/lios/go-activiti/engine" 5 | . "github.com/lios/go-activiti/engine/manager" 6 | ) 7 | 8 | type EndExecutionOperation struct { 9 | AbstractOperation 10 | } 11 | 12 | func (end *EndExecutionOperation) Run() (err error) { 13 | err = deleteDataForExecution(end.Execution) 14 | if err != nil { 15 | return err 16 | } 17 | manager := GetProcessInstanceManager() 18 | err = manager.DeleteProcessInstance(end.Execution.GetProcessInstanceId()) 19 | return err 20 | } 21 | 22 | func deleteDataForExecution(entity engine.ExecutionEntity) (err error) { 23 | taskManager := GetTaskManager() 24 | tasks, errSelect := taskManager.FindByProcessInstanceId(entity.GetProcessInstanceId()) 25 | if errSelect == nil { 26 | for _, task := range tasks { 27 | taskManager.DeleteTask(task) 28 | } 29 | } 30 | 31 | identityLinkManager := GetIdentityLinkManager() 32 | identityLinks, errSelect := identityLinkManager.SelectByProcessInstanceId(entity.GetProcessInstanceId()) 33 | if errSelect == nil { 34 | for _, identityLink := range identityLinks { 35 | err := identityLinkManager.Delete(identityLink.Id) 36 | if err != nil { 37 | return err 38 | } 39 | } 40 | } 41 | variableManager := GetVariableManager() 42 | variables, err := variableManager.SelectByProcessInstanceId(entity.GetProcessInstanceId()) 43 | if err == nil { 44 | for _, variable := range variables { 45 | err = variableManager.Delete(variable.Id) 46 | if err != nil { 47 | return err 48 | } 49 | } 50 | } 51 | return err 52 | } 53 | -------------------------------------------------------------------------------- /engine/behavior/exclusiveGatewayActivityBehavior.go: -------------------------------------------------------------------------------- 1 | package behavior 2 | 3 | import ( 4 | "github.com/lios/go-activiti/engine" 5 | "github.com/lios/go-activiti/engine/utils" 6 | ) 7 | 8 | type ExclusiveGatewayActivityBehavior struct { 9 | } 10 | 11 | //排他网关 12 | func (exclusive ExclusiveGatewayActivityBehavior) Execute(execution engine.ExecutionEntity) (err error) { 13 | err = exclusive.Leave(execution) 14 | return err 15 | } 16 | 17 | func (exclusive ExclusiveGatewayActivityBehavior) Leave(execution engine.ExecutionEntity) (err error) { 18 | element := execution.GetCurrentFlowElement() 19 | exclusiveGateway, ok := element.(engine.ExclusiveGateway) 20 | var outgoingSequenceFlow engine.FlowElement 21 | var defaultSequenceFlow engine.FlowElement 22 | if ok { 23 | defaultSequenceFlowId := exclusiveGateway.DefaultFlow 24 | sequenceFlowIterator := exclusiveGateway.GetOutgoing() 25 | if sequenceFlowIterator != nil && len(sequenceFlowIterator) > 0 { 26 | for _, sequenceFlow := range sequenceFlowIterator { 27 | flow := (sequenceFlow).(engine.SequenceFlow) 28 | conditionEvaluatesToTrue := utils.HasTrueCondition(flow, execution) 29 | if conditionEvaluatesToTrue && defaultSequenceFlowId != "" && defaultSequenceFlowId != flow.Id { 30 | outgoingSequenceFlow = sequenceFlow 31 | } 32 | if defaultSequenceFlowId != "" && defaultSequenceFlowId == flow.Id { 33 | defaultSequenceFlow = sequenceFlow 34 | } 35 | } 36 | 37 | } 38 | } 39 | if outgoingSequenceFlow != nil { 40 | execution.SetCurrentFlowElement(outgoingSequenceFlow) 41 | } else { 42 | if defaultSequenceFlow != nil { 43 | execution.SetCurrentFlowElement(defaultSequenceFlow) 44 | } 45 | } 46 | //执行出口逻辑,设置条件判断 47 | GetAgenda().PlanTakeOutgoingSequenceFlowsOperation(execution, true) 48 | return nil 49 | } 50 | -------------------------------------------------------------------------------- /engine/behavior/flowNodeActivityBehavior.go: -------------------------------------------------------------------------------- 1 | package behavior 2 | 3 | import ( 4 | "github.com/lios/go-activiti/engine" 5 | ) 6 | 7 | type FlowNodeActivityBehavior interface { 8 | Leave(execution engine.ExecutionEntity) error 9 | } 10 | -------------------------------------------------------------------------------- /engine/behavior/inclusiveGatewayActivityBehavior.go: -------------------------------------------------------------------------------- 1 | package behavior 2 | 3 | import ( 4 | "github.com/lios/go-activiti/engine" 5 | . "github.com/lios/go-activiti/engine/manager" 6 | "github.com/lios/go-activiti/engine/utils" 7 | ) 8 | 9 | type InclusiveGatewayActivityBehavior struct { 10 | } 11 | 12 | //包容网关 13 | func (exclusive InclusiveGatewayActivityBehavior) Execute(execution engine.ExecutionEntity) error { 14 | return exclusive.Leave(execution) 15 | } 16 | 17 | //执行逻辑:获取当前所有执行的节点,判断是否可达当前网关可以停止执行,等待完成 18 | func (exclusive InclusiveGatewayActivityBehavior) Leave(execution engine.ExecutionEntity) error { 19 | processInstanceId := execution.GetProcessInstanceId() 20 | taskManager := GetTaskManager() 21 | //查询当前执行节点 22 | tasks, errS := taskManager.FindByProcessInstanceId(processInstanceId) 23 | var oneExecutionCanReachGateway = false 24 | if errS != nil { 25 | bytearry, err := GetDefineManager().GetBytearry(execution.GetProcessDefineId()) 26 | if err != nil { 27 | return err 28 | } 29 | process := GetBpmn(bytearry) 30 | for _, task := range tasks { 31 | if task.TaskDefineKey != execution.GetCurrentActivityId() { 32 | //判断是否可以继续执行 33 | oneExecutionCanReachGateway = utils.IsReachable(process, task.TaskDefineKey, execution.GetCurrentActivityId()) 34 | } else { 35 | oneExecutionCanReachGateway = true 36 | } 37 | } 38 | } 39 | if !oneExecutionCanReachGateway { 40 | //执行出口逻辑,设置条件判断 41 | GetAgenda().PlanTakeOutgoingSequenceFlowsOperation(execution, true) 42 | } 43 | return nil 44 | } 45 | -------------------------------------------------------------------------------- /engine/behavior/processEngineConfiguration.go: -------------------------------------------------------------------------------- 1 | package behavior 2 | 3 | import ( 4 | . "github.com/lios/go-activiti/engine/variable" 5 | . "github.com/lios/go-activiti/event" 6 | ) 7 | 8 | var processEngineConfiguration ProcessEngineConfiguration 9 | 10 | type ProcessEngineConfiguration struct { 11 | CommandInvoker CommandInterceptor 12 | CommandInterceptors []CommandInterceptor 13 | EventListeners []ActivitiEventListener 14 | Service ServiceImpl 15 | CommandExecutor CommandExecutor 16 | CommandContextFactory CommandContextFactory 17 | VariableTypes VariableTypes 18 | EventDispatcher ActivitiEventDispatcher 19 | } 20 | 21 | func GetProcessEngineConfiguration() *ProcessEngineConfiguration { 22 | return &processEngineConfiguration 23 | } 24 | func init() { 25 | processEngineConfiguration = ProcessEngineConfiguration{} 26 | initCommandContextFactory() 27 | initCommandInvoker() 28 | initCommandInterceptors() 29 | initCommandExecutor() 30 | initService() 31 | initCommandContext(processEngineConfiguration) 32 | initVariableTypes() 33 | initEventDispatcher() 34 | } 35 | 36 | func initCommandContext(configuration ProcessEngineConfiguration) { 37 | //context := CommandContext{} 38 | } 39 | 40 | func (processEngineConfiguration ProcessEngineConfiguration) AddEventListeners(eventListeners []ActivitiEventListener) { 41 | var EventListeners []ActivitiEventListener 42 | dispatcher := GetEventDispatcher() 43 | if len(eventListeners) > 0 { 44 | for _, listener := range eventListeners { 45 | EventListeners = append(EventListeners, listener) 46 | dispatcher.AddEventListener(listener) 47 | } 48 | } 49 | SetEventDispatcher(dispatcher) 50 | processEngineConfiguration.EventListeners = EventListeners 51 | } 52 | 53 | func getDefaultCommandInterceptors() []CommandInterceptor { 54 | var interceptors []CommandInterceptor 55 | interceptors = append(interceptors, &CommandContextInterceptor{CommandContextFactory: processEngineConfiguration.CommandContextFactory}) 56 | //interceptors = append(interceptors, CommandInvoker{}) 57 | interceptors = append(interceptors, &TransactionContextInterceptor{}) 58 | return interceptors 59 | } 60 | func initCommandInvoker() { 61 | commandInvoker := CommandInvoker{} 62 | processEngineConfiguration.CommandInvoker = &commandInvoker 63 | } 64 | 65 | func initCommandInterceptors() { 66 | interceptors := getDefaultCommandInterceptors() 67 | interceptors = append(interceptors, processEngineConfiguration.CommandInvoker) 68 | processEngineConfiguration.CommandInterceptors = interceptors 69 | } 70 | 71 | func initCommandExecutor() { 72 | if processEngineConfiguration.CommandExecutor == nil { 73 | first := initInterceptorChain(processEngineConfiguration.CommandInterceptors) 74 | commandExecutor := CommandExecutorImpl{First: first} 75 | processEngineConfiguration.CommandExecutor = commandExecutor 76 | } 77 | } 78 | func initService() { 79 | serviceImpl := ServiceImpl{CommandExecutor: processEngineConfiguration.CommandExecutor} 80 | SetServiceImpl(serviceImpl) 81 | processEngineConfiguration.Service = serviceImpl 82 | } 83 | 84 | func initInterceptorChain(interceptors []CommandInterceptor) CommandInterceptor { 85 | if len(interceptors) > 0 { 86 | for i := 0; i < len(interceptors)-1; i++ { 87 | interceptor := interceptors[i] 88 | interceptor.SetNext(interceptors[i+1]) 89 | } 90 | } 91 | return interceptors[0] 92 | } 93 | 94 | func initCommandContextFactory() { 95 | factory := CommandContextFactory{} 96 | processEngineConfiguration.CommandContextFactory = factory 97 | } 98 | 99 | func initVariableTypes() { 100 | defaultVariableTypes := DefaultVariableTypes{} 101 | defaultVariableTypes.AddType(BooleanType{}) 102 | defaultVariableTypes.AddType(IntType{}) 103 | defaultVariableTypes.AddType(StringType{}) 104 | defaultVariableTypes.AddType(MapType{}) 105 | processEngineConfiguration.VariableTypes = defaultVariableTypes 106 | } 107 | 108 | func initEventDispatcher() { 109 | eventDispatcher := processEngineConfiguration.EventDispatcher 110 | if processEngineConfiguration.EventDispatcher == nil { 111 | eventDispatcher = ActivitiEventDispatcherImpl{EventSupport: &ActivitiEventSupport{}, Enabled: true} 112 | } 113 | if processEngineConfiguration.EventListeners != nil && len(processEngineConfiguration.EventListeners) > 0 { 114 | for _, listenerToAdd := range processEngineConfiguration.EventListeners { 115 | eventDispatcher.AddEventListener(listenerToAdd) 116 | } 117 | } 118 | processEngineConfiguration.EventDispatcher = eventDispatcher 119 | SetEventDispatcher(eventDispatcher) 120 | } 121 | -------------------------------------------------------------------------------- /engine/behavior/processUtils.go: -------------------------------------------------------------------------------- 1 | package behavior 2 | 3 | import ( 4 | . "github.com/lios/go-activiti/engine" 5 | . "github.com/lios/go-activiti/engine/manager" 6 | "github.com/lios/go-activiti/errs" 7 | "sync" 8 | ) 9 | 10 | var flowMap *sync.Map 11 | 12 | type ProcessUtils struct { 13 | ProcessId int64 14 | } 15 | 16 | func init() { 17 | flowMap = new(sync.Map) 18 | } 19 | func (processUtil *ProcessUtils) GetCurrentTask(taskId int) (FlowElement, error) { 20 | manager := GetTaskManager() 21 | task, err := manager.FindById(taskId) 22 | if err != nil { 23 | return nil, err 24 | } 25 | processUtil.ProcessId = task.ProcessInstanceId 26 | processUtil.LoadProcess() 27 | defineManager := GetDefineManager() 28 | bytearry, err := defineManager.FindProcessByTask(task.ProcessInstanceId) 29 | if err != nil { 30 | return nil, err 31 | } 32 | currentTask := FindCurrentTask(bytearry, task.TaskDefineKey) 33 | return currentTask, nil 34 | } 35 | 36 | func (processUtil *ProcessUtils) GetFlowElement(flowElementId string) (FlowElement, error) { 37 | flowM, ok := flowMap.Load(processUtil.ProcessId) 38 | if !ok { 39 | 40 | } 41 | flowElements, isOk := flowM.(map[string]FlowElement) 42 | if isOk { 43 | flowElement := flowElements[flowElementId] 44 | return flowElement, nil 45 | } 46 | return nil, errs.ProcessError{Code: "1003", Msg: "not find"} 47 | } 48 | 49 | func (processUtil *ProcessUtils) LoadProcess() error { 50 | defineManager := GetDefineManager() 51 | bytearry, err := defineManager.FindProcessByTask(processUtil.ProcessId) 52 | if err != nil { 53 | return err 54 | } 55 | process := ConverterBpmn(bytearry) 56 | flowMap.Store(processUtil.ProcessId, process.FlowMap) 57 | return nil 58 | } 59 | -------------------------------------------------------------------------------- /engine/behavior/serviceImpl.go: -------------------------------------------------------------------------------- 1 | package behavior 2 | 3 | var serviceImpl ServiceImpl 4 | 5 | type ServiceImpl struct { 6 | CommandExecutor CommandExecutor 7 | } 8 | 9 | func (serviceImpl *ServiceImpl) SetCommandExecutor(commandExecutor CommandExecutor) { 10 | serviceImpl.CommandExecutor = commandExecutor 11 | } 12 | 13 | func GetServiceImpl() ServiceImpl { 14 | return serviceImpl 15 | } 16 | 17 | func SetServiceImpl(service ServiceImpl) { 18 | serviceImpl = service 19 | } 20 | -------------------------------------------------------------------------------- /engine/behavior/takeOutgoingSequenceFlowsOperation.go: -------------------------------------------------------------------------------- 1 | package behavior 2 | 3 | import ( 4 | . "github.com/lios/go-activiti/engine" 5 | . "github.com/lios/go-activiti/engine/manager" 6 | "github.com/lios/go-activiti/engine/utils" 7 | ) 8 | 9 | type TakeOutgoingSequenceFlowsOperation struct { 10 | AbstractOperation 11 | EvaluateConditions bool 12 | } 13 | 14 | func (task TakeOutgoingSequenceFlowsOperation) Run() (err error) { 15 | currentFlowElement := task.getCurrentFlowElement() 16 | _, ok := currentFlowElement.(SequenceFlow) 17 | if ok { 18 | task.handleSequenceFlow() 19 | } else { 20 | err = task.handleFlowNode() 21 | } 22 | return err 23 | } 24 | 25 | //处理节点 26 | func (task TakeOutgoingSequenceFlowsOperation) handleFlowNode() (err error) { 27 | execution := task.Execution 28 | currentFlowElement := task.Execution.GetCurrentFlowElement() 29 | err = task.handleActivityEnd(currentFlowElement) 30 | if err != nil { 31 | return err 32 | } 33 | gateway, ok := currentFlowElement.(Gateway) 34 | var defaultSequenceFlowId = "" 35 | if ok { 36 | defaultSequenceFlowId = gateway.DefaultFlow 37 | } 38 | flowElements := currentFlowElement.GetOutgoing() 39 | var outgoingSequenceFlows = make([]FlowElement, 0) 40 | if len(flowElements) > 0 { 41 | for _, flowElement := range flowElements { 42 | sequenceFlow := (flowElement).(SequenceFlow) 43 | if !task.EvaluateConditions || utils.HasTrueCondition(sequenceFlow, execution) { 44 | outgoingSequenceFlows = append(outgoingSequenceFlows, flowElement) 45 | } 46 | } 47 | if outgoingSequenceFlows != nil && len(outgoingSequenceFlows) == 0 { 48 | if defaultSequenceFlowId != "" { 49 | for _, flowElement := range flowElements { 50 | if defaultSequenceFlowId == (flowElement).GetId() { 51 | outgoingSequenceFlows = append(outgoingSequenceFlows, flowElement) 52 | } 53 | } 54 | } 55 | } 56 | } 57 | 58 | if len(outgoingSequenceFlows) == 0 { 59 | if flowElements == nil || len(flowElements) == 0 { 60 | GetAgenda().PlanEndExecutionOperation(execution) 61 | } else { 62 | panic("No outgoing sequence flow of element") 63 | } 64 | } else { 65 | for _, outgoingExecution := range outgoingSequenceFlows { 66 | execution.SetCurrentFlowElement(outgoingExecution) 67 | GetAgenda().PlanContinueProcessOperation(execution) 68 | } 69 | } 70 | return err 71 | } 72 | 73 | //处理连线 74 | func (task TakeOutgoingSequenceFlowsOperation) handleSequenceFlow() { 75 | GetAgenda().PlanContinueProcessOperation(task.Execution) 76 | } 77 | 78 | //获取当前活动节点 79 | func (task TakeOutgoingSequenceFlowsOperation) getCurrentFlowElement() FlowElement { 80 | execution := task.Execution 81 | currentFlowElement := execution.GetCurrentFlowElement() 82 | if currentFlowElement != nil { 83 | return currentFlowElement 84 | } 85 | return nil 86 | } 87 | 88 | func (task TakeOutgoingSequenceFlowsOperation) handleActivityEnd(element FlowElement) (err error) { 89 | historicActinstManager := GetHistoricActinstManager() 90 | err = historicActinstManager.RecordTaskCreated(element, task.Execution) 91 | return err 92 | } 93 | -------------------------------------------------------------------------------- /engine/behavior/tiggerableActivityBehavior.go: -------------------------------------------------------------------------------- 1 | package behavior 2 | 3 | import ( 4 | "github.com/lios/go-activiti/engine" 5 | ) 6 | 7 | type TriggerableActivityBehavior interface { 8 | Trigger(entity engine.ExecutionEntity) 9 | } 10 | -------------------------------------------------------------------------------- /engine/behavior/transactionContextInterceptor.go: -------------------------------------------------------------------------------- 1 | package behavior 2 | 3 | import ( 4 | "github.com/jinzhu/gorm" 5 | "github.com/lios/go-activiti/db" 6 | ) 7 | 8 | type TransactionContextInterceptor struct { 9 | Next CommandInterceptor 10 | } 11 | 12 | func (transactionContextInterceptor TransactionContextInterceptor) Execute(command Command) (value interface{}, err error) { 13 | defer db.ClearTXDB() 14 | db.GORM_DB.Transaction(func(tx *gorm.DB) error { 15 | db.InitTXDB(tx) 16 | value, err = transactionContextInterceptor.Next.Execute(command) 17 | return err 18 | }) 19 | return value, err 20 | } 21 | 22 | func (transactionContextInterceptor *TransactionContextInterceptor) SetNext(next CommandInterceptor) { 23 | transactionContextInterceptor.Next = next 24 | } 25 | -------------------------------------------------------------------------------- /engine/behavior/triggerExecutionOperation.go: -------------------------------------------------------------------------------- 1 | package behavior 2 | 3 | import ( 4 | "github.com/lios/go-activiti/engine" 5 | ) 6 | 7 | type TriggerExecutionOperation struct { 8 | AbstractOperation 9 | } 10 | 11 | func (trigger TriggerExecutionOperation) Run() (err error) { 12 | element := trigger.getCurrentFlowElement(trigger.Execution) 13 | behavior := element.GetBehavior() 14 | operation := behavior.(TriggerableActivityBehavior) 15 | operation.Trigger(trigger.Execution) 16 | return err 17 | } 18 | 19 | func (trigger TriggerExecutionOperation) getCurrentFlowElement(execut engine.ExecutionEntity) engine.FlowElement { 20 | currentFlowElement := execut.GetCurrentFlowElement() 21 | if currentFlowElement != nil { 22 | return currentFlowElement 23 | } 24 | return nil 25 | } 26 | -------------------------------------------------------------------------------- /engine/behavior/userAutoTaskActivityBehavior.go: -------------------------------------------------------------------------------- 1 | package behavior 2 | 3 | import ( 4 | "github.com/lios/go-activiti/engine" 5 | . "github.com/lios/go-activiti/engine/common" 6 | . "github.com/lios/go-activiti/engine/handler" 7 | . "github.com/lios/go-activiti/engine/persistence" 8 | . "github.com/lios/go-activiti/model" 9 | "reflect" 10 | "time" 11 | ) 12 | 13 | type UserAutoTaskActivityBehavior struct { 14 | UserTask engine.UserTask 15 | ProcessKey string 16 | } 17 | 18 | //自动通过用户节点处理 19 | func (user UserAutoTaskActivityBehavior) Execute(execution engine.ExecutionEntity) (err error) { 20 | task := Task{} 21 | task.ProcessInstanceId = execution.GetProcessInstanceId() 22 | task.Assignee = user.UserTask.Assignee 23 | task.StartTime = time.Now() 24 | task.TaskDefineKey = user.UserTask.Id 25 | task.TaskDefineName = user.UserTask.Name 26 | manager := TaskManager{Task: &task} 27 | err = manager.Insert(execution) 28 | 29 | activitiConstructor, err := GetConstructorByName(user.ProcessKey) 30 | if err != nil { 31 | manager.DeleteTask(task) 32 | GetAgenda().PlanTriggerExecutionOperation(execution) 33 | return nil 34 | } 35 | constructor := activitiConstructor(execution) 36 | reflectConstructor := reflect.ValueOf(constructor) 37 | taskParams := []reflect.Value{reflectConstructor} 38 | 39 | method, b := reflectConstructor.Type().MethodByName(user.UserTask.Name) 40 | if !b { 41 | manager.DeleteTask(task) 42 | GetAgenda().PlanTriggerExecutionOperation(execution) 43 | return err 44 | } 45 | 46 | callResponse := method.Func.Call(taskParams) 47 | 48 | code := callResponse[0].Interface() 49 | errRes := callResponse[1].Interface() 50 | code = code.(string) 51 | if code != ACTIVITI_HANDLER_CODE { 52 | err := errRes.(error) 53 | return err 54 | } 55 | manager.DeleteTask(task) 56 | GetAgenda().PlanTriggerExecutionOperation(execution) 57 | return err 58 | } 59 | 60 | //普通用户节点处理 61 | func (user UserAutoTaskActivityBehavior) Trigger(execution engine.ExecutionEntity) { 62 | user.Leave(execution) 63 | } 64 | 65 | func (user UserAutoTaskActivityBehavior) Leave(execution engine.ExecutionEntity) { 66 | element := execution.GetCurrentFlowElement() 67 | execution.SetCurrentFlowElement(element) 68 | GetAgenda().PlanTakeOutgoingSequenceFlowsOperation(execution, true) 69 | } 70 | -------------------------------------------------------------------------------- /engine/behavior/userTaskActivityBehavior.go: -------------------------------------------------------------------------------- 1 | package behavior 2 | 3 | import ( 4 | "github.com/lios/go-activiti/engine" 5 | . "github.com/lios/go-activiti/engine/common" 6 | . "github.com/lios/go-activiti/engine/handler" 7 | . "github.com/lios/go-activiti/engine/manager" 8 | . "github.com/lios/go-activiti/engine/persistence" 9 | "github.com/lios/go-activiti/event" 10 | . "github.com/lios/go-activiti/event/impl" 11 | . "github.com/lios/go-activiti/model" 12 | "time" 13 | ) 14 | 15 | type UserTaskActivityBehavior struct { 16 | UserTask engine.UserTask 17 | ProcessKey string 18 | } 19 | 20 | //普通用户节点处理 21 | func (user UserTaskActivityBehavior) Execute(execution engine.ExecutionEntity) (err error) { 22 | task := Task{} 23 | task.ProcessInstanceId = execution.GetProcessInstanceId() 24 | task.Assignee = user.UserTask.Assignee 25 | task.StartTime = time.Now() 26 | task.TaskDefineKey = user.UserTask.Id 27 | task.TaskDefineName = user.UserTask.Name 28 | manager := TaskManager{Task: &task} 29 | err = manager.Insert(execution) 30 | if err != nil { 31 | return err 32 | } 33 | err = handleAssignments(user.UserTask, task.Id, task.ProcessInstanceId) 34 | 35 | // All properties set, now firing 'create' events 36 | if GetProcessEngineConfiguration().EventDispatcher.IsEnabled() { 37 | activitiEntityEvent, err := CreateEntityEvent(event.TASK_CREATED, task) 38 | if err != nil { 39 | return err 40 | } 41 | GetProcessEngineConfiguration().EventDispatcher.DispatchEvent(activitiEntityEvent) 42 | } 43 | extensionElements := user.UserTask.ExtensionElements 44 | if extensionElements.TaskListener != nil && len(extensionElements.TaskListener) > 0 { 45 | taskListeners := extensionElements.TaskListener 46 | for _, listener := range taskListeners { 47 | if listener.EventType == TASK_TYPE_CREATE { 48 | err = PerformTaskListener(execution, user.UserTask, user.ProcessKey) 49 | if err != nil { 50 | return err 51 | } 52 | } 53 | } 54 | } 55 | return err 56 | } 57 | 58 | //保存候选用户 59 | func handleAssignments(user engine.UserTask, taskId, processInstanceId int64) (err error) { 60 | users := user.CandidateUsers 61 | if len(users) >= 0 { 62 | for _, user := range users { 63 | link := IdentityLink{} 64 | link.TaskId = taskId 65 | link.ProcessInstanceId = processInstanceId 66 | link.UserId = user 67 | identityLinkManager := GetIdentityLinkManager() 68 | identityLinkManager.IdentityLink = link 69 | err = identityLinkManager.CreateIdentityLink() 70 | if err != nil { 71 | return err 72 | } 73 | } 74 | } 75 | return err 76 | } 77 | 78 | //普通用户节点处理 79 | func (user UserTaskActivityBehavior) Trigger(execution engine.ExecutionEntity) { 80 | user.Leave(execution) 81 | } 82 | 83 | func (user UserTaskActivityBehavior) Leave(execution engine.ExecutionEntity) { 84 | element := execution.GetCurrentFlowElement() 85 | execution.SetCurrentFlowElement(element) 86 | GetAgenda().PlanTakeOutgoingSequenceFlowsOperation(execution, true) 87 | } 88 | -------------------------------------------------------------------------------- /engine/cmd/backTaskCmd.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | . "github.com/lios/go-activiti/engine" 5 | "github.com/lios/go-activiti/engine/behavior" 6 | . "github.com/lios/go-activiti/engine/manager" 7 | "github.com/pborman/uuid" 8 | ) 9 | 10 | type BackTaskCmd struct { 11 | TaskId int 12 | TargetFlowId string 13 | Comment string 14 | } 15 | 16 | func (backTaskCmd BackTaskCmd) Execute(interceptor behavior.CommandContext) (interface{}, error) { 17 | manager := GetTaskManager() 18 | task, err := manager.FindById(backTaskCmd.TaskId) 19 | if err != nil { 20 | return task, err 21 | } 22 | processUtils := behavior.ProcessUtils{} 23 | currentTask, err := processUtils.GetCurrentTask(backTaskCmd.TaskId) 24 | if err != nil { 25 | return false, nil 26 | } 27 | sourceElement := currentTask.GetOutgoing() 28 | targetFlowElement, err := processUtils.GetFlowElement(backTaskCmd.TargetFlowId) 29 | sequenceFlows := createTask(targetFlowElement, currentTask.GetId(), backTaskCmd.TargetFlowId) 30 | currentTask.SetOutgoing(sequenceFlows) 31 | _, err = behavior.GetServiceImpl().CommandExecutor.Exe(CompleteCmd{backTaskCmd.TaskId, nil, true}) 32 | if err != nil { 33 | return false, nil 34 | } 35 | currentTask.SetOutgoing(sourceElement) 36 | return true, err 37 | } 38 | 39 | func createTask(element FlowElement, sourceRef, targetRef string) []FlowElement { 40 | sequenceFlow := SequenceFlow{} 41 | flow := Flow{} 42 | sequenceFlow.Flow = &flow 43 | sequenceFlow.Id = uuid.New() 44 | sequenceFlow.SourceRef = sourceRef 45 | sequenceFlow.TargetRef = targetRef 46 | sequenceFlow.SetTargetFlowElement(element) 47 | flowElement := make([]FlowElement, 0) 48 | flowElement = append(flowElement, sequenceFlow) 49 | return flowElement 50 | } 51 | -------------------------------------------------------------------------------- /engine/cmd/completeCmd.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "github.com/lios/go-activiti/engine" 5 | "github.com/lios/go-activiti/engine/behavior" 6 | "github.com/lios/go-activiti/engine/common" 7 | . "github.com/lios/go-activiti/engine/entityImpl" 8 | "github.com/lios/go-activiti/engine/handler" 9 | . "github.com/lios/go-activiti/engine/manager" 10 | "github.com/lios/go-activiti/event" 11 | "github.com/lios/go-activiti/event/impl" 12 | "github.com/lios/go-activiti/model" 13 | ) 14 | 15 | type CompleteCmd struct { 16 | TaskId int 17 | Variables map[string]interface{} 18 | LocalScope bool 19 | } 20 | 21 | func (taskCmd CompleteCmd) Execute(interceptor behavior.CommandContext) (interface{}, error) { 22 | manager := GetTaskManager() 23 | task, err := manager.FindById(taskCmd.TaskId) 24 | if err != nil { 25 | return task, err 26 | } 27 | taskCmd.executeTaskComplete(task, interceptor) 28 | return task, err 29 | } 30 | 31 | func (taskCmd CompleteCmd) executeTaskComplete(task model.Task, interceptor behavior.CommandContext) (err error) { 32 | 33 | // All properties set, now firing 'create' events 34 | if event.GetEventDispatcher().IsEnabled() { 35 | activitiEntityEvent, err := impl.CreateEntityEvent(event.TASK_COMPLETED, task) 36 | if err != nil { 37 | return err 38 | } 39 | event.GetEventDispatcher().DispatchEvent(activitiEntityEvent) 40 | } 41 | err = deleteTask(task) 42 | if err != nil { 43 | return err 44 | } 45 | defineManager := GetDefineManager() 46 | bytearry, err := defineManager.FindProcessByTask(task.ProcessInstanceId) 47 | if err != nil { 48 | return err 49 | } 50 | currentTask := behavior.FindCurrentTask(bytearry, task.TaskDefineKey) 51 | taskExecution := TaskEntityImpl{} 52 | execution := ExecutionEntityImpl{} 53 | execution.SetCurrentFlowElement(currentTask) 54 | execution.SetCurrentActivityId(task.TaskDefineKey) 55 | processInstanceManager := behavior.GetProcessInstanceManager() 56 | instance := processInstanceManager.GetProcessInstance(task.ProcessInstanceId) 57 | execution.SetProcessDefineId(instance.ProcessDefineId) 58 | execution.SetProcessInstanceId(task.ProcessInstanceId) 59 | taskExecution.SetTaskId(task.Id) 60 | taskExecution.ExecutionEntityImpl = execution 61 | if taskCmd.LocalScope { 62 | err = SetVariable(&taskExecution, taskCmd.Variables) 63 | } else { 64 | err = SetVariable(&execution, taskCmd.Variables) 65 | } 66 | if err != nil { 67 | return err 68 | } 69 | userTask, ok := currentTask.(engine.UserTask) 70 | if ok { 71 | taskListeners := userTask.ExtensionElements.TaskListener 72 | for _, listener := range taskListeners { 73 | if listener.EventType == common.TASK_TYPE_COMPLETED { 74 | err = handler.PerformTaskListener(&execution, userTask, instance.Key) 75 | if err != nil { 76 | return err 77 | } 78 | } 79 | } 80 | } 81 | interceptor.Agenda.PlanTriggerExecutionOperation(&taskExecution) 82 | return nil 83 | } 84 | 85 | func deleteTask(task model.Task) (err error) { 86 | manager := GetTaskManager() 87 | return manager.DeleteTask(task) 88 | } 89 | -------------------------------------------------------------------------------- /engine/cmd/deployProcessCmd.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "github.com/lios/go-activiti/engine/behavior" 5 | "github.com/lios/go-activiti/engine/persistence" 6 | ) 7 | 8 | type DeploymentCmd struct { 9 | Name string 10 | Key string 11 | TenantId string 12 | Bytes []byte 13 | } 14 | 15 | func (deploy DeploymentCmd) Execute(interceptor behavior.CommandContext) (interface{}, error) { 16 | deploymentManager := persistence.DeploymentManager{} 17 | err := deploymentManager.Deployment(deploy.Name, deploy.Key, deploy.Bytes) 18 | return nil, err 19 | } 20 | -------------------------------------------------------------------------------- /engine/cmd/getTaskCmd.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "github.com/lios/go-activiti/engine/behavior" 5 | . "github.com/lios/go-activiti/engine/manager" 6 | ) 7 | 8 | type GetTaskCmd struct { 9 | UserId string 10 | GroupId string 11 | } 12 | 13 | func (getTaskCmd GetTaskCmd) Execute(interceptor behavior.CommandContext) (interface{}, error) { 14 | manager := GetTaskManager() 15 | taskResult, err := manager.QueryUndoTask(getTaskCmd.UserId, getTaskCmd.GroupId) 16 | if err != nil { 17 | return taskResult, err 18 | } 19 | return taskResult, err 20 | } 21 | -------------------------------------------------------------------------------- /engine/cmd/startProcessInstanceByKeyCmd.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "github.com/lios/go-activiti/engine" 5 | "github.com/lios/go-activiti/engine/behavior" 6 | . "github.com/lios/go-activiti/engine/entityImpl" 7 | . "github.com/lios/go-activiti/engine/manager" 8 | . "github.com/lios/go-activiti/engine/persistence" 9 | . "github.com/lios/go-activiti/model" 10 | "time" 11 | ) 12 | 13 | type StartProcessInstanceByKeyCmd struct { 14 | ProcessDefinitionKey string 15 | Variables map[string]interface{} 16 | BusinessKey string 17 | TenantId string 18 | } 19 | 20 | func (start StartProcessInstanceByKeyCmd) Execute(interceptor behavior.CommandContext) (interface{}, error) { 21 | defineManager := GetDefineManager() 22 | bytearries, err := defineManager.FindDeployedProcessDefinitionByKey(start.ProcessDefinitionKey) 23 | if err != nil { 24 | return nil, err 25 | } 26 | //解析xml数据 27 | process := behavior.GetBpmn(*bytearries[0]) 28 | instance := ProcessInstance{} 29 | instance.BusinessKey = start.BusinessKey 30 | instance.TenantId = start.TenantId 31 | instance.StartTime = time.Now() 32 | instance.Key = process.Id 33 | instance.Name = process.Name 34 | instance.ProcessDefineId = bytearries[0].Id 35 | instance.DeploymentId = bytearries[0].DeploymentId 36 | //生成流程实例 37 | manager := ProcessInstanceManager{Instance: &instance} 38 | manager.CreateProcessInstance() 39 | //获取开始节点 40 | flowElement := process.InitialFlowElement 41 | element := flowElement.(engine.StartEvent) 42 | execution := ExecutionEntityImpl{ProcessInstanceId: instance.Id} 43 | execution.SetCurrentFlowElement(element) 44 | execution.SetProcessDefineId(bytearries[0].Id) 45 | execution.SetCurrentActivityId(element.GetId()) 46 | //保存流程变量 47 | err = SetVariable(&execution, start.Variables) 48 | if err != nil { 49 | return nil, err 50 | } 51 | context, err := behavior.GetCommandContext() 52 | if err == nil { 53 | context.Agenda.PlanContinueProcessOperation(&execution) 54 | } 55 | return process, nil 56 | } 57 | -------------------------------------------------------------------------------- /engine/common/activitiCommon.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | const ( 4 | ACTIVITI_HANDLER_CODE = "OK" 5 | TASK_TYPE_CREATE = "create" 6 | TASK_TYPE_COMPLETED = "complete" 7 | TASK_TYPE_ASSIGNED = "assignment" 8 | ) 9 | -------------------------------------------------------------------------------- /engine/entityImpl/executionEntityImpl.go: -------------------------------------------------------------------------------- 1 | package entityImpl 2 | 3 | import ( 4 | "github.com/lios/go-activiti/engine" 5 | . "github.com/lios/go-activiti/engine/behavior" 6 | . "github.com/lios/go-activiti/engine/manager" 7 | . "github.com/lios/go-activiti/engine/persistence" 8 | . "github.com/lios/go-activiti/engine/variable" 9 | "github.com/lios/go-activiti/errs" 10 | "reflect" 11 | ) 12 | 13 | type ExecutionEntityImpl struct { 14 | BusinessKey string 15 | CurrentFlowElement engine.FlowElement 16 | DeploymentId int 17 | ProcessInstanceId int64 18 | ProcessDefineId int64 19 | CurrentActivityId string 20 | } 21 | 22 | func (execution *ExecutionEntityImpl) SetBusinessKey(businessKey string) { 23 | execution.BusinessKey = businessKey 24 | } 25 | 26 | func (execution ExecutionEntityImpl) GetCurrentFlowElement() engine.FlowElement { 27 | return execution.CurrentFlowElement 28 | } 29 | 30 | func (execution *ExecutionEntityImpl) SetCurrentFlowElement(flow engine.FlowElement) { 31 | execution.CurrentFlowElement = flow 32 | execution.CurrentActivityId = flow.GetId() 33 | } 34 | 35 | func (execution ExecutionEntityImpl) GetDeploymentId() int { 36 | return execution.DeploymentId 37 | } 38 | 39 | func (execution *ExecutionEntityImpl) SetDeploymentId(deploymentId int) { 40 | execution.DeploymentId = deploymentId 41 | } 42 | 43 | func (execution ExecutionEntityImpl) GetProcessInstanceId() int64 { 44 | return execution.ProcessInstanceId 45 | } 46 | 47 | func (execution *ExecutionEntityImpl) SetProcessInstanceId(processInstanceId int64) { 48 | execution.ProcessInstanceId = processInstanceId 49 | } 50 | 51 | func (execution *ExecutionEntityImpl) GetProcessDefineId() int64 { 52 | return execution.ProcessDefineId 53 | } 54 | 55 | func (execution *ExecutionEntityImpl) SetProcessDefineId(processDefineId int64) { 56 | execution.ProcessDefineId = processDefineId 57 | } 58 | 59 | func (execution *ExecutionEntityImpl) GetCurrentActivityId() string { 60 | return execution.CurrentActivityId 61 | } 62 | 63 | func (execution *ExecutionEntityImpl) SetCurrentActivityId(currentActivityId string) { 64 | execution.CurrentActivityId = currentActivityId 65 | } 66 | 67 | func (execution *ExecutionEntityImpl) GetTaskId() int64 { 68 | return -1 69 | } 70 | 71 | func (execution *ExecutionEntityImpl) SetTaskId(taskId int64) { 72 | 73 | } 74 | func (execution *ExecutionEntityImpl) GetProcessVariable() map[string]interface{} { 75 | return execution.GetVariable() 76 | } 77 | 78 | func (execution *ExecutionEntityImpl) GetVariable() map[string]interface{} { 79 | variableManager := GetVariableManager() 80 | variables, err := variableManager.SelectByProcessInstanceId(execution.GetProcessInstanceId()) 81 | if err == nil { 82 | return execution.HandleVariable(variables) 83 | } 84 | return nil 85 | } 86 | 87 | func (execution *ExecutionEntityImpl) HandleVariable(variables []Variable) map[string]interface{} { 88 | engineConfiguration := GetProcessEngineConfiguration() 89 | variableTypes := engineConfiguration.VariableTypes 90 | var variableMap = make(map[string]interface{}, 0) 91 | for _, variable := range variables { 92 | variableType := variableTypes.GetVariableType(variable.Type) 93 | value := variableType.GetValue(&variable) 94 | variableMap[variable.Name] = value 95 | } 96 | return variableMap 97 | } 98 | 99 | //保存流程变量 100 | func SetVariable(execution engine.ExecutionEntity, variables map[string]interface{}) error { 101 | engineConfiguration := GetProcessEngineConfiguration() 102 | variableTypes := engineConfiguration.VariableTypes 103 | variableManager := GetVariableManager() 104 | if variables != nil && len(variables) > 0 { 105 | for k, v := range variables { 106 | kind := reflect.TypeOf(v).Kind() 107 | variableType := variableTypes.GetVariableType(kind.String()) 108 | if variableType == nil { 109 | return errs.ProcessError{Code: "1001", Msg: "no type"} 110 | } 111 | variable := variableManager.Create(k, variableType, v) 112 | //存在更新 113 | specificVariable, e := execution.GetSpecificVariable(k) 114 | if e != nil { 115 | variable.Version = specificVariable.Version + 1 116 | } 117 | execution.SetScope(variable) 118 | variableManager.Variable = variable 119 | err := variableManager.Insert() 120 | if err != nil { 121 | return err 122 | } 123 | } 124 | } 125 | return nil 126 | } 127 | 128 | func (execution *ExecutionEntityImpl) GetSpecificVariable(variableName string) (Variable, error) { 129 | variableManager := VariableManager{} 130 | return variableManager.SelectProcessInstanceId(variableName, execution.ProcessInstanceId) 131 | } 132 | 133 | func (execution *ExecutionEntityImpl) SetScope(variable *Variable) { 134 | variable.ProcessInstanceId = execution.ProcessInstanceId 135 | } 136 | -------------------------------------------------------------------------------- /engine/entityImpl/taskEntityImpl.go: -------------------------------------------------------------------------------- 1 | package entityImpl 2 | 3 | import ( 4 | . "github.com/lios/go-activiti/engine/manager" 5 | . "github.com/lios/go-activiti/engine/persistence" 6 | . "github.com/lios/go-activiti/engine/variable" 7 | ) 8 | 9 | type TaskEntityImpl struct { 10 | ExecutionEntityImpl 11 | TaskId int64 12 | Variables map[string]interface{} 13 | } 14 | 15 | func (task *TaskEntityImpl) GetTaskId() int64 { 16 | return task.TaskId 17 | } 18 | 19 | func (task *TaskEntityImpl) SetTaskId(taskId int64) { 20 | task.TaskId = taskId 21 | } 22 | 23 | func (task *TaskEntityImpl) GetVariable() map[string]interface{} { 24 | variableManager := GetVariableManager() 25 | variables, err := variableManager.SelectByTaskId(task.TaskId) 26 | if err != nil { 27 | return task.HandleVariable(variables) 28 | } 29 | return nil 30 | } 31 | 32 | func (task *TaskEntityImpl) GetSpecificVariable(variableName string) (Variable, error) { 33 | variableManager := VariableManager{} 34 | return variableManager.SelectTaskId(variableName, task.TaskId) 35 | } 36 | 37 | func (task *TaskEntityImpl) SetScope(variable *Variable) { 38 | variable.TaskId = task.TaskId 39 | } 40 | -------------------------------------------------------------------------------- /engine/executionEntity.go: -------------------------------------------------------------------------------- 1 | package engine 2 | 3 | import ( 4 | "github.com/lios/go-activiti/engine/variable" 5 | ) 6 | 7 | type ExecutionEntity interface { 8 | SetBusinessKey(businessKey string) 9 | 10 | GetCurrentFlowElement() FlowElement 11 | 12 | SetCurrentFlowElement(flow FlowElement) 13 | 14 | GetDeploymentId() int 15 | 16 | SetDeploymentId(deploymentId int) 17 | 18 | GetProcessInstanceId() int64 19 | 20 | SetProcessInstanceId(processInstanceId int64) 21 | 22 | GetProcessDefineId() int64 23 | 24 | SetProcessDefineId(processDefineId int64) 25 | 26 | GetCurrentActivityId() string 27 | 28 | SetCurrentActivityId(currentActivityId string) 29 | 30 | //SetVariable(execution ExecutionEntity,variables map[string]interface{}) error 31 | 32 | GetSpecificVariable(variableName string) (variable.Variable, error) 33 | 34 | SetScope(variable *variable.Variable) 35 | 36 | GetVariable() map[string]interface{} 37 | 38 | GetProcessVariable() map[string]interface{} 39 | 40 | GetTaskId() int64 41 | 42 | SetTaskId(taskId int64) 43 | } 44 | -------------------------------------------------------------------------------- /engine/handler/iActiviti.go: -------------------------------------------------------------------------------- 1 | package handler 2 | 3 | import ( 4 | . "github.com/lios/go-activiti/engine" 5 | . "github.com/lios/go-activiti/engine/common" 6 | "github.com/lios/go-activiti/errs" 7 | "reflect" 8 | "sync" 9 | ) 10 | 11 | var gConstructorMap map[string]ActivitiConstructor 12 | var lock sync.Mutex 13 | 14 | func init() { 15 | gConstructorMap = make(map[string]ActivitiConstructor, 0) 16 | } 17 | 18 | type IActiviti interface { 19 | GetInPut() interface{} 20 | GetOutPut() interface{} 21 | } 22 | 23 | type ActivitiConstructor func(entity ExecutionEntity) IActiviti 24 | 25 | func RegisterConstructor(name string, constructor ActivitiConstructor) error { 26 | lock.Lock() 27 | defer lock.Unlock() 28 | _, ok := gConstructorMap[name] 29 | if !ok { 30 | gConstructorMap[name] = constructor 31 | } else { 32 | return errs.ProcessError{Code: "1005", Msg: "name has register"} 33 | } 34 | return nil 35 | } 36 | 37 | func GetConstructorByName(name string) (ActivitiConstructor, error) { 38 | lock.Lock() 39 | defer lock.Unlock() 40 | constructor, ok := gConstructorMap[name] 41 | if !ok { 42 | return nil, errs.ProcessError{Code: "1006", Msg: "name not find"} 43 | } 44 | return constructor, nil 45 | } 46 | 47 | func PerformTaskListener(entity ExecutionEntity, task UserTask, processKey string) error { 48 | activitiConstructor, err := GetConstructorByName(processKey) 49 | if err != nil { 50 | return err 51 | } 52 | constructor := activitiConstructor(entity) 53 | reflectConstructor := reflect.ValueOf(constructor) 54 | taskParams := []reflect.Value{reflectConstructor} 55 | 56 | method, b := reflectConstructor.Type().MethodByName(task.Name) 57 | if !b { 58 | return nil 59 | } 60 | 61 | callResponse := method.Func.Call(taskParams) 62 | code := callResponse[0].Interface() 63 | errRes := callResponse[1].Interface() 64 | code = code.(string) 65 | if code != ACTIVITI_HANDLER_CODE { 66 | err := errRes.(error) 67 | return err 68 | } 69 | return nil 70 | } 71 | -------------------------------------------------------------------------------- /engine/handler/iActivitiDemo.go: -------------------------------------------------------------------------------- 1 | package handler 2 | 3 | import ( 4 | "fmt" 5 | . "github.com/lios/go-activiti/engine" 6 | "github.com/lios/go-activiti/engine/common" 7 | ) 8 | 9 | func init() { 10 | RegisterConstructor("userAuto", NewTestIActiviti) 11 | } 12 | 13 | func NewTestIActiviti(entity ExecutionEntity) IActiviti { 14 | return &TestIActiviti{ 15 | Entity: entity, 16 | } 17 | } 18 | 19 | type TestIActiviti struct { 20 | Entity ExecutionEntity 21 | InPut string 22 | OutPut string 23 | } 24 | 25 | func (test *TestIActiviti) GetInPut() interface{} { 26 | return test.InPut 27 | } 28 | 29 | func (test *TestIActiviti) GetOutPut() interface{} { 30 | return test.OutPut 31 | } 32 | 33 | func (test *TestIActiviti) User001() (code interface{}, err error) { 34 | variable := test.Entity.GetVariable() 35 | fmt.Println(variable) 36 | return common.ACTIVITI_HANDLER_CODE, nil 37 | } 38 | 39 | func (test *TestIActiviti) User002() (code interface{}, err error) { 40 | return common.ACTIVITI_HANDLER_CODE, nil 41 | } 42 | -------------------------------------------------------------------------------- /engine/manager/dbManager.go: -------------------------------------------------------------------------------- 1 | package manager 2 | 3 | import . "github.com/lios/go-activiti/engine/persistence" 4 | 5 | func GetTaskManager() TaskManager { 6 | return TaskManager{} 7 | } 8 | 9 | func GetDefineManager() DefineManager { 10 | return DefineManager{} 11 | } 12 | func GetVariableManager() VariableManager { 13 | return VariableManager{} 14 | } 15 | 16 | func GetIdentityLinkManager() IdentityLinkManager { 17 | return IdentityLinkManager{} 18 | } 19 | 20 | func GetHistoricActinstManager() HistoricActinstManager { 21 | return HistoricActinstManager{} 22 | } 23 | 24 | func GetHistoricTaskManager() HistoricTaskManager { 25 | return HistoricTaskManager{} 26 | } 27 | 28 | func GetHistoricProcessManager() HistoricProcessManager { 29 | return HistoricProcessManager{} 30 | } 31 | -------------------------------------------------------------------------------- /engine/operation.go: -------------------------------------------------------------------------------- 1 | package engine 2 | 3 | type Operation interface { 4 | Run() error 5 | } 6 | -------------------------------------------------------------------------------- /engine/persistence/defineManager.go: -------------------------------------------------------------------------------- 1 | package persistence 2 | 3 | import ( 4 | "github.com/lios/go-activiti/db" 5 | "github.com/lios/go-activiti/errs" 6 | . "github.com/lios/go-activiti/model" 7 | "github.com/prometheus/common/log" 8 | ) 9 | 10 | type DefineManager struct { 11 | } 12 | 13 | func (define DefineManager) FindDeployedProcessDefinitionByKey(key string) ([]*Bytearry, error) { 14 | bytearries := make([]*Bytearry, 0) 15 | err := db.DB().Where("`key`=?", key).Where("deployment_id != 0").Order("version DESC", true).Find(&bytearries).Error 16 | return bytearries, err 17 | } 18 | 19 | func (define DefineManager) GetBytearry(processDefineId int64) (Bytearry, error) { 20 | bytearries := Bytearry{} 21 | err := db.DB().Where("id=?", processDefineId).First(&bytearries).Error 22 | if err != nil { 23 | log.Infoln("Find bytearry by err", err) 24 | return bytearries, err 25 | } 26 | return bytearries, nil 27 | } 28 | 29 | func (define DefineManager) CreateByteArry(name string, key string, bytes string) error { 30 | bytearries, err := define.FindDeployedProcessDefinitionByKey(key) 31 | if err != nil { 32 | return err 33 | } 34 | var verion = 0 35 | if bytearries != nil && len(bytearries) > 0 { 36 | verion = bytearries[0].Version 37 | verion++ 38 | } 39 | byteArry := Bytearry{Name: name, Bytes: bytes, Key: key, Version: verion} 40 | err = db.DB().Create(&byteArry).Error 41 | if err != nil { 42 | log.Infoln("Create bytearry err", err) 43 | return err 44 | } 45 | return nil 46 | } 47 | 48 | func (define DefineManager) FindProcessByTask(processInstanceId int64) (Bytearry, error) { 49 | bytearries := make([]Bytearry, 0) 50 | var sql = "SELECT b.* FROM bytearry b " + 51 | "LEFT JOIN process_instance p on b.id = p.process_define_id " + 52 | "WHERE p.id = ? " 53 | err := db.DB().Raw(sql, processInstanceId).Find(&bytearries).Error 54 | if err != nil { 55 | return Bytearry{}, err 56 | } 57 | if bytearries != nil && len(bytearries) > 0 { 58 | return bytearries[0], nil 59 | } 60 | return Bytearry{}, errs.ProcessError{Code: "1001", Msg: "Not Find"} 61 | } 62 | -------------------------------------------------------------------------------- /engine/persistence/deploymentManager.go: -------------------------------------------------------------------------------- 1 | package persistence 2 | 3 | import ( 4 | "github.com/lios/go-activiti/db" 5 | . "github.com/lios/go-activiti/model" 6 | "github.com/prometheus/common/log" 7 | "time" 8 | ) 9 | 10 | type DeploymentManager struct { 11 | } 12 | 13 | func (define DeploymentManager) Deployment(name string, key string, bytes []byte) (err error) { 14 | deployment := Deployment{Name: name, Key: key, DeployTime: time.Now()} 15 | err = db.DB().Create(&deployment).Error 16 | if err != nil { 17 | log.Infoln("Create deployment err", err) 18 | return err 19 | } 20 | defineManager := DefineManager{} 21 | bytearries, err := defineManager.FindDeployedProcessDefinitionByKey(key) 22 | if err != nil { 23 | return err 24 | } 25 | var verion = 0 26 | if bytearries != nil && len(bytearries) > 0 { 27 | verion = bytearries[0].Version 28 | verion++ 29 | } 30 | byte := Bytearry{Name: name, Key: key, Bytes: string(bytes), DeploymentId: deployment.Id, Version: verion} 31 | err = db.DB().Create(&byte).Error 32 | if err != nil { 33 | log.Infoln("Create bytearry err", err) 34 | return err 35 | } 36 | return nil 37 | } 38 | -------------------------------------------------------------------------------- /engine/persistence/historicActinstManager.go: -------------------------------------------------------------------------------- 1 | package persistence 2 | 3 | import ( 4 | "github.com/lios/go-activiti/db" 5 | "github.com/lios/go-activiti/engine" 6 | . "github.com/lios/go-activiti/model" 7 | "github.com/prometheus/common/log" 8 | "reflect" 9 | "time" 10 | ) 11 | 12 | type HistoricActinstManager struct { 13 | HistoricActinst HistoricActinst 14 | } 15 | 16 | func (historicActinstManager HistoricActinstManager) Insert() { 17 | err := db.DB().Create(&historicActinstManager.HistoricActinst).Error 18 | if err != nil { 19 | log.Infoln("Create HistoricActinst Err", err) 20 | } 21 | } 22 | 23 | func (historicActinstManager HistoricActinstManager) RecordActivityStart(entity engine.ExecutionEntity) { 24 | historicActinst := HistoricActinst{} 25 | historicActinst.ProcessDefineId = entity.GetProcessDefineId() 26 | historicActinst.ProcessInstanceId = entity.GetProcessInstanceId() 27 | historicActinst.ActId = entity.GetCurrentActivityId() 28 | if entity.GetCurrentFlowElement() != nil { 29 | historicActinst.ActName = entity.GetCurrentFlowElement().GetName() 30 | historicActinst.ActType = historicActinstManager.parseActivityType(entity.GetCurrentFlowElement()) 31 | } 32 | historicActinst.StartTime = time.Now() 33 | historicActinstManager.HistoricActinst = historicActinst 34 | historicActinstManager.Insert() 35 | } 36 | 37 | func (historicActinstManager HistoricActinstManager) FindUnfinishedHistoricActivityInstancesByExecutionAndActivityId(processInstanceId int64, actId string) (HistoricActinst, error) { 38 | historicActinst := HistoricActinst{} 39 | err := db.DB().Where("act_id = ?", actId).Where("proc_inst_id = ?", processInstanceId).First(&historicActinst).Error 40 | if err != nil { 41 | log.Infoln("Select HistoricActinst err: ", err) 42 | return HistoricActinst{}, err 43 | } 44 | return historicActinst, nil 45 | } 46 | 47 | func (historicActinstManager HistoricActinstManager) Update() (err error) { 48 | err = db.DB().Model(&HistoricActinst{}).Where("act_id = ?", historicActinstManager.HistoricActinst.ActId). 49 | Where("proc_inst_id = ?", historicActinstManager.HistoricActinst.ProcessInstanceId). 50 | Update(&historicActinstManager.HistoricActinst).Error 51 | if err != nil { 52 | log.Infoln("Update HistoricActinst err: ", err) 53 | } 54 | return err 55 | } 56 | func (historicActinstManager HistoricActinstManager) UpdateProcessInstanceId() (err error) { 57 | err = db.DB().Model(&HistoricActinst{}).Where("proc_inst_id = ?", historicActinstManager.HistoricActinst.ProcessInstanceId). 58 | Update(&historicActinstManager.HistoricActinst).Error 59 | if err != nil { 60 | log.Infoln("Update HistoricActinst err: ", err) 61 | } 62 | return err 63 | } 64 | 65 | func (historicActinstManager HistoricActinstManager) UpdateTaskId() (err error) { 66 | err = db.DB().Model(&HistoricActinst{}).Where("task_id = ?", historicActinstManager.HistoricActinst.TaskId). 67 | Update(&historicActinstManager.HistoricActinst).Error 68 | if err != nil { 69 | log.Infoln("Update HistoricActinst err: ", err) 70 | } 71 | return err 72 | } 73 | 74 | func (historicActinstManager HistoricActinstManager) RecordTaskCreated(element engine.FlowElement, entity engine.ExecutionEntity) (err error) { 75 | var actinst = HistoricActinst{} 76 | actinst, err = historicActinstManager.FindUnfinishedHistoricActivityInstancesByExecutionAndActivityId(entity.GetProcessInstanceId(), element.GetId()) 77 | if err == nil { 78 | actinst.EndTime = time.Now() 79 | historicActinstManager.HistoricActinst = actinst 80 | err = historicActinstManager.Update() 81 | } 82 | return err 83 | } 84 | 85 | func (historicActinstManager HistoricActinstManager) parseActivityType(element engine.FlowElement) string { 86 | typeOf := reflect.TypeOf(element) 87 | return typeOf.Name() 88 | } 89 | -------------------------------------------------------------------------------- /engine/persistence/historicIdentityLinkManager.go: -------------------------------------------------------------------------------- 1 | package persistence 2 | 3 | import ( 4 | "github.com/lios/go-activiti/db" 5 | "github.com/lios/go-activiti/model" 6 | "github.com/prometheus/common/log" 7 | ) 8 | 9 | type HistoricIdentityLinkManager struct { 10 | HistoricIdentityLink model.HistoricIdentityLink 11 | } 12 | 13 | func (historicIdentityLink HistoricIdentityLinkManager) Insert() (err error) { 14 | err = db.DB().Create(&historicIdentityLink.HistoricIdentityLink).Error 15 | if err != nil { 16 | log.Infoln("Create HistoricIdentityLink Err", err) 17 | } 18 | return err 19 | } 20 | -------------------------------------------------------------------------------- /engine/persistence/historicProcessManager.go: -------------------------------------------------------------------------------- 1 | package persistence 2 | 3 | import ( 4 | "github.com/lios/go-activiti/db" 5 | . "github.com/lios/go-activiti/model" 6 | "github.com/prometheus/common/log" 7 | ) 8 | 9 | type HistoricProcessManager struct { 10 | HistoricProcess HistoricProcess 11 | } 12 | 13 | func (historicProcessManager HistoricProcessManager) Insert() (err error) { 14 | err = db.DB().Create(&historicProcessManager.HistoricProcess).Error 15 | if err != nil { 16 | log.Infoln("Create HistoricActinst Err", err) 17 | } 18 | return err 19 | } 20 | 21 | func (historicProcessManager HistoricProcessManager) MarkEnded() (err error) { 22 | historicProcess := historicProcessManager.HistoricProcess 23 | err = db.DB().Where("proc_inst_id=?", historicProcess.ProcessInstanceId).Update(&historicProcess).Error 24 | if err != nil { 25 | log.Infoln("delete HistoricProcess Err", err) 26 | return err 27 | } 28 | historicActinst := HistoricActinst{} 29 | historicActinst.EndTime = historicProcess.EndTime 30 | historicProcess.ProcessInstanceId = historicProcess.Id 31 | historicActinstManager := HistoricActinstManager{} 32 | historicActinstManager.HistoricActinst = historicActinst 33 | err = historicActinstManager.UpdateProcessInstanceId() 34 | return err 35 | } 36 | -------------------------------------------------------------------------------- /engine/persistence/historicTaskManager.go: -------------------------------------------------------------------------------- 1 | package persistence 2 | 3 | import ( 4 | "github.com/lios/go-activiti/db" 5 | . "github.com/lios/go-activiti/model" 6 | "github.com/prometheus/common/log" 7 | ) 8 | 9 | type HistoricTaskManager struct { 10 | HistoricTask HistoricTask 11 | } 12 | 13 | func (historicTaskManager HistoricTaskManager) Insert() (err error) { 14 | err = db.DB().Create(&historicTaskManager.HistoricTask).Error 15 | if err != nil { 16 | log.Infoln("Create HistoricTask Err", err) 17 | } 18 | return err 19 | } 20 | 21 | func (historicTaskManager HistoricTaskManager) MarkEnded() (err error) { 22 | err = db.DB().Model(&HistoricTask{}).Where("task_id=?", historicTaskManager.HistoricTask.TaskId).Update(&historicTaskManager.HistoricTask).Error 23 | if err != nil { 24 | log.Infoln("Update HistoricTask Err", err) 25 | } 26 | return err 27 | } 28 | -------------------------------------------------------------------------------- /engine/persistence/historicVariableManager.go: -------------------------------------------------------------------------------- 1 | package persistence 2 | 3 | import ( 4 | "github.com/lios/go-activiti/db" 5 | "github.com/lios/go-activiti/engine/variable" 6 | "github.com/prometheus/common/log" 7 | ) 8 | 9 | type HistoricVariableManager struct { 10 | HistoricVariable variable.HistoricVariable 11 | } 12 | 13 | func (historicVariableManager HistoricVariableManager) Insert() (err error) { 14 | err = db.DB().Create(&historicVariableManager.HistoricVariable).Error 15 | if err != nil { 16 | log.Infoln("Create HistoricVariable Err ", err) 17 | } 18 | return err 19 | } 20 | -------------------------------------------------------------------------------- /engine/persistence/identityLinkManager.go: -------------------------------------------------------------------------------- 1 | package persistence 2 | 3 | import ( 4 | "github.com/lios/go-activiti/db" 5 | "github.com/lios/go-activiti/errs" 6 | . "github.com/lios/go-activiti/model" 7 | "github.com/prometheus/common/log" 8 | ) 9 | 10 | type IdentityLinkManager struct { 11 | IdentityLink IdentityLink 12 | } 13 | 14 | //创建流程实例 15 | func (identityLinkManager IdentityLinkManager) CreateIdentityLink() (err error) { 16 | err = db.DB().Create(&identityLinkManager.IdentityLink).Error 17 | if err != nil { 18 | log.Infoln("Create IdentityLink Err ", err) 19 | return err 20 | } 21 | err = identityLinkManager.createHistoricIdentityLink() 22 | return err 23 | } 24 | 25 | func (identityLinkManager IdentityLinkManager) SelectByProcessInstanceId(processInstanceId int64) ([]IdentityLink, error) { 26 | identityLink := make([]IdentityLink, 0) 27 | err := db.DB().Where("proc_inst_id = ?", processInstanceId).Find(&identityLink).Error 28 | if err != nil { 29 | log.Infoln("Select Variable err: ", err) 30 | } 31 | if identityLink == nil || len(identityLink) <= 0 { 32 | return []IdentityLink{}, errs.ProcessError{Code: "1001", Msg: "Not find"} 33 | } 34 | return identityLink, nil 35 | } 36 | 37 | func (identityLinkManager IdentityLinkManager) SelectByTaskId(taskId int64) ([]IdentityLink, error) { 38 | identityLink := make([]IdentityLink, 0) 39 | err := db.DB().Where("task_id = ?", taskId).Find(&identityLink).Error 40 | if err != nil { 41 | log.Infoln("Select Variable err: ", err) 42 | } 43 | if identityLink != nil && len(identityLink) > 0 { 44 | return identityLink, nil 45 | } 46 | return identityLink, errs.ProcessError{Code: "1001", Msg: "Not Find"} 47 | } 48 | 49 | func (identityLinkManager IdentityLinkManager) Delete(identityLinkId int64) (err error) { 50 | identityLink := IdentityLink{} 51 | err = db.DB().Where("id=?", identityLinkId).Delete(&identityLink).Error 52 | if err != nil { 53 | log.Infoln("Delete identityLink err: ", err) 54 | } 55 | return err 56 | } 57 | 58 | func (identityLinkManager IdentityLinkManager) createHistoricIdentityLink() (err error) { 59 | identityLink := identityLinkManager.IdentityLink 60 | historicIdentityLink := HistoricIdentityLink{} 61 | historicIdentityLink.UserId = identityLink.UserId 62 | historicIdentityLink.TaskId = identityLink.TaskId 63 | historicIdentityLink.ProcessInstanceId = identityLink.ProcessInstanceId 64 | historicIdentityLinkManager := HistoricIdentityLinkManager{} 65 | historicIdentityLinkManager.HistoricIdentityLink = historicIdentityLink 66 | err = historicIdentityLinkManager.Insert() 67 | return err 68 | } 69 | -------------------------------------------------------------------------------- /engine/persistence/processInstanceManager.go: -------------------------------------------------------------------------------- 1 | package persistence 2 | 3 | import ( 4 | "github.com/lios/go-activiti/db" 5 | . "github.com/lios/go-activiti/model" 6 | "github.com/prometheus/common/log" 7 | "time" 8 | ) 9 | 10 | type ProcessInstanceManager struct { 11 | Instance *ProcessInstance 12 | } 13 | 14 | //创建流程实例 15 | func (processInstanceManager *ProcessInstanceManager) CreateProcessInstance() { 16 | err := db.DB().Create(&processInstanceManager.Instance).Error 17 | if err != nil { 18 | log.Infoln("create processInstance err", err) 19 | } 20 | 21 | processInstanceManager.createHistoricProcessInstance() 22 | } 23 | 24 | //查询流程实例 25 | func (processInstanceManager *ProcessInstanceManager) GetProcessInstance(processInstanceId int64) ProcessInstance { 26 | instance := ProcessInstance{} 27 | err := db.DB().Where("id = ?", processInstanceId).Find(&instance).Error 28 | if err != nil { 29 | log.Infoln("create processInstance err", err) 30 | } 31 | return instance 32 | } 33 | 34 | //删除流程实例 35 | func (processInstanceManager ProcessInstanceManager) DeleteProcessInstance(processInstanceId int64) (err error) { 36 | err = db.DB().Where("id = ?", processInstanceId).Delete(&ProcessInstance{}).Error 37 | if err != nil { 38 | log.Infoln("delete processInstance err ", err) 39 | return err 40 | } 41 | err = processInstanceManager.recordActivityEnd(processInstanceId) 42 | return err 43 | } 44 | 45 | func (processInstanceManager ProcessInstanceManager) recordActivityEnd(processInstanceId int64) (err error) { 46 | historicProcessManager := HistoricProcessManager{} 47 | historicProcess := HistoricProcess{} 48 | historicProcess.ProcessInstanceId = processInstanceId 49 | historicProcess.EndTime = time.Now() 50 | historicProcessManager.HistoricProcess = historicProcess 51 | err = historicProcessManager.MarkEnded() 52 | return err 53 | } 54 | 55 | func (processInstanceManager *ProcessInstanceManager) createHistoricProcessInstance() (err error) { 56 | processInstance := processInstanceManager.Instance 57 | historicProcess := HistoricProcess{} 58 | //historicProcess.ProcessInstanceEntity = processInstance.ProcessInstanceEntity 59 | historicProcess.ProcessInstanceId = processInstance.Id 60 | historicProcess.DeploymentId = processInstance.DeploymentId 61 | historicProcess.TenantId = processInstance.TenantId 62 | historicProcess.StartTime = processInstance.StartTime 63 | historicProcess.Name = processInstance.Name 64 | historicProcess.BusinessKey = processInstance.BusinessKey 65 | historicProcess.StartUserId = processInstance.StartUserId 66 | historicProcess.Key = processInstance.Key 67 | historicProcess.ProcessDefineId = processInstance.ProcessDefineId 68 | 69 | historicProcessManager := HistoricProcessManager{} 70 | historicProcessManager.HistoricProcess = historicProcess 71 | return historicProcessManager.Insert() 72 | } 73 | -------------------------------------------------------------------------------- /engine/persistence/taskManager.go: -------------------------------------------------------------------------------- 1 | package persistence 2 | 3 | import ( 4 | "fmt" 5 | "github.com/lios/go-activiti/db" 6 | "github.com/lios/go-activiti/engine" 7 | . "github.com/lios/go-activiti/entity" 8 | "github.com/lios/go-activiti/errs" 9 | . "github.com/lios/go-activiti/model" 10 | "github.com/prometheus/common/log" 11 | "time" 12 | ) 13 | 14 | type TaskManager struct { 15 | Task *Task 16 | } 17 | 18 | func (taskManager TaskManager) Insert(execution engine.ExecutionEntity) (err error) { 19 | err = db.DB().Create(taskManager.Task).Error 20 | if err == nil { 21 | err = taskManager.recordTaskCreated(taskManager.Task, execution) 22 | } 23 | //dispatcher := event.GetEventDispatcher() 24 | //dispatcher.DispatchEvent(CreateEntityEvent()) 25 | return err 26 | } 27 | 28 | func (taskManager TaskManager) recordTaskCreated(task *Task, entity engine.ExecutionEntity) (err error) { 29 | historicTaskManager := HistoricTaskManager{} 30 | historicTask := taskManager.createHistoricTask(task) 31 | historicTaskManager.HistoricTask = historicTask 32 | err = historicTaskManager.Insert() 33 | if err != nil { 34 | historicActinstManager := HistoricActinstManager{} 35 | actinst, err := historicActinstManager.FindUnfinishedHistoricActivityInstancesByExecutionAndActivityId(entity.GetProcessInstanceId(), task.TaskDefineKey) 36 | if err == nil { 37 | actinst.Assignee = task.Assignee 38 | actinst.TaskId = task.Id 39 | historicActinstManager.HistoricActinst = actinst 40 | err = historicActinstManager.Update() 41 | } 42 | } 43 | return err 44 | } 45 | 46 | func (taskManager TaskManager) createHistoricTask(task *Task) HistoricTask { 47 | historicTask := HistoricTask{} 48 | //historicTask.TaskEntity = task.TaskEntity 49 | historicTask.TaskId = task.Id 50 | historicTask.ProcessInstanceId = task.ProcessInstanceId 51 | historicTask.StartTime = task.StartTime 52 | historicTask.TenantId = task.TenantId 53 | historicTask.Assignee = task.Assignee 54 | historicTask.TaskDefineKey = task.TaskDefineKey 55 | historicTask.DeploymentId = task.DeploymentId 56 | historicTask.TaskDefineName = task.TaskDefineName 57 | return historicTask 58 | } 59 | 60 | func (taskManager TaskManager) FindById(taskId int) (Task, error) { 61 | task := Task{} 62 | err := db.DB().Where("id= ?", taskId).First(&task).Error 63 | if err != nil { 64 | log.Infoln("Select FindById Err ", err) 65 | return task, err 66 | } 67 | return task, nil 68 | } 69 | 70 | func (taskManager TaskManager) FindByProcessInstanceId(processInstanceId int64) (task []Task, err error) { 71 | task = make([]Task, 0) 72 | err = db.DB().Where("proc_inst_id=?", processInstanceId).Find(&task).Error 73 | if err != nil { 74 | log.Infoln("Select FindByProcessInstanceId err ", err) 75 | } 76 | if task == nil || len(task) <= 0 { 77 | return task, errs.ProcessError{Code: "1001", Msg: "Not find"} 78 | } 79 | return task, err 80 | } 81 | 82 | func (taskManager TaskManager) DeleteTask(task Task) (err error) { 83 | err = db.DB().Where("id = ?", task.Id).Delete(&task).Error 84 | if err != nil { 85 | return err 86 | } 87 | identityLinkManager := IdentityLinkManager{} 88 | identityLinks, errSelect := identityLinkManager.SelectByTaskId(task.Id) 89 | if errSelect == nil { 90 | for _, identityLink := range identityLinks { 91 | err = identityLinkManager.Delete(identityLink.Id) 92 | if err != nil { 93 | return err 94 | } 95 | } 96 | } 97 | variableManager := VariableManager{} 98 | variables, errSelect := variableManager.SelectByTaskId(task.Id) 99 | if errSelect == nil { 100 | for _, variable := range variables { 101 | err = variableManager.Delete(variable.Id) 102 | if err != nil { 103 | return err 104 | } 105 | } 106 | } 107 | err = recordTaskEnd(task) 108 | return err 109 | } 110 | 111 | func recordTaskEnd(task Task) (err error) { 112 | historicTaskManager := HistoricTaskManager{} 113 | historicTask := HistoricTask{} 114 | historicTask.TaskId = task.Id 115 | historicTask.EndTime = time.Now() 116 | historicTaskManager.HistoricTask = historicTask 117 | err = historicTaskManager.MarkEnded() 118 | if err != nil { 119 | return err 120 | } 121 | 122 | historicActinst := HistoricActinst{} 123 | historicActinst.EndTime = historicTask.EndTime 124 | historicActinst.TaskId = historicTask.TaskId 125 | historicActinstManager := HistoricActinstManager{} 126 | historicActinstManager.HistoricActinst = historicActinst 127 | return historicActinstManager.UpdateTaskId() 128 | } 129 | 130 | func (taskManager TaskManager) QueryUndoTask(userId, groupId string) (taskResult []TaskEntity, err error) { 131 | taskResult = make([]TaskEntity, 0) 132 | var sql = "SELECT t.*,i.user_id,i.group_id FROM task t " + 133 | "LEFT JOIN identity_link i on t.id = i.task_id " + 134 | "WHERE 1=1 " 135 | if userId != "" { 136 | sql += fmt.Sprintf("AND i.user_id = '%s' ", userId) 137 | } 138 | if groupId != "" { 139 | sql += fmt.Sprintf("AND i.group_id = '%s' ", groupId) 140 | } 141 | err = db.DB().Raw(sql).Find(&taskResult).Error 142 | if err != nil { 143 | return taskResult, err 144 | } 145 | return taskResult, nil 146 | } 147 | -------------------------------------------------------------------------------- /engine/persistence/variableManager.go: -------------------------------------------------------------------------------- 1 | package persistence 2 | 3 | import ( 4 | "github.com/lios/go-activiti/db" 5 | . "github.com/lios/go-activiti/engine/variable" 6 | "github.com/lios/go-activiti/errs" 7 | "github.com/prometheus/common/log" 8 | ) 9 | 10 | type VariableManager struct { 11 | Variable *Variable 12 | } 13 | 14 | func (define VariableManager) Create(name string, variableType VariableType, value interface{}) *Variable { 15 | variable := Variable{} 16 | variable.Version = 0 17 | variable.Name = name 18 | variable.Type = variableType.GetTypeName() 19 | variable.SetValue(value, variableType) 20 | return &variable 21 | 22 | } 23 | 24 | func (defineManager VariableManager) Insert() (err error) { 25 | err = db.DB().Create(&defineManager.Variable).Error 26 | if err != nil { 27 | log.Infoln("Create Variable Error", err) 28 | return err 29 | } 30 | err = defineManager.createHistoricVariable() 31 | return err 32 | } 33 | 34 | func (defineManager VariableManager) createHistoricVariable() (err error) { 35 | variable := defineManager.Variable 36 | historicVariable := HistoricVariable{} 37 | 38 | historicVariable.TaskId = variable.TaskId 39 | historicVariable.ProcessInstanceId = variable.ProcessInstanceId 40 | historicVariable.Name = variable.Name 41 | historicVariable.Version = variable.Version 42 | historicVariable.Type = variable.Type 43 | historicVariable.Text = variable.Text 44 | historicVariable.Number = variable.Number 45 | historicVariable.Date = variable.Date 46 | historicVariable.Float = variable.Float 47 | historicVariable.Blob = variable.Blob 48 | 49 | historicVariableManager := HistoricVariableManager{} 50 | historicVariableManager.HistoricVariable = historicVariable 51 | return historicVariableManager.Insert() 52 | } 53 | 54 | func (defineManager VariableManager) SelectProcessInstanceId(name string, processInstanceId int64) (Variable, error) { 55 | variables := Variable{} 56 | err := db.DB().Where("proc_inst_id = ?", processInstanceId).Where("name = ?", name).First(&variables).Error 57 | if err != nil { 58 | log.Infoln("Select Variable err: ", err) 59 | return Variable{}, err 60 | } 61 | return variables, nil 62 | } 63 | 64 | func (variableManager VariableManager) SelectTaskId(name string, taskId int64) (Variable, error) { 65 | variables := Variable{} 66 | err := db.DB().Where("task_id = ?", taskId).Where("name = ?", name).First(&variables).Error 67 | if err != nil { 68 | log.Infoln("根据[taskId] 查询流程变量异常", err) 69 | return Variable{}, err 70 | } 71 | return variables, nil 72 | } 73 | 74 | func (variableManager VariableManager) SelectByProcessInstanceId(processInstanceId int64) ([]Variable, error) { 75 | variables := make([]Variable, 0) 76 | err := db.DB().Where("proc_inst_id = ?", processInstanceId).Find(&variables).Error 77 | if err != nil { 78 | log.Infoln("Select Variable err: ", err) 79 | return variables, err 80 | } 81 | if variables != nil && len(variables) > 0 { 82 | return variables, nil 83 | } 84 | return variables, errs.ProcessError{Code: "1001", Msg: "Not Find"} 85 | } 86 | 87 | func (variableManager VariableManager) SelectByTaskId(taskId int64) ([]Variable, error) { 88 | variables := make([]Variable, 0) 89 | err := db.DB().Where("task_id = ?", taskId).Find(&variables).Error 90 | if err != nil { 91 | log.Infoln("Select Variable err: ", err) 92 | return variables, err 93 | } 94 | if variables != nil && len(variables) > 0 { 95 | return variables, nil 96 | } 97 | return variables, errs.ProcessError{Code: "1001", Msg: "Not Find"} 98 | } 99 | 100 | func (variableManager VariableManager) Delete(variableId int64) error { 101 | variable := Variable{} 102 | err := db.DB().Where("id=?", variableId).Delete(variable).Error 103 | if err != nil { 104 | log.Infoln("delete Variable err: ", err) 105 | } 106 | return err 107 | } 108 | -------------------------------------------------------------------------------- /engine/process.go: -------------------------------------------------------------------------------- 1 | package engine 2 | 3 | import ( 4 | "encoding/xml" 5 | "github.com/lios/go-activiti/errs" 6 | ) 7 | 8 | var ( 9 | //将元素存入map 10 | processMap = make(map[int64]Process, 0) 11 | ) 12 | 13 | //流程定义对象 14 | type Definitions struct { 15 | DefinitionsName xml.Name `xml:"definitions"` 16 | Xmlns string `xml:"xmlns,attr"` 17 | Xsi string `xml:"xsi,attr"` 18 | Xsd string `xml:"xsd,attr"` 19 | Activiti string `xml:"activiti,attr"` 20 | Bpmndi string `xml:"bpmndi,attr"` 21 | Omgdc string `xml:"omgdc,attr"` 22 | Omgdi string `xml:"omgdi,attr"` 23 | TypeLanguage string `xml:"typeLanguage,attr"` 24 | RgetNamespace string `xml:"rgetNamespace,attr"` 25 | ExpressionLanguage string `xml:"expressionLanguage,attr"` 26 | TargetNamespace string `xml:"targetNamespace,attr"` 27 | Process []Process `xml:"process"` 28 | Message []Message `xml:"message"` 29 | } 30 | type Process struct { 31 | ProcessName xml.Name `xml:"process"` 32 | Id string `xml:"id,attr"` 33 | Name string `xml:"name,attr"` 34 | Documentation string `xml:"documentation"` 35 | IsExecutable string `xml:"isExecutable,attr"` 36 | StartEvent []StartEvent `xml:"startEvent"` 37 | EndEvent []EndEvent `xml:"endEvent"` 38 | UserTask []UserTask `xml:"userTask"` 39 | SequenceFlow []SequenceFlow `xml:"sequenceFlow"` 40 | ExclusiveGateway []ExclusiveGateway `xml:"exclusiveGateway"` 41 | InclusiveGateway []InclusiveGateway `xml:"inclusiveGateway"` 42 | ParallelGateway []ParallelGateway `xml:"parallelGateway"` 43 | BoundaryEvent []BoundaryEvent `xml:"boundaryEvent"` 44 | IntermediateCatchEvent []IntermediateCatchEvent `xml:"intermediateCatchEvent"` 45 | SubProcess []SubProcess `xml:"subProcess"` 46 | Flow []FlowElement 47 | InitialFlowElement FlowElement 48 | FlowMap map[string]FlowElement 49 | } 50 | 51 | //子流程 52 | type SubProcess struct { 53 | *Process 54 | SubProcessName xml.Name `xml:"subProcess"` 55 | } 56 | 57 | //消息订阅 58 | type Message struct { 59 | *BaseElement 60 | MessageName xml.Name `xml:"message"` 61 | } 62 | 63 | //通用字段 64 | type BaseElement struct { 65 | Id string `xml:"id,attr"` 66 | Name string `xml:"name,attr"` 67 | } 68 | 69 | //父类实现体 70 | type Flow struct { 71 | BaseElement 72 | Id string `xml:"id,attr"` 73 | Name string `xml:"name,attr"` 74 | IncomingFlow []FlowElement 75 | OutgoingFlow []FlowElement 76 | SourceFlowElement FlowElement 77 | TargetFlowElement FlowElement 78 | Behavior ActivityBehavior 79 | } 80 | 81 | //开始节点 82 | type StartEvent struct { 83 | *Flow 84 | StartEventName xml.Name `xml:"startEvent"` 85 | Initiator string `xml:"initiator,attr"` 86 | FormKey string `xml:"formKey,attr"` 87 | } 88 | 89 | //结束节点 90 | type EndEvent struct { 91 | *Flow 92 | EndEventName xml.Name `xml:"endEvent"` 93 | } 94 | 95 | //用户任务 96 | type UserTask struct { 97 | *Flow 98 | UserTaskName xml.Name `xml:"userTask"` 99 | Assignee string `xml:"assignee,attr"` 100 | CandidateUsers []string `xml:"candidateUsers,attr"` 101 | CandidateGroups []string `xml:"candidateGroups,attr"` 102 | ExtensionElements ExtensionElements `xml:"extensionElements"` 103 | } 104 | 105 | type ExtensionElements struct { 106 | ExtensionElementName xml.Name `xml:"extensionElements"` 107 | TaskListener []TaskListener `xml:"taskListener"` 108 | } 109 | type TaskListener struct { 110 | TaskListenerName xml.Name `xml:"taskListener"` 111 | EventType string `xml:"event,attr"` 112 | } 113 | 114 | //连线 115 | type SequenceFlow struct { 116 | *Flow 117 | SequenceFlowName xml.Name `xml:"sequenceFlow"` 118 | Id string `xml:"id,attr"` 119 | SourceRef string `xml:"sourceRef,attr"` 120 | TargetRef string `xml:"targetRef,attr"` 121 | ConditionExpression string `xml:"conditionExpression"` 122 | } 123 | type Gateway struct { 124 | *Flow 125 | DefaultFlow string 126 | } 127 | 128 | //排他网关 129 | type ExclusiveGateway struct { 130 | *Gateway 131 | } 132 | 133 | //包容网关 134 | type InclusiveGateway struct { 135 | *Gateway 136 | } 137 | 138 | //并行网关 139 | type ParallelGateway struct { 140 | *Gateway 141 | } 142 | 143 | //边界事件 144 | type BoundaryEvent struct { 145 | *Flow 146 | BoundaryEventName xml.Name `xml:"boundaryEvent"` 147 | AttachedToRef string `xml:"attachedToRef,attr"` 148 | CancelActivity string `xml:"cancelActivity,attr"` 149 | TimerEventDefinition TimerEventDefinition `xml:"timerEventDefinition"` 150 | } 151 | 152 | //定时任务 153 | type TimerEventDefinition struct { 154 | TimerEventDefinitionName xml.Name `xml:"timerEventDefinition"` 155 | TimeDuration string `xml:"timeDuration"` 156 | } 157 | 158 | //中间抛出事件 159 | type IntermediateCatchEvent struct { 160 | *Flow 161 | IntermediateCatchEventName xml.Name `xml:"intermediateCatchEvent"` 162 | MessageEventDefinition MessageEventDefinition `xml:"messageEventDefinition"` 163 | } 164 | 165 | //消息事件 166 | type MessageEventDefinition struct { 167 | MessageEventDefinitionName xml.Name `xml:"messageEventDefinition"` 168 | MessageRef string `xml:"messageRef,attr"` 169 | } 170 | 171 | //接口 172 | type FlowElement interface { 173 | SetIncoming(f []FlowElement) 174 | SetOutgoing(f []FlowElement) 175 | GetIncoming() []FlowElement 176 | GetOutgoing() []FlowElement 177 | 178 | SetSourceFlowElement(f FlowElement) 179 | SetTargetFlowElement(f FlowElement) 180 | GetSourceFlowElement() FlowElement 181 | GetTargetFlowElement() FlowElement 182 | 183 | GetBehavior() ActivityBehavior 184 | SetBehavior(behavior ActivityBehavior) 185 | 186 | GetId() string 187 | GetName() string 188 | } 189 | 190 | func SetProcess(defineId int64, process Process) { 191 | //_,err := processMap[process.Id] 192 | processMap[defineId] = process 193 | } 194 | 195 | func GetProcess(id int64) (Process, error) { 196 | process, ok := processMap[id] 197 | if !ok { 198 | return Process{}, errs.ProcessError{} 199 | } 200 | return process, nil 201 | } 202 | 203 | func (pocess Process) GetFlowElement(flowElementId string) FlowElement { 204 | return pocess.FlowMap[flowElementId] 205 | } 206 | 207 | func (flow *Flow) SetIncoming(f []FlowElement) { 208 | flow.IncomingFlow = f 209 | } 210 | func (flow *Flow) SetOutgoing(f []FlowElement) { 211 | flow.OutgoingFlow = f 212 | } 213 | 214 | func (flow *Flow) GetIncoming() []FlowElement { 215 | return flow.IncomingFlow 216 | } 217 | func (flow *Flow) GetOutgoing() []FlowElement { 218 | return flow.OutgoingFlow 219 | } 220 | 221 | func (flow *Flow) SetSourceFlowElement(f FlowElement) { 222 | flow.SourceFlowElement = f 223 | } 224 | func (flow *Flow) SetTargetFlowElement(f FlowElement) { 225 | flow.TargetFlowElement = f 226 | } 227 | 228 | func (flow *Flow) GetSourceFlowElement() FlowElement { 229 | return flow.SourceFlowElement 230 | } 231 | func (flow *Flow) GetTargetFlowElement() FlowElement { 232 | return flow.TargetFlowElement 233 | } 234 | 235 | func (flow *Flow) GetBehavior() ActivityBehavior { 236 | return flow.Behavior 237 | } 238 | func (flow *Flow) SetBehavior(behavior ActivityBehavior) { 239 | flow.Behavior = behavior 240 | } 241 | 242 | func (flow *Flow) GetId() string { 243 | return flow.Id 244 | } 245 | 246 | func (flow *Flow) GetName() string { 247 | return flow.Name 248 | } 249 | -------------------------------------------------------------------------------- /engine/service/repositoryService.go: -------------------------------------------------------------------------------- 1 | package engine 2 | 3 | import ( 4 | "github.com/lios/go-activiti/engine/behavior" 5 | "github.com/lios/go-activiti/engine/cmd" 6 | ) 7 | 8 | type RepositoryService struct { 9 | } 10 | 11 | //流程部署 12 | func (this RepositoryService) Deploy(name string, key string, bytes []byte) { 13 | behavior.GetServiceImpl().CommandExecutor.Exe(cmd.DeploymentCmd{Name: name, Key: key, Bytes: bytes}) 14 | } 15 | -------------------------------------------------------------------------------- /engine/service/runtimeService.go: -------------------------------------------------------------------------------- 1 | package engine 2 | 3 | import ( 4 | "github.com/lios/go-activiti/engine/behavior" 5 | "github.com/lios/go-activiti/engine/cmd" 6 | ) 7 | 8 | type RuntimeService struct { 9 | behavior.ServiceImpl 10 | } 11 | 12 | //发起流程 13 | func (runtime RuntimeService) StartProcessInstanceByKey(processDefinitionKey string, variables map[string]interface{}, 14 | businessKey string, tenantId string) { 15 | behavior.GetServiceImpl().CommandExecutor.Exe(cmd.StartProcessInstanceByKeyCmd{ProcessDefinitionKey: processDefinitionKey, 16 | Variables: variables, TenantId: tenantId, BusinessKey: businessKey}) 17 | } 18 | -------------------------------------------------------------------------------- /engine/service/taskService.go: -------------------------------------------------------------------------------- 1 | package engine 2 | 3 | import ( 4 | "github.com/lios/go-activiti/engine/behavior" 5 | "github.com/lios/go-activiti/engine/cmd" 6 | . "github.com/lios/go-activiti/entity" 7 | . "github.com/lios/go-activiti/model" 8 | ) 9 | 10 | type TaskService struct { 11 | } 12 | 13 | //查询待审批任务 14 | func (taskService TaskService) QueryUndoTask(userId, groupId string) ([]TaskEntity, error) { 15 | exe, err := behavior.GetServiceImpl().CommandExecutor.Exe(cmd.GetTaskCmd{UserId: userId, GroupId: groupId}) 16 | if err != nil { 17 | return nil, err 18 | } 19 | results, ok := exe.([]TaskEntity) 20 | if ok { 21 | return results, nil 22 | } 23 | return nil, err 24 | } 25 | 26 | //流程审批完成 27 | func (taskService TaskService) Complete(taskId int, variables map[string]interface{}, localScope bool) (Task, error) { 28 | var task Task 29 | exe, err := behavior.GetServiceImpl().CommandExecutor.Exe(cmd.CompleteCmd{TaskId: taskId, Variables: variables, LocalScope: localScope}) 30 | if err != nil { 31 | return task, err 32 | } 33 | return exe.(Task), nil 34 | } 35 | 36 | //查询待审批任务 37 | func (taskService TaskService) BackTask(taskId int, targetFlowId string) (bool, error) { 38 | exe, err := behavior.GetServiceImpl().CommandExecutor.Exe(cmd.BackTaskCmd{TaskId: taskId, TargetFlowId: targetFlowId}) 39 | if err != nil { 40 | return false, err 41 | } 42 | return exe.(bool), nil 43 | } 44 | -------------------------------------------------------------------------------- /engine/utils/conditionUtil.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | . "github.com/heartlhj/go-expression/expression" 5 | . "github.com/heartlhj/go-expression/expression/spel" 6 | "github.com/lios/go-activiti/engine" 7 | ) 8 | 9 | var ( 10 | context = StandardEvaluationContext{} 11 | parser = SpelExpressionParser{} 12 | ) 13 | 14 | type ConditionUtil struct { 15 | } 16 | 17 | func HasTrueCondition(sequenceFlow engine.SequenceFlow, execution engine.ExecutionEntity) bool { 18 | var conditionExpression = sequenceFlow.ConditionExpression 19 | if conditionExpression != "" { 20 | variable := execution.GetProcessVariable() 21 | context.SetVariables(variable) 22 | valueContext := parser.ParseExpression(conditionExpression).GetValueContext(&context) 23 | b, ok := valueContext.(bool) 24 | if ok { 25 | return b 26 | } 27 | return false 28 | } else { 29 | return true 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /engine/utils/executionGraphUtil.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import . "github.com/lios/go-activiti/engine" 4 | 5 | type ExecutionGraphUtil struct { 6 | } 7 | 8 | func IsReachable(process Process, sourceElementId string, targetElementId string) bool { 9 | sourceFlowElement := process.FlowMap[sourceElementId] 10 | sourceFlow, ok := sourceFlowElement.(SequenceFlow) 11 | if !ok { 12 | element := sourceFlow.GetTargetFlowElement() 13 | flow, _ := (element).(SequenceFlow) 14 | sourceFlow = flow 15 | } 16 | 17 | targetFlowElement := process.FlowMap[targetElementId] 18 | targetFlow, ok := targetFlowElement.(SequenceFlow) 19 | if !ok { 20 | element := targetFlow.GetTargetFlowElement() 21 | flow, _ := (element).(SequenceFlow) 22 | targetFlow = flow 23 | } 24 | var visitedElements = make(map[string]FlowElement, 0) 25 | return isReachable(process, sourceFlow, targetFlow, visitedElements) 26 | 27 | } 28 | 29 | func isReachable(process Process, sourceElement FlowElement, targetElement FlowElement, visitedElements map[string]FlowElement) bool { 30 | if sourceElement.GetId() == targetElement.GetId() { 31 | return true 32 | } 33 | visitedElements[sourceElement.GetId()] = sourceElement 34 | outgoing := sourceElement.GetOutgoing() 35 | if outgoing != nil && len(outgoing) > 0 { 36 | for _, value := range outgoing { 37 | sequenceFlowTarget := (value).GetTargetFlowElement() 38 | if sequenceFlowTarget != nil && visitedElements[(sequenceFlowTarget).GetId()] != nil { 39 | var reachable = isReachable(process, sequenceFlowTarget, targetElement, visitedElements) 40 | if reachable { 41 | return true 42 | } 43 | } 44 | } 45 | } 46 | return false 47 | } 48 | -------------------------------------------------------------------------------- /engine/variable/boolType.go: -------------------------------------------------------------------------------- 1 | package variable 2 | 3 | type BooleanType struct { 4 | } 5 | 6 | func (boolType BooleanType) GetTypeName() string { 7 | return "bool" 8 | } 9 | 10 | func (boolType BooleanType) GetValue(valueFields ValueFields) interface{} { 11 | return valueFields.GetTextValue() == "true" 12 | } 13 | 14 | func (boolType BooleanType) SetValue(value interface{}, valueFields ValueFields) { 15 | b, ok := value.(bool) 16 | if ok { 17 | if b { 18 | valueFields.SetTextValue("true") 19 | } else { 20 | valueFields.SetTextValue("false") 21 | } 22 | } 23 | valueFields.SetBlobValue("") 24 | } 25 | -------------------------------------------------------------------------------- /engine/variable/defaultVariableTypes.go: -------------------------------------------------------------------------------- 1 | package variable 2 | 3 | var ( 4 | typesList = make(map[string]VariableType, 0) 5 | ) 6 | 7 | type DefaultVariableTypes struct { 8 | } 9 | 10 | func (variableTypes DefaultVariableTypes) AddType(variableType VariableType) { 11 | typesList[variableType.GetTypeName()] = variableType 12 | } 13 | 14 | func (variableTypes DefaultVariableTypes) GetVariableType(typeName string) VariableType { 15 | return typesList[typeName] 16 | } 17 | -------------------------------------------------------------------------------- /engine/variable/historicVariable.go: -------------------------------------------------------------------------------- 1 | package variable 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | type HistoricVariable struct { 8 | Id int64 9 | Version int64 `gorm:"column:version"` 10 | TaskId int64 `gorm:"column:task_id"` 11 | ProcessInstanceId int64 `gorm:"column:proc_inst_id"` 12 | Name string `gorm:"column:name"` 13 | Type string `gorm:"column:type"` 14 | Date time.Time `gorm:"column:date"` 15 | Number int `gorm:"column:number"` 16 | Float float64 `gorm:"column:float"` 17 | Text string `gorm:"column:text"` 18 | Blob string `gorm:"column:blob"` 19 | } 20 | 21 | func (HistoricVariable) TableName() string { 22 | return "hi_variable" 23 | } 24 | 25 | func (variable HistoricVariable) GetName() string { 26 | return variable.Name 27 | } 28 | 29 | func (variable HistoricVariable) GetProcessInstanceId() int64 { 30 | return variable.ProcessInstanceId 31 | } 32 | 33 | func (variable HistoricVariable) GetTaskId() int64 { 34 | return variable.TaskId 35 | } 36 | 37 | func (variable HistoricVariable) GetNumberValue() int { 38 | return variable.Number 39 | } 40 | 41 | func (variable *HistoricVariable) SetNumberValue(value int) { 42 | variable.Number = value 43 | } 44 | 45 | func (variable HistoricVariable) GetTextValue() string { 46 | return variable.Text 47 | } 48 | 49 | func (variable *HistoricVariable) SetTextValue(value string) { 50 | variable.Text = value 51 | } 52 | 53 | func (variable *HistoricVariable) SetValue(value interface{}, variableType VariableType) { 54 | variableType.SetValue(value, variable) 55 | } 56 | 57 | func (variable *HistoricVariable) SetBlobValue(value string) { 58 | variable.Blob = value 59 | } 60 | 61 | func (variable HistoricVariable) GetBlobValue() string { 62 | return variable.Blob 63 | } 64 | -------------------------------------------------------------------------------- /engine/variable/intType.go: -------------------------------------------------------------------------------- 1 | package variable 2 | 3 | type IntType struct { 4 | } 5 | 6 | func (intType IntType) GetTypeName() string { 7 | return "int" 8 | } 9 | 10 | func (intType IntType) GetValue(valueFields ValueFields) interface{} { 11 | return valueFields.GetNumberValue() 12 | } 13 | 14 | func (intType IntType) SetValue(value interface{}, valueFields ValueFields) { 15 | valueInt, ok := value.(int) 16 | if ok { 17 | valueFields.SetNumberValue(valueInt) 18 | } 19 | valueFields.SetBlobValue("") 20 | } 21 | -------------------------------------------------------------------------------- /engine/variable/mapType.go: -------------------------------------------------------------------------------- 1 | package variable 2 | 3 | import "encoding/json" 4 | 5 | type MapType struct { 6 | } 7 | 8 | func (mapType MapType) GetTypeName() string { 9 | return "map" 10 | } 11 | 12 | func (mapType MapType) GetValue(valueFields ValueFields) interface{} { 13 | var tempMap map[string]interface{} 14 | err := json.Unmarshal([]byte(valueFields.GetTextValue()), &tempMap) 15 | if err != nil { 16 | panic(err) 17 | } 18 | return tempMap 19 | } 20 | 21 | func (mapType MapType) SetValue(value interface{}, valueFields ValueFields) { 22 | b, ok := value.(map[string]interface{}) 23 | if ok { 24 | dataType, _ := json.Marshal(b) 25 | dataString := string(dataType) 26 | valueFields.SetTextValue(dataString) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /engine/variable/stringType.go: -------------------------------------------------------------------------------- 1 | package variable 2 | 3 | type StringType struct { 4 | } 5 | 6 | func (stringType StringType) GetTypeName() string { 7 | return "string" 8 | } 9 | 10 | func (stringType StringType) GetValue(valueFields ValueFields) interface{} { 11 | return valueFields.GetTextValue() 12 | } 13 | 14 | func (stringType StringType) SetValue(value interface{}, valueFields ValueFields) { 15 | b, ok := value.(string) 16 | if ok { 17 | valueFields.SetTextValue(b) 18 | } 19 | valueFields.SetBlobValue("") 20 | } 21 | -------------------------------------------------------------------------------- /engine/variable/valueFields.go: -------------------------------------------------------------------------------- 1 | package variable 2 | 3 | type ValueFields interface { 4 | GetName() string 5 | 6 | GetProcessInstanceId() int64 7 | 8 | GetTaskId() int64 9 | 10 | GetNumberValue() int 11 | 12 | SetNumberValue(value int) 13 | 14 | GetTextValue() string 15 | 16 | SetTextValue(value string) 17 | 18 | SetBlobValue(value string) 19 | 20 | GetBlobValue() string 21 | } 22 | -------------------------------------------------------------------------------- /engine/variable/variable.go: -------------------------------------------------------------------------------- 1 | package variable 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | type Variable struct { 8 | Id int64 9 | Version int64 `gorm:"column:version"` 10 | TaskId int64 `gorm:"column:task_id"` 11 | ProcessInstanceId int64 `gorm:"column:proc_inst_id"` 12 | Name string `gorm:"column:name"` 13 | Type string `gorm:"column:type"` 14 | Date time.Time `gorm:"column:date"` 15 | Number int `gorm:"column:number"` 16 | Float float64 `gorm:"column:float"` 17 | Text string `gorm:"column:text"` 18 | Blob string `gorm:"column:blob"` 19 | } 20 | 21 | func (Variable) TableName() string { 22 | return "variable" 23 | } 24 | 25 | func (variable Variable) GetName() string { 26 | return variable.Name 27 | } 28 | 29 | func (variable Variable) GetProcessInstanceId() int64 { 30 | return variable.ProcessInstanceId 31 | } 32 | 33 | func (variable Variable) GetTaskId() int64 { 34 | return variable.TaskId 35 | } 36 | 37 | func (variable Variable) GetNumberValue() int { 38 | return variable.Number 39 | } 40 | 41 | func (variable *Variable) SetNumberValue(value int) { 42 | variable.Number = value 43 | } 44 | 45 | func (variable Variable) GetTextValue() string { 46 | return variable.Text 47 | } 48 | 49 | func (variable *Variable) SetTextValue(value string) { 50 | variable.Text = value 51 | } 52 | 53 | func (variable *Variable) SetValue(value interface{}, variableType VariableType) { 54 | variableType.SetValue(value, variable) 55 | } 56 | 57 | func (variable *Variable) SetBlobValue(value string) { 58 | variable.Blob = value 59 | } 60 | 61 | func (variable Variable) GetBlobValue() string { 62 | return variable.Blob 63 | } 64 | -------------------------------------------------------------------------------- /engine/variable/variableInstanceEntity.go: -------------------------------------------------------------------------------- 1 | package variable 2 | 3 | type VariableInstanceEntit interface { 4 | GetType() VariableType 5 | 6 | SetType(variableType VariableType) 7 | } 8 | -------------------------------------------------------------------------------- /engine/variable/variableType.go: -------------------------------------------------------------------------------- 1 | package variable 2 | 3 | type VariableType interface { 4 | GetTypeName() string 5 | 6 | GetValue(valueFields ValueFields) interface{} 7 | 8 | SetValue(value interface{}, valueFields ValueFields) 9 | } 10 | -------------------------------------------------------------------------------- /engine/variable/variableTypes.go: -------------------------------------------------------------------------------- 1 | package variable 2 | 3 | type VariableTypes interface { 4 | AddType(variableType VariableType) 5 | 6 | GetVariableType(typeName string) VariableType 7 | } 8 | -------------------------------------------------------------------------------- /engine/variableScope.go: -------------------------------------------------------------------------------- 1 | package engine 2 | 3 | type VariableScope interface { 4 | SetVariable(variableName string, value interface{}) 5 | } 6 | -------------------------------------------------------------------------------- /entity/identityLinkEntity.go: -------------------------------------------------------------------------------- 1 | package entity 2 | 3 | type IdentityLinkEntity struct { 4 | } 5 | -------------------------------------------------------------------------------- /entity/processInstanceEntity.go: -------------------------------------------------------------------------------- 1 | package entity 2 | 3 | type ProcessInstanceEntity struct { 4 | } 5 | -------------------------------------------------------------------------------- /entity/taskEntity.go: -------------------------------------------------------------------------------- 1 | package entity 2 | 3 | import "time" 4 | 5 | type TaskEntity struct { 6 | Id int64 `json:"id"` 7 | TaskDefineKey string `json:"task_define_key"` 8 | TaskDefineName string `json:"task_define_name"` 9 | TenantId string `json:"tenant_id"` 10 | DeploymentId int `json:"deployment_id"` 11 | StartTime time.Time `json:"start_time"` 12 | Assignee string `json:"assignee"` 13 | ProcInstId int64 `json:"proc_inst_id"` 14 | UserId string `json:"user_id"` 15 | GroupId string `json:"group_id"` 16 | } 17 | -------------------------------------------------------------------------------- /entity/variableEntity.go: -------------------------------------------------------------------------------- 1 | package entity 2 | 3 | type VariableEntity struct { 4 | } 5 | -------------------------------------------------------------------------------- /errs/errs.go: -------------------------------------------------------------------------------- 1 | package errs 2 | 3 | type Err struct { 4 | Error string `json:"error"` 5 | ErrorCode string `json:"error_code"` 6 | } 7 | 8 | type ErrResponse struct { 9 | HttpSC int 10 | Error Err 11 | } 12 | 13 | var ( 14 | ErrorRequestBodyParseFailed = ErrResponse{HttpSC: 400, Error: Err{Error: "Request body is not correct", ErrorCode: "001"}} 15 | ErrorNotAuthUser = ErrResponse{HttpSC: 401, Error: Err{Error: "User authentication failed", ErrorCode: "002"}} 16 | ErrorDBError = ErrResponse{HttpSC: 500, Error: Err{Error: "DB ops failed", ErrorCode: "003"}} 17 | ErrorInternalFaults = ErrResponse{HttpSC: 500, Error: Err{Error: "Internal service error", ErrorCode: "004"}} 18 | ) 19 | -------------------------------------------------------------------------------- /errs/processError.go: -------------------------------------------------------------------------------- 1 | package errs 2 | 3 | type ProcessError struct { 4 | Code string 5 | Msg string 6 | } 7 | 8 | func (error ProcessError) Error() string { 9 | return error.Code + "---" + error.Msg 10 | } 11 | -------------------------------------------------------------------------------- /event/activitiEntityEvent.go: -------------------------------------------------------------------------------- 1 | package event 2 | 3 | type ActivitiEntityEvent interface { 4 | ActivitiEvent 5 | GetEntity() interface{} 6 | } 7 | -------------------------------------------------------------------------------- /event/activitiEvent.go: -------------------------------------------------------------------------------- 1 | package event 2 | 3 | type ActivitiEventType string 4 | 5 | const ( 6 | TASK_CREATED ActivitiEventType = "TASK_CREATED" 7 | 8 | TASK_ASSIGNED ActivitiEventType = "TASK_ASSIGNED" 9 | 10 | TASK_COMPLETED ActivitiEventType = "TASK_COMPLETED" 11 | ) 12 | 13 | type ActivitiEvent interface { 14 | GetType() ActivitiEventType 15 | } 16 | -------------------------------------------------------------------------------- /event/activitiEventDispatcher.go: -------------------------------------------------------------------------------- 1 | package event 2 | 3 | type ActivitiEventDispatcher interface { 4 | AddEventListener(listenerToAdd ActivitiEventListener) 5 | 6 | RemoveEventListener(listenerToRemove ActivitiEventListener) 7 | 8 | DispatchEvent(event ActivitiEvent) 9 | 10 | SetEnabled(enabled bool) 11 | 12 | IsEnabled() bool 13 | } 14 | -------------------------------------------------------------------------------- /event/activitiEventDispatcherImpl.go: -------------------------------------------------------------------------------- 1 | package event 2 | 3 | var eventDispatcher ActivitiEventDispatcher 4 | 5 | type ActivitiEventDispatcherImpl struct { 6 | EventSupport *ActivitiEventSupport 7 | Enabled bool 8 | } 9 | 10 | func SetEventDispatcher(event ActivitiEventDispatcher) { 11 | eventDispatcher = event 12 | } 13 | 14 | func GetEventDispatcher() ActivitiEventDispatcher { 15 | return eventDispatcher 16 | } 17 | func (eventDispatcher ActivitiEventDispatcherImpl) AddEventListener(listenerToAdd ActivitiEventListener) { 18 | eventDispatcher.EventSupport.AddEventListener(listenerToAdd) 19 | } 20 | 21 | func (eventDispatcher ActivitiEventDispatcherImpl) RemoveEventListener(listenerToRemove ActivitiEventListener) { 22 | } 23 | 24 | func (eventDispatcher ActivitiEventDispatcherImpl) DispatchEvent(event ActivitiEvent) { 25 | if eventDispatcher.Enabled { 26 | eventDispatcher.EventSupport.DispatchEvent(event) 27 | } 28 | } 29 | 30 | func (eventDispatcher ActivitiEventDispatcherImpl) SetEnabled(enabled bool) { 31 | eventDispatcher.Enabled = enabled 32 | } 33 | 34 | func (eventDispatcher ActivitiEventDispatcherImpl) IsEnabled() bool { 35 | return eventDispatcher.Enabled 36 | } 37 | -------------------------------------------------------------------------------- /event/activitiEventListener.go: -------------------------------------------------------------------------------- 1 | package event 2 | 3 | type ActivitiEventListener interface { 4 | OnEvent(event ActivitiEvent) error 5 | } 6 | -------------------------------------------------------------------------------- /event/activitiEventSupport.go: -------------------------------------------------------------------------------- 1 | package event 2 | 3 | import . "github.com/lios/go-activiti/errs" 4 | 5 | type ActivitiEventSupport struct { 6 | EventListeners []ActivitiEventListener 7 | } 8 | 9 | func (activitiEventSupport *ActivitiEventSupport) AddEventListener(listenerToAdd ActivitiEventListener) (err error) { 10 | if listenerToAdd == nil { 11 | err = ProcessError{Msg: "Listener cannot be null."} 12 | } 13 | activitiEventSupport.EventListeners = append(activitiEventSupport.EventListeners, listenerToAdd) 14 | return err 15 | } 16 | 17 | func (activitiEventSupport ActivitiEventSupport) DispatchEvent(event ActivitiEvent) (err error) { 18 | if event == nil { 19 | err = ProcessError{Msg: "Event cannot be null."} 20 | return err 21 | } 22 | 23 | if len(event.GetType()) == 0 { 24 | err = ProcessError{Msg: "Event type cannot be null."} 25 | return err 26 | } 27 | 28 | // Call global listeners 29 | if activitiEventSupport.EventListeners != nil && len(activitiEventSupport.EventListeners) > 0 { 30 | for _, listener := range activitiEventSupport.EventListeners { 31 | err = dispatchEvent(event, listener) 32 | if err != nil { 33 | return err 34 | } 35 | } 36 | } 37 | return err 38 | } 39 | 40 | func dispatchEvent(event ActivitiEvent, listener ActivitiEventListener) error { 41 | return listener.OnEvent(event) 42 | } 43 | -------------------------------------------------------------------------------- /event/impl/activitiEntityEventImpl.go: -------------------------------------------------------------------------------- 1 | package impl 2 | 3 | import . "github.com/lios/go-activiti/event" 4 | 5 | type ActivitiEntityEventImpl struct { 6 | ActivitiEntityEvent 7 | ActivitiEventImpl 8 | Entity interface{} 9 | } 10 | 11 | func (ActivitiEntityEventImpl) GetType() ActivitiEventType { 12 | return TASK_CREATED 13 | } 14 | -------------------------------------------------------------------------------- /event/impl/activitiEventBuilder.go: -------------------------------------------------------------------------------- 1 | package impl 2 | 3 | import ( 4 | "github.com/lios/go-activiti/errs" 5 | . "github.com/lios/go-activiti/event" 6 | ) 7 | 8 | type ActivitiEventBuilder struct { 9 | } 10 | 11 | func CreateEvent() ActivitiEvent { 12 | return nil 13 | } 14 | 15 | func CreateEntityEvent(eventType ActivitiEventType, entity interface{}) (ActivitiEntityEvent, error) { 16 | entityEventImpl := ActivitiEntityEventImpl{} 17 | entityEventImpl.ActivitiEventImpl = ActivitiEventImpl{} 18 | entityEventImpl.EventType = eventType 19 | var err error = nil 20 | if entity == nil { 21 | err = errs.ProcessError{Msg: "Entity cannot be null."} 22 | } 23 | entityEventImpl.Entity = entity 24 | return entityEventImpl, err 25 | } 26 | -------------------------------------------------------------------------------- /event/impl/activitiEventImpl.go: -------------------------------------------------------------------------------- 1 | package impl 2 | 3 | import . "github.com/lios/go-activiti/event" 4 | 5 | type ActivitiEventImpl struct { 6 | EventType ActivitiEventType 7 | ExecutionId string 8 | ProcessInstanceId string 9 | ProcessDefinitionId string 10 | } 11 | 12 | func (activitiEvent ActivitiEventImpl) GetType() ActivitiEventType { 13 | return activitiEvent.EventType 14 | } 15 | 16 | func (activitiEvent ActivitiEventImpl) SetType(eventType ActivitiEventType) { 17 | activitiEvent.EventType = eventType 18 | } 19 | func (activitiEvent ActivitiEventImpl) GetProcessDefinitionId() string { 20 | return activitiEvent.ProcessDefinitionId 21 | } 22 | 23 | func (activitiEvent ActivitiEventImpl) SetProcessDefinitionId(processDefinitionId string) { 24 | activitiEvent.ProcessDefinitionId = processDefinitionId 25 | } 26 | 27 | func (activitiEvent ActivitiEventImpl) GetProcessInstanceId() string { 28 | return activitiEvent.ProcessInstanceId 29 | } 30 | 31 | func (activitiEvent ActivitiEventImpl) SetProcessInstanceId(processInstanceId string) { 32 | activitiEvent.ProcessInstanceId = processInstanceId 33 | } 34 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/lios/go-activiti 2 | 3 | go 1.12 4 | 5 | require ( 6 | github.com/Unknwon/goconfig v0.0.0-20190425194916-3dba17dd7b9e // 7 | github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect 8 | github.com/go-sql-driver/mysql v1.5.0 9 | github.com/heartlhj/go-expression v0.1.2-fix 10 | github.com/jinzhu/gorm v1.9.15 11 | github.com/julienschmidt/httprouter v1.3.0 12 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 13 | github.com/pborman/uuid v1.2.0 14 | github.com/prometheus/common v0.13.0 15 | ) 16 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/julienschmidt/httprouter" 5 | . "github.com/lios/go-activiti/web" 6 | 7 | "log" 8 | "net/http" 9 | ) 10 | 11 | func RegisterHandler() *httprouter.Router { 12 | router := httprouter.New() 13 | router.GET("/", Index) 14 | router.POST("/import", Create) 15 | return router 16 | } 17 | 18 | func main() { 19 | r := RegisterHandler() 20 | log.Println("StartIng Http.....") 21 | http.ListenAndServe(":8080", r) 22 | } 23 | -------------------------------------------------------------------------------- /model/bytearry.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | //流程源数据 4 | type Bytearry struct { 5 | Id int64 `gorm:"column:id"` 6 | Key string `gorm:"column:key"` 7 | Name string `gorm:"column:name"` 8 | Version int `gorm:"column:version"` 9 | Bytes string `gorm:"column:bytes"` 10 | DeploymentId int64 `gorm:"column:deployment_id"` 11 | } 12 | 13 | func (Bytearry) TableName() string { 14 | return "bytearry" 15 | } 16 | -------------------------------------------------------------------------------- /model/deployment.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import "time" 4 | 5 | //部署 6 | type Deployment struct { 7 | Id int64 `gorm:"column:id"` 8 | Key string `gorm:"column:key"` 9 | Name string `gorm:"column:name"` 10 | Version int `gorm:"column:version"` 11 | TenantId string `gorm:"column:tenant_id"` 12 | DeployTime time.Time `gorm:"column:deploy_time"` 13 | } 14 | 15 | func (Deployment) TableName() string { 16 | return "deployment" 17 | } 18 | -------------------------------------------------------------------------------- /model/historicActinst.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | //流程实例 8 | type HistoricActinst struct { 9 | Id int64 10 | ProcessDefineId int64 `gorm:"column:process_define_id"` 11 | ProcessInstanceId int64 `gorm:"column:proc_inst_id"` 12 | TaskId int64 `gorm:"column:task_id"` 13 | ActId string `gorm:"column:act_id"` 14 | ActName string `gorm:"column:act_name"` 15 | ActType string `gorm:"column:act_type"` 16 | TenantId string `gorm:"column:tenant_id"` 17 | StartTime time.Time `gorm:"column:start_time"` 18 | EndTime time.Time `gorm:"column:end_time","default: null"` 19 | StartUserId string `gorm:"column:start_user_id"` 20 | Assignee string `gorm:"column:assignee"` 21 | } 22 | 23 | func (HistoricActinst) TableName() string { 24 | return "hi_actinst" 25 | } 26 | -------------------------------------------------------------------------------- /model/historicIdentityLink.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type HistoricIdentityLink struct { 4 | Id int64 5 | Type string `gorm:"column:type"` 6 | TaskId int64 `gorm:"column:task_id"` 7 | ProcessInstanceId int64 `gorm:"column:proc_inst_id"` 8 | GroupId string `gorm:"column:group_id"` 9 | UserId string `gorm:"column:user_id"` 10 | } 11 | 12 | func (HistoricIdentityLink) TableName() string { 13 | return "hi_identity_link" 14 | } 15 | -------------------------------------------------------------------------------- /model/historicProcinst.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | //流程实例 8 | type HistoricProcess struct { 9 | Id int64 10 | ProcessInstanceId int64 `gorm:"column:proc_inst_id"` 11 | Key string `gorm:"column:key"` 12 | Name string `gorm:"column:name"` 13 | BusinessKey string `gorm:"column:business_key"` 14 | TenantId string `gorm:"column:tenant_id"` 15 | DeploymentId int64 `gorm:"column:deployment_id"` 16 | StartTime time.Time `gorm:"column:start_time"` 17 | EndTime time.Time `gorm:"column:end_time","default: null"` 18 | StartUserId string `gorm:"column:start_user_id"` 19 | ProcessDefineId int64 `gorm:"column:process_define_id"` 20 | } 21 | 22 | func (HistoricProcess) TableName() string { 23 | return "hi_process_instance" 24 | } 25 | -------------------------------------------------------------------------------- /model/historicTask.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | type HistoricTask struct { 8 | Id int64 9 | TaskId int64 `gorm:"column:task_id"` 10 | TaskDefineKey string `gorm:"column:task_define_key"` 11 | TaskDefineName string `gorm:"column:task_define_name"` 12 | TenantId string `gorm:"column:tenant_id"` 13 | DeploymentId int `gorm:"column:deployment_id"` 14 | StartTime time.Time `gorm:"column:start_time"` 15 | EndTime time.Time `gorm:"column:end_time","default: null"` 16 | Assignee string `gorm:"column:assignee"` 17 | ProcessInstanceId int64 `gorm:"column:proc_inst_id"` 18 | } 19 | 20 | func (HistoricTask) TableName() string { 21 | return "hi_task" 22 | } 23 | -------------------------------------------------------------------------------- /model/identityLink.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type IdentityLink struct { 4 | Id int64 5 | Type string `gorm:"column:type"` 6 | TaskId int64 `gorm:"column:task_id"` 7 | ProcessInstanceId int64 `gorm:"column:proc_inst_id"` 8 | GroupId string `gorm:"column:group_id"` 9 | UserId string `gorm:"column:user_id"` 10 | } 11 | 12 | func (IdentityLink) TableName() string { 13 | return "identity_link" 14 | } 15 | -------------------------------------------------------------------------------- /model/procinst.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | //流程实例 8 | type ProcessInstance struct { 9 | Id int64 10 | Key string `gorm:"column:key"` 11 | Name string `gorm:"column:name"` 12 | BusinessKey string `gorm:"column:business_key"` 13 | TenantId string `gorm:"column:tenant_id"` 14 | DeploymentId int64 `gorm:"column:deployment_id"` 15 | StartTime time.Time `gorm:"column:start_time"` 16 | StartUserId string `gorm:"column:start_user_id"` 17 | ProcessDefineId int64 `gorm:"column:process_define_id"` 18 | } 19 | 20 | func (ProcessInstance) TableName() string { 21 | return "process_instance" 22 | } 23 | 24 | func (processInstance ProcessInstance) setBusinessKey(businessKey string) { 25 | processInstance.BusinessKey = businessKey 26 | } 27 | -------------------------------------------------------------------------------- /model/task.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | type Task struct { 8 | Id int64 9 | TaskDefineKey string `gorm:"column:task_define_key"` 10 | TaskDefineName string `gorm:"column:task_define_name"` 11 | TenantId string `gorm:"column:tenant_id"` 12 | DeploymentId int `gorm:"column:deployment_id"` 13 | StartTime time.Time `gorm:"column:start_time"` 14 | Assignee string `gorm:"column:assignee"` 15 | ProcessInstanceId int64 `gorm:"column:proc_inst_id"` 16 | } 17 | 18 | func (Task) TableName() string { 19 | return "task" 20 | } 21 | -------------------------------------------------------------------------------- /resources/process_demo.bpmn20.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | process_demo 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /resources/userAuto.bpmn20.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | =19}]]> 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /resources/userTest.bpmn20.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | =19}]]> 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /runtime/runtime.go: -------------------------------------------------------------------------------- 1 | package runtime 2 | 3 | import ( 4 | "bytes" 5 | "runtime" 6 | ) 7 | 8 | func GoroutineId() string { 9 | buf := make([]byte, 30) 10 | buf = buf[:runtime.Stack(buf, false)] 11 | return string(bytes.Split(buf, []byte(" "))[1]) 12 | } 13 | -------------------------------------------------------------------------------- /templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 |

{{.Name}}

6 |
7 | 8 |
9 |

Welcome to learning go

10 |
11 |
13 |
14 |

Import File

15 |
16 | 17 |
18 | 19 |
20 |
21 | 22 |
23 |
24 | 25 |
27 |
28 |

查询

29 |
30 | 31 |
32 | 33 |
34 |
35 | 36 | -------------------------------------------------------------------------------- /test/process_test.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "fmt" 5 | "github.com/lios/go-activiti/engine/behavior" 6 | _ "github.com/lios/go-activiti/engine/handler" 7 | peocess "github.com/lios/go-activiti/engine/service" 8 | "github.com/lios/go-activiti/event" 9 | "github.com/lios/go-activiti/runtime" 10 | "io/ioutil" 11 | "os" 12 | "testing" 13 | ) 14 | 15 | const ( 16 | key = "process_demo" 17 | userKey = "userTest" 18 | userAutoKey = "userAuto" 19 | file_path = "F:\\Work\\go-activiti\\resources\\userAuto.bpmn20.xml" 20 | ) 21 | 22 | type ActivitiListener struct { 23 | name string 24 | } 25 | 26 | func (act ActivitiListener) OnEvent(event event.ActivitiEvent) error { 27 | fmt.Println(event) 28 | return nil 29 | } 30 | 31 | //测试部署流程 32 | func TestDeployMentProcss(t *testing.T) { 33 | f, err := os.Open(file_path) 34 | if err == nil { 35 | bytes, err := ioutil.ReadAll(f) 36 | if err == nil { 37 | repository := peocess.RepositoryService{} 38 | repository.Deploy(userAutoKey, userAutoKey, bytes) 39 | } 40 | } 41 | 42 | } 43 | 44 | //测试解析BPMN 45 | func TestConverterBpmn(t *testing.T) { 46 | f, err := os.Open(file_path) 47 | if err == nil { 48 | bytes, err := ioutil.ReadAll(f) 49 | if err == nil { 50 | process := behavior.Converter(bytes) 51 | fmt.Println(process) 52 | } 53 | } 54 | 55 | } 56 | 57 | //测试发起流程 58 | func TestStartProcss(t *testing.T) { 59 | variables := make(map[string]interface{}, 0) 60 | variables["name"] = "lisi" 61 | variables["age"] = 18 62 | variables["isOld"] = true 63 | runtime := peocess.RuntimeService{} 64 | runtime.StartProcessInstanceByKey(userKey, variables, "", "") 65 | } 66 | 67 | //测试发起流程 68 | func TestStartAutoProcss(t *testing.T) { 69 | variables := make(map[string]interface{}, 0) 70 | variables["name"] = "lisi" 71 | variables["age"] = 18 72 | variables["isOld"] = true 73 | runtime := peocess.RuntimeService{} 74 | runtime.StartProcessInstanceByKey(userAutoKey, variables, "", "") 75 | } 76 | 77 | //测试查询代办 78 | func TestQueryUndoTask(t *testing.T) { 79 | taskService := peocess.TaskService{} 80 | variables := make(map[string]interface{}, 0) 81 | variables["code"] = "0001" 82 | taskEntities, _ := taskService.QueryUndoTask("lisi", "") 83 | fmt.Println(taskEntities) 84 | } 85 | 86 | //测试完成任务 87 | func TestComplete(t *testing.T) { 88 | taskService := peocess.TaskService{} 89 | variables := make(map[string]interface{}, 0) 90 | variables["code"] = "0001" 91 | taskService.Complete(38, variables, true) 92 | } 93 | 94 | //测试驳回 95 | func TestBackTask(t *testing.T) { 96 | taskService := peocess.TaskService{} 97 | variables := make(map[string]interface{}, 0) 98 | variables["code"] = "0001" 99 | taskService.BackTask(26, "sid-4D05C44F-097D-4182-AD76-F4CC40F0F5F5") 100 | } 101 | 102 | //测试获取协程ID 103 | func TestRuntime(t *testing.T) { 104 | id := runtime.GoroutineId() 105 | fmt.Println(id) 106 | } 107 | 108 | //测试监听器 109 | func TestListener(t *testing.T) { 110 | configuration := behavior.GetProcessEngineConfiguration() 111 | eventListeners := make([]event.ActivitiEventListener, 0) 112 | eventListeners = append(eventListeners, ActivitiListener{}) 113 | configuration.AddEventListeners(eventListeners) 114 | taskService := peocess.TaskService{} 115 | taskService.Complete(7, nil, true) 116 | } 117 | -------------------------------------------------------------------------------- /web/handlers.go: -------------------------------------------------------------------------------- 1 | package web 2 | 3 | import ( 4 | "encoding/xml" 5 | "fmt" 6 | "github.com/julienschmidt/httprouter" 7 | "github.com/lios/go-activiti/engine" 8 | "github.com/lios/go-activiti/engine/behavior" 9 | "github.com/lios/go-activiti/model" 10 | "html/template" 11 | "io/ioutil" 12 | "log" 13 | "net/http" 14 | ) 15 | 16 | const ( 17 | MAX_UPLOAD_SIZE = 50 * 1024 * 1024 // 文件大小 50MB 18 | ) 19 | 20 | func Index(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { 21 | t, e := template.ParseFiles("workflow\\templates\\index.html") 22 | if e != nil { 23 | log.Printf("Parsing template index.htmlerror: %s", e) 24 | return 25 | } 26 | var bytearry = &model.Bytearry{Name: "你好"} 27 | t.Execute(w, bytearry) 28 | return 29 | 30 | } 31 | 32 | func Create(w http.ResponseWriter, r *http.Request, p httprouter.Params) { 33 | r.Body = http.MaxBytesReader(w, r.Body, MAX_UPLOAD_SIZE) 34 | if err := r.ParseMultipartForm(MAX_UPLOAD_SIZE); err != nil { 35 | sendErrorResponse(w, http.StatusBadRequest, "File is too big") 36 | return 37 | } 38 | 39 | file, _, err := r.FormFile("file") 40 | name := r.Form.Get("name") 41 | if err != nil { 42 | sendErrorResponse(w, http.StatusInternalServerError, "Internal Error") 43 | return 44 | } 45 | body, err := ioutil.ReadAll(file) 46 | //解析xml数据 47 | data := new(engine.Definitions) 48 | err = xml.Unmarshal(body, &data) 49 | dataStr, err := xml.MarshalIndent(data, "", " ") 50 | converter := behavior.Converter(body) 51 | defineManager := behavior.GetDefineManager() 52 | defineManager.CreateByteArry(converter.Name, converter.Id, string(body)) 53 | fmt.Println(converter.Id) 54 | //导出xml文件 55 | headerBytes := []byte(xml.Header) //加入XML头 56 | xmlOutPutData := append(headerBytes, dataStr...) //拼接XML头和实际XML内容 57 | 58 | //设置Content-Type 59 | w.Header().Add("Content-Type", "application/octet-stream") 60 | w.Header().Add("Content-Disposition", "attachment; filename=\""+name+"\".bpmn20.xml") 61 | 62 | sendNormalResponse(w, string(xmlOutPutData), 201) 63 | } 64 | -------------------------------------------------------------------------------- /web/response.go: -------------------------------------------------------------------------------- 1 | package web 2 | 3 | import ( 4 | "io" 5 | "net/http" 6 | ) 7 | 8 | func sendErrorResponse(w http.ResponseWriter, sc int, errMsg string) { 9 | w.WriteHeader(sc) 10 | io.WriteString(w, errMsg) 11 | } 12 | 13 | func sendNormalResponse(w http.ResponseWriter, resp string, sc int) { 14 | w.WriteHeader(sc) 15 | io.WriteString(w, resp) 16 | } 17 | --------------------------------------------------------------------------------