/**
* Copyright 1996-2014 FoxBPM ORG.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @author kenshin
*/
package org.foxbpm.engine.impl.entity;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.foxbpm.engine.datavariable.VariableQuery;
import org.foxbpm.engine.db.HasRevision;
import org.foxbpm.engine.db.PersistentObject;
import org.foxbpm.engine.impl.Context;
import org.foxbpm.engine.impl.datavariable.VariableQueryImpl;
import org.foxbpm.engine.impl.expression.ExpressionMgmt;
import org.foxbpm.engine.impl.mgmt.DataVariableMgmtInstance;
import org.foxbpm.engine.impl.runtime.ContextInstanceImpl;
import org.foxbpm.engine.impl.util.ClockUtil;
import org.foxbpm.engine.impl.util.ExceptionUtil;
import org.foxbpm.engine.impl.util.GuidUtil;
import org.foxbpm.engine.impl.util.StringUtil;
import org.foxbpm.engine.runtime.ContextInstance;
import org.foxbpm.engine.runtime.ProcessInstance;
import org.foxbpm.kernel.process.impl.KernelFlowNodeImpl;
import org.foxbpm.kernel.process.impl.KernelProcessDefinitionImpl;
import org.foxbpm.kernel.runtime.KernelProcessInstance;
import org.foxbpm.kernel.runtime.ProcessInstanceStatus;
import org.foxbpm.kernel.runtime.impl.KernelProcessInstanceImpl;
import org.foxbpm.kernel.runtime.impl.KernelTokenImpl;
/**
* 流程实例实体
*
* @author kenshin
*
*/
public class ProcessInstanceEntity extends KernelProcessInstanceImpl implements ProcessInstance, PersistentObject,
HasRevision {
private static final long serialVersionUID = 1L;
/** 流程定义唯一版本编号 */
protected String processDefinitionId;
/** 流程定义编号 */
protected String processDefinitionKey;
/** 交互式流程文件定义号 */
protected String definitionId;
/** 根令牌编号 */
protected String rootTokenId;
/** 父流程实例用来启动子流程实例的令牌编号 */
protected String parentTokenId;
/** 父流程实例编号 */
protected String parentId;
/** 实例主题 */
protected String subject;
/** 流程实例的启动人 */
protected String startAuthor;
/** 流程任务的发起人 */
protected String initiator;
/** 业务关联键 */
protected String bizKey;
/** 流程实例启动时间 */
protected Date startTime;
/** 流程实例结束时间 */
protected Date endTime;
/** 流程实例最近一次操作时间 */
protected Date updateTime;
/** 流程实例归档时间 */
protected Date archiveTime;
/** 流程实例位置 */
protected String processLocation;
// 对象字段 /////////////////////
/** 任务集合 */
protected List<TaskEntity> tasks;
/** 任务身份集合 */
protected List<IdentityLinkEntity> identityLinks;
/** 变量管理器 */
protected DataVariableMgmtInstance dataVariableMgmtInstance;
/** 实例内容管理器 */
protected ContextInstance contextInstance;
/** 控制并发修改标示 */
protected int revision;
/**
* 是否需要重新计算流程位置
*/
protected boolean isLocationChange;
public boolean isModified() {
return true;
}
/** 构造函数 */
public ProcessInstanceEntity() {
this(null);
}
// Constructor 构造函数
// /////////////////////////////////////////////////////
public ProcessInstanceEntity(KernelFlowNodeImpl startFlowNode) {
super(startFlowNode);
// 设置流程实例的编号,通过静态方法获得Guid
this.id = GuidUtil.CreateGuid();
this.dataVariableMgmtInstance = new DataVariableMgmtInstance(this);
this.contextInstance = new ContextInstanceImpl();
}
public void start() {
if(getRootToken().getFlowNode() != null){
throw ExceptionUtil.getException("10303004",getId());
}
this.instanceStatus = ProcessInstanceStatus.RUNNING;
this.setStartTime(ClockUtil.getCurrentTime());
ProcessDefinitionEntity processDefinitionEntity = (ProcessDefinitionEntity) getProcessDefinition();
if (processDefinitionEntity.getSubject() != null) {
try{
this.setSubject(StringUtil.getString(processDefinitionEntity.getSubject().getValue(getRootToken())));
}catch(Exception ex){
throw ExceptionUtil.getException("10304001",processDefinitionEntity.getId());
}
}
super.start();
}
public KernelTokenImpl createRootToken() {
super.createRootToken();
this.rootTokenId = this.rootToken.getId();
return this.rootToken;
}
public KernelTokenImpl createToken() {
TokenEntity tokenObj = new TokenEntity();
String tokenObjId = GuidUtil.CreateGuid();
tokenObj.setId(tokenObjId);
tokenObj.setStartTime(ClockUtil.getCurrentTime());
tokenObj.setProcessInstance(this);
addToken(tokenObj);
Context.getCommandContext().getTokenManager().insert(tokenObj);
return tokenObj;
}
public void initialize() {
super.initialize();
this.tasks = new ArrayList<TaskEntity>();
}
@SuppressWarnings({"unchecked", "rawtypes"})
protected void ensureTasksInitialized() {
//流程第一次启动时,不需要从数据库查询
if (tasks == null) {
if(revision == 0){
tasks = new ArrayList<TaskEntity>();
}
else{
tasks = (List) Context.getCommandContext().getTaskManager().findTasksByProcessInstanceId(id);
}
}
}
protected List<TaskEntity> getTasksInternal() {
ensureTasksInitialized();
return tasks;
}
public List<TaskEntity> getTasks() {
return new ArrayList<TaskEntity>(getTasksInternal());
}
public void addTask(TaskEntity taskEntity) {
getTasksInternal().add(taskEntity);
}
public void removeTask(TaskEntity task) {
getTasksInternal().remove(task);
}
public void ensureParentProcessInstanceTokenInitialized() {
if (parentProcessInstanceToken == null && parentTokenId != null) {
TokenEntity token = Context.getCommandContext().getTokenManager().findTokenById(parentTokenId);
setParentProcessInstanceToken(token);
}
}
public KernelProcessInstance createSubProcessInstance(KernelProcessDefinitionImpl processDefinition,
KernelTokenImpl token) {
ProcessInstanceEntity createSubProcessInstance = (ProcessInstanceEntity) super.createSubProcessInstance(processDefinition, token);
// 创建流程实例,并持久化。
Context.getCommandContext().getProcessInstanceManager().insert(createSubProcessInstance);
return createSubProcessInstance;
}
protected void ensureParentProcessInstanceInitialized() {
if (parentProcessInstance == null && parentId != null) {
ProcessInstanceEntity parentProcessInstance = Context.getCommandContext().getProcessInstanceManager().findProcessInstanceById(parentId);
setParentProcessInstance(parentProcessInstance);
}
}
public void ensureRootTokenInitialized() {
if (rootToken == null && rootTokenId != null) {
TokenEntity token = Context.getCommandContext().getTokenManager().findTokenById(rootTokenId);
setRootToken(token);
}
}
public void ensureProcessDefinitionInitialized() {
if ((processDefinition == null) && (processDefinitionId != null)) {
ProcessDefinitionEntity deployedProcessDefinition = Context.getProcessEngineConfiguration().getDeploymentManager().findDeployedProcessDefinitionById(processDefinitionId);
setProcessDefinition(deployedProcessDefinition);
}
}
@SuppressWarnings({"unchecked", "rawtypes"})
protected void ensureTokensInitialized() {
//如果跟令牌不存在,则不需要初始化
if(rootTokenId == null){
this.tokens = new ArrayList<KernelTokenImpl>();
}else if (tokens == null) {
this.tokens = (List) Context.getCommandContext().getTokenManager().findTokensByProcessInstanceId(id);
}
}
public void setParentProcessInstance(KernelProcessInstanceImpl parentProcessInstance) {
ProcessInstanceEntity processInstanceEntity = ((ProcessInstanceEntity) parentProcessInstance);
this.parentProcessInstance = processInstanceEntity;
this.parentId = processInstanceEntity.getId();
}
public void setParentProcessInstanceToken(KernelTokenImpl parentProcessInstanceToken) {
this.parentProcessInstanceToken = parentProcessInstanceToken;
this.parentTokenId = parentProcessInstanceToken.getId();
}
public void setRootToken(KernelTokenImpl rootToken) {
this.rootTokenId = rootToken.getId();
super.setRootToken(rootToken);
}
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public String getProcessDefinitionId() {
return processDefinitionId;
}
public void setProcessDefinitionId(String processDefinitionId) {
this.processDefinitionId = processDefinitionId;
}
public String getProcessDefinitionKey() {
return processDefinitionKey;
}
public void setProcessDefinitionKey(String processDefinitionKey) {
this.processDefinitionKey = processDefinitionKey;
}
public String getDefinitionId() {
return definitionId;
}
public void setDefinitionId(String definitionId) {
this.definitionId = definitionId;
}
public String getRootTokenId() {
return rootTokenId;
}
public void setRootTokenId(String rootTokenId) {
this.rootTokenId = rootTokenId;
}
public String getParentTokenId() {
return parentTokenId;
}
public void setParentTokenId(String parentTokenId) {
this.parentTokenId = parentTokenId;
}
public String getParentId() {
return parentId;
}
public void setParentId(String parentId) {
this.parentId = parentId;
}
public String getStartAuthor() {
return startAuthor;
}
public void setStartAuthor(String startAuthor) {
this.startAuthor = startAuthor;
}
public String getInitiator() {
return initiator;
}
public void setInitiator(String initiator) {
this.initiator = initiator;
}
public Date getStartTime() {
return startTime;
}
public void setStartTime(Date startTime) {
this.startTime = startTime;
}
public Date getEndTime() {
return endTime;
}
public void setEndTime(Date endTime) {
this.endTime = endTime;
}
public Date getUpdateTime() {
return updateTime;
}
public void setUpdateTime(Date updateTime) {
this.updateTime = updateTime;
}
public Date getArchiveTime() {
return archiveTime;
}
public void setArchiveTime(Date archiveTime) {
this.archiveTime = archiveTime;
}
public String getProcessLocation() {
return processLocation;
}
public void setProcessLocation(String processLocation) {
this.processLocation = processLocation;
}
public DataVariableMgmtInstance getDataVariableMgmtInstance() {
return dataVariableMgmtInstance;
}
public void setDataVariableMgmtInstance(DataVariableMgmtInstance dataVariableMgmtInstance) {
this.dataVariableMgmtInstance = dataVariableMgmtInstance;
}
public void setProcessDefinition(KernelProcessDefinitionImpl processDefinition) {
this.processDefinition = processDefinition;
this.processDefinitionId = processDefinition.getId();
this.processDefinitionKey = processDefinition.getKey();
}
public String getBizKey() {
return bizKey;
}
public void setBizKey(String bizKey) {
this.bizKey = bizKey;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public void setRevision(int revision) {
this.revision = revision;
}
public int getRevision() {
return revision;
}
public int getRevisionNext() {
return revision + 1;
}
public Map<String, Object> getPersistentState() {
Map<String, Object> mapPersistentState = new HashMap<String, Object>();
mapPersistentState.put("id", id);
mapPersistentState.put("subject", subject);
mapPersistentState.put("processDefinitionKey", processDefinitionKey);
mapPersistentState.put("processDefinitionId", processDefinitionId);
mapPersistentState.put("rootTokenId", rootTokenId);
mapPersistentState.put("definitionId", definitionId);
mapPersistentState.put("parentId", parentId);
mapPersistentState.put("parentTokenId", parentTokenId);
mapPersistentState.put("initiator", initiator);
mapPersistentState.put("startAuthor", startAuthor);
mapPersistentState.put("bizKey", bizKey);
mapPersistentState.put("startTime", startTime);
mapPersistentState.put("endTime", endTime);
mapPersistentState.put("updateTime", updateTime);
mapPersistentState.put("archiveTime", archiveTime);
mapPersistentState.put("isSuspended", isSuspended);
mapPersistentState.put("processLocation", processLocation);
mapPersistentState.put("instanceStatus", instanceStatus);
return mapPersistentState;
}
public void setVariables(Map<String, Object> variables) {
if (variables == null) {
return;
}
for (String mapKey : variables.keySet()) {
VariableQuery variableQuery = new VariableQueryImpl(Context.getProcessEngineConfiguration().getCommandExecutor());
variableQuery.addVariableKey(mapKey);
variableQuery.processInstanceId(this.id);
@SuppressWarnings({"unchecked", "rawtypes"})
List<VariableInstanceEntity> variableInstances = (List) variableQuery.list();
if (variableInstances != null && variableInstances.size() == 1) {
// 更新
Context.getCommandContext().getVariableManager().update(variableInstances.get(0));
dataVariableMgmtInstance.getDataVariableEntities().add(variableInstances.get(0));
} else {
VariableInstanceEntity variableInstanceEntity = addVariableToMgmt(mapKey, variables.get(mapKey));
Context.getCommandContext().getVariableManager().insert(variableInstanceEntity);
}
ExpressionMgmt.setVariable(mapKey, variables.get(mapKey));
}
}
public void setTransVariables(Map<String, Object> transientVariables) {
if (transientVariables == null) {
return;
}
for (String mapKey : transientVariables.keySet()) {
addVariableToMgmt(mapKey, transientVariables.get(mapKey));
ExpressionMgmt.setVariable(mapKey, transientVariables.get(mapKey));
}
}
private VariableInstanceEntity addVariableToMgmt(String key, Object value) {
VariableInstanceEntity variableInstanceEntity = new VariableInstanceEntity();
variableInstanceEntity.setKey(key);
variableInstanceEntity.setValue(value);
variableInstanceEntity.setProcessInstanceId(this.id);
variableInstanceEntity.setProcessDefinitionId(processDefinitionId);
variableInstanceEntity.setProcessDefinitionKey(processDefinitionKey);
variableInstanceEntity.setId(GuidUtil.CreateGuid());
dataVariableMgmtInstance.getDataVariableEntities().add(variableInstanceEntity);
return variableInstanceEntity;
}
public boolean isEnd() {
return endTime != null;
}
public void end() {
endTime = ClockUtil.getCurrentTime();
super.end();
}
public void abort() {
endTime = ClockUtil.getCurrentTime();
super.abort();
}
public String getProcessDefinitionName() {
ensureProcessDefinitionInitialized();
if (processDefinition != null) {
return processDefinition.getName();
}
return null;
}
protected KernelProcessInstanceImpl newProcessInstance() {
return new ProcessInstanceEntity();
}
@Override
public void suspendInstance() {
for(TaskEntity tmpTask : getTasks()){
tmpTask.setSuspended(true);
}
super.suspendInstance();
}
@Override
public void continueInstance() {
for(TaskEntity tmpTask : getTasks()){
tmpTask.setSuspended(false);
}
super.continueInstance();
}
public void setLocationChange(boolean isLocationChange) {
this.isLocationChange = isLocationChange;
}
public boolean isLocationChange() {
return isLocationChange;
}
}