/** * Copyright 2007-2010 非也 * All rights reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation。 * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see http://www.gnu.org/licenses. * */ package org.fireflow.pdl.fpdl.behavior; import java.util.Date; import java.util.List; import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.fireflow.client.WorkflowSession; import org.fireflow.client.impl.WorkflowSessionLocalImpl; import org.fireflow.engine.context.RuntimeContext; import org.fireflow.engine.entity.runtime.ActivityInstance; import org.fireflow.engine.entity.runtime.ProcessInstance; import org.fireflow.engine.entity.runtime.ScheduleJob; import org.fireflow.engine.entity.runtime.ScheduleJobState; import org.fireflow.engine.entity.runtime.impl.ScheduleJobImpl; import org.fireflow.engine.exception.EngineException; import org.fireflow.engine.invocation.TimerOperationName; import org.fireflow.engine.modules.beanfactory.BeanFactory; import org.fireflow.engine.modules.calendar.CalendarService; import org.fireflow.engine.modules.persistence.ActivityInstancePersister; import org.fireflow.engine.modules.persistence.PersistenceService; import org.fireflow.engine.modules.persistence.ProcessInstancePersister; import org.fireflow.engine.modules.persistence.ScheduleJobPersister; import org.fireflow.engine.modules.schedule.Scheduler; import org.fireflow.engine.modules.script.ScriptEngineHelper; import org.fireflow.model.ModelElement; import org.fireflow.model.data.Expression; import org.fireflow.pdl.fpdl.behavior.router.SplitEvaluator; import org.fireflow.pdl.fpdl.behavior.router.impl.OrSplitEvaluator; import org.fireflow.pdl.fpdl.misc.FpdlConstants; import org.fireflow.pdl.fpdl.process.Node; import org.fireflow.pdl.fpdl.process.StartNode; import org.fireflow.pdl.fpdl.process.SubProcess; import org.fireflow.pdl.fpdl.process.Synchronizer; import org.fireflow.pdl.fpdl.process.features.Feature; import org.fireflow.pdl.fpdl.process.features.startnode.CatchCompensationFeature; import org.fireflow.pdl.fpdl.process.features.startnode.CatchFaultFeature; import org.fireflow.pdl.fpdl.process.features.startnode.NormalStartFeature; import org.fireflow.pdl.fpdl.process.features.startnode.TimerStartFeature; import org.fireflow.pvm.kernel.PObjectKey; import org.fireflow.pvm.kernel.Token; import org.fireflow.pvm.kernel.TokenState; import org.fireflow.pvm.pdllogic.BusinessStatus; import org.fireflow.pvm.pdllogic.ContinueDirection; import org.fireflow.pvm.pdllogic.ExecuteResult; import org.fireflow.pvm.pdllogic.WorkflowBehavior; /** * @author 非也 * @version 2.0 */ public class StartNodeBehavior extends AbsSynchronizerBehavior implements WorkflowBehavior { private static Log log = LogFactory.getLog(StartNodeBehavior.class); protected List<String> determineNextTransitions( WorkflowSession session, Token token4Node, Node node){ RuntimeContext runtimeContext = ((WorkflowSessionLocalImpl)session).getRuntimeContext(); BeanFactory beanFactory = runtimeContext.getEngineModule(BeanFactory.class, FpdlConstants.PROCESS_TYPE_FPDL20); String className = OrSplitEvaluator.class.getName(); SplitEvaluator splitEvaluator = this.splitEvaluatorRegistry.get(className); if (splitEvaluator==null){ splitEvaluator = (SplitEvaluator)beanFactory.createBean(className); splitEvaluatorRegistry.put(className, splitEvaluator); } return splitEvaluator.determineNextTransitions(session, token4Node, node); } public int canBeFired(WorkflowSession session, Token token,List<Token> liblings, Synchronizer synchronizer){ return token.getStepNumber(); } protected boolean hasAlivePreviousNode(WorkflowSession session, Token token, Node thisNode) { return false; } @Override public ExecuteResult execute(WorkflowSession session, Token token, Object workflowElement) { WorkflowSessionLocalImpl sessionLocalImpl = (WorkflowSessionLocalImpl)session; ActivityInstance activityInstance = sessionLocalImpl .getCurrentActivityInstance(); StartNode startNode = (StartNode) workflowElement; Feature dec = startNode.getFeature(); // 如果是流程入口,则直接执行后续节点 // 流程入口的TimerStartFeature,JmsMessageStartFeature, // WebserviceStartFeature需要通过外部逻辑进行处理,其逻辑不是Startnode.execute(...)的职责 SubProcess process = (SubProcess) startNode.getParent(); Node entry = process.getEntry(); if (entry != null && entry.getId().equals(startNode.getId())) { ExecuteResult result = new ExecuteResult(); result.setStatus(BusinessStatus.COMPLETED); return result; } // 如果是NormalStartFeature 或者 CatchFaultFeature或者CatchCompensationFeature, // 也不需要有执行逻辑,直接运行后续节点 else if (dec == null || dec instanceof NormalStartFeature || dec instanceof CatchFaultFeature || dec instanceof CatchCompensationFeature) { ExecuteResult result = new ExecuteResult(); result.setStatus(BusinessStatus.COMPLETED); return result; } // 只处理Activity边上的TimerStartFeature else if (dec != null && dec instanceof TimerStartFeature) { // 1、检验currentActivityInstance和currentProcessInstance的一致性 ProcessInstance oldProcInst = sessionLocalImpl.getCurrentProcessInstance(); ActivityInstance oldActInst = sessionLocalImpl.getCurrentActivityInstance(); RuntimeContext ctx = ((WorkflowSessionLocalImpl) session) .getRuntimeContext(); PersistenceService persistenceService = ctx.getEngineModule( PersistenceService.class, FpdlConstants.PROCESS_TYPE_FPDL20); ActivityInstancePersister actInstPersistenceService = persistenceService .getActivityInstancePersister(); ProcessInstancePersister processInstancePersister = persistenceService .getProcessInstancePersister(); if (oldProcInst == null || !oldProcInst.getId() .equals(token.getProcessInstanceId())) { ProcessInstance procInst = processInstancePersister.fetch( ProcessInstance.class, token.getProcessInstanceId()); ((WorkflowSessionLocalImpl) session) .setCurrentProcessInstance(procInst); } if (oldActInst == null || !oldActInst.getId().equals(token.getElementInstanceId())) { ActivityInstance actInst = actInstPersistenceService.fetch( ActivityInstance.class, token.getElementInstanceId()); ((WorkflowSessionLocalImpl) session) .setCurrentActivityInstance(actInst); } try { // 2、执行业务逻辑 TimerStartFeature timerDecorator = (TimerStartFeature) dec; createScheduleJob(session, activityInstance, timerDecorator); ExecuteResult result = new ExecuteResult(); result.setStatus(BusinessStatus.RUNNING); return result; } finally { ((WorkflowSessionLocalImpl) session) .setCurrentProcessInstance(oldProcInst); ((WorkflowSessionLocalImpl) session) .setCurrentActivityInstance(oldActInst); } } else { // 其他情况一律不进行处理,直接执行后续节点 ExecuteResult result = new ExecuteResult(); result.setStatus(BusinessStatus.COMPLETED); return result; } } private void createScheduleJob(WorkflowSession session, ActivityInstance activityInstance, TimerStartFeature timerDecorator) { RuntimeContext runtimeContext = ((WorkflowSessionLocalImpl) session) .getRuntimeContext(); CalendarService calendarService = runtimeContext.getEngineModule( CalendarService.class, activityInstance.getProcessType()); WorkflowSessionLocalImpl sessionLocalImpl = (WorkflowSessionLocalImpl)session; ProcessInstance processInstance = sessionLocalImpl.getCurrentProcessInstance(); String operationName = timerDecorator.getTimerOperationName().name(); String triggerType = null; String triggerExpression = null; // TODO 注册ScheduleJob if (TimerOperationName.TRIGGERED_ONLY_ONCE.name().equalsIgnoreCase( operationName.trim())) { triggerType = ScheduleJob.STARTTIME_REPEATCOUNT_INTERVAL; triggerExpression = triggeredOnlyOnce(session, activityInstance, timerDecorator); } else if (TimerOperationName.TRIGGERED_BY_REPEAT_COUNT.name() .equalsIgnoreCase(operationName.trim())) { triggerType = ScheduleJob.STARTTIME_REPEATCOUNT_INTERVAL; triggerExpression = triggeredByRepeatCount(session, activityInstance, timerDecorator); } else if (TimerOperationName.TRIGGERED_BY_STARTTIME_ENDTIME.name() .equalsIgnoreCase(operationName.trim())) { triggerType = ScheduleJob.STARTTIME_ENDTIME_INTERVAL; triggerExpression = triggerdByStarttimeEndtime(session, activityInstance, timerDecorator); } else if (TimerOperationName.TRIGGERED_BY_CRON.name() .equalsIgnoreCase(operationName.trim())) { triggerType = ScheduleJob.CRON; triggerExpression = triggeredByCron(session, activityInstance, timerDecorator); } else { log.error("Unsupported timer operation '" + operationName + "'."); throw new EngineException(activityInstance, "Unsupported timer operation '" + operationName + "'."); } ScheduleJobImpl scheduleJob = new ScheduleJobImpl(); scheduleJob.setName(activityInstance.getName()); scheduleJob.setDisplayName(activityInstance.getDisplayName()); scheduleJob.setState(ScheduleJobState.RUNNING); scheduleJob.setActivityInstanceId(activityInstance.getId()); if (timerDecorator.getAttachedToActivity() == null) {// 如果不是依附在Activity上,则是定时启动的StartNode scheduleJob.setCreateNewProcessInstance(true); } else { scheduleJob.setCreateNewProcessInstance(false); } scheduleJob.setCancelAttachedToActivity(timerDecorator .getCancelAttachedToActivity()); scheduleJob.setProcessId(activityInstance.getProcessId()); scheduleJob.setProcessType(activityInstance.getProcessType()); scheduleJob.setVersion(activityInstance.getVersion()); scheduleJob.setTriggerType(triggerType); scheduleJob.setTriggerExpression(triggerExpression); scheduleJob.setCreatedTime(calendarService.getSysDate()); // 保存 PersistenceService persistenceService = runtimeContext.getEngineModule( PersistenceService.class, activityInstance.getProcessType()); ScheduleJobPersister persister = persistenceService .getScheduleJobPersister(); persister.saveOrUpdate(scheduleJob); // 加入调度器 Scheduler scheduler = runtimeContext.getEngineModule(Scheduler.class, activityInstance.getProcessType()); scheduler.schedule(scheduleJob, runtimeContext); } private String triggeredOnlyOnce(WorkflowSession session, ActivityInstance activityInstance, TimerStartFeature timerDecorator) throws EngineException { RuntimeContext runtimeContext = ((WorkflowSessionLocalImpl) session) .getRuntimeContext(); WorkflowSessionLocalImpl sessionLocalImpl = (WorkflowSessionLocalImpl)session; ProcessInstance processInstance = sessionLocalImpl.getCurrentProcessInstance(); Expression theStartTimeExpression = timerDecorator .getStartTimeExpression(); Expression theRepeatCountExpression = null; Expression theRepeatIntervalExpression = null; if (theStartTimeExpression == null || theStartTimeExpression.getBody() == null || theStartTimeExpression.getBody().trim().equals("")) { log.error("The start time expression is null"); throw new EngineException(activityInstance, "The start time expression is null"); } Map<String, Object> varContext = ScriptEngineHelper .fulfillScriptContext(session, runtimeContext, processInstance, activityInstance); Date startTime = null; Integer repeatCount = 0; Integer repeatInterval = 0; startTime = (Date) ScriptEngineHelper.evaluateExpression( runtimeContext, theStartTimeExpression, varContext); StringBuffer buf = new StringBuffer(); buf.append(startTime.getTime()).append("|") .append(repeatCount.toString()).append("|") .append(repeatInterval); return buf.toString(); } private String triggeredByRepeatCount(WorkflowSession session, ActivityInstance activityInstance, TimerStartFeature timerDecorator) throws EngineException { RuntimeContext runtimeContext = ((WorkflowSessionLocalImpl) session) .getRuntimeContext(); WorkflowSessionLocalImpl sessionLocalImpl = (WorkflowSessionLocalImpl)session; ProcessInstance processInstance = sessionLocalImpl.getCurrentProcessInstance(); Expression theStartTimeExpression = timerDecorator .getStartTimeExpression(); Expression theRepeatCountExpression = timerDecorator .getRepeatCountExpression(); Expression theRepeatIntervalExpression = timerDecorator .getRepeatIntervalExpression(); if (theStartTimeExpression == null || theStartTimeExpression.getBody() == null || theStartTimeExpression.getBody().trim().equals("")) { log.error("The start time expression is null"); throw new EngineException(activityInstance, "The start time expression is null"); } Map<String, Object> varContext = ScriptEngineHelper .fulfillScriptContext(session, runtimeContext, processInstance, activityInstance); Date startTime = null; Integer repeatCount = 0; Integer repeatInterval = 0; startTime = (Date) ScriptEngineHelper.evaluateExpression( runtimeContext, theStartTimeExpression, varContext); if (theRepeatCountExpression != null && theRepeatCountExpression.getBody() != null && !theRepeatCountExpression.getBody().trim().equals("")) { repeatCount = (Integer) ScriptEngineHelper.evaluateExpression( runtimeContext, theRepeatCountExpression, varContext); } if (theRepeatIntervalExpression != null && theRepeatIntervalExpression.getBody() != null && !theRepeatIntervalExpression.getBody().trim().equals("")) { repeatInterval = (Integer) ScriptEngineHelper.evaluateExpression( runtimeContext, theRepeatIntervalExpression, varContext); } StringBuffer buf = new StringBuffer(); buf.append(startTime.getTime()).append("|") .append(repeatCount.toString()).append("|") .append(repeatInterval); return buf.toString(); } public String triggerdByStarttimeEndtime(WorkflowSession session, ActivityInstance activityInstance, TimerStartFeature timerDecorator) throws EngineException { RuntimeContext runtimeContext = ((WorkflowSessionLocalImpl) session) .getRuntimeContext(); WorkflowSessionLocalImpl sessionLocalImpl = (WorkflowSessionLocalImpl)session; ProcessInstance processInstance = sessionLocalImpl.getCurrentProcessInstance(); Expression theStartTimeExpression = timerDecorator .getStartTimeExpression(); Expression theEndTimeExpression = timerDecorator.getEndTimeExpression(); Expression theRepeatIntervalExpression = timerDecorator .getRepeatCountExpression(); if (theStartTimeExpression == null || theStartTimeExpression.getBody() == null || theStartTimeExpression.getBody().trim().equals("")) { log.error("The start time expression is null"); throw new EngineException(activityInstance, "The start time expression is null"); } Map<String, Object> varContext = ScriptEngineHelper .fulfillScriptContext(session, runtimeContext, processInstance, activityInstance); Date startTime = null; Date endTime = null; Integer repeatInterval = 0; startTime = (Date) ScriptEngineHelper.evaluateExpression( runtimeContext, theStartTimeExpression, varContext); if (theEndTimeExpression != null && theEndTimeExpression.getBody() != null && !theEndTimeExpression.getBody().trim().equals("")) { endTime = (Date) ScriptEngineHelper.evaluateExpression( runtimeContext, theEndTimeExpression, varContext); } if (theRepeatIntervalExpression != null && theRepeatIntervalExpression.getBody() != null && !theRepeatIntervalExpression.getBody().trim().equals("")) { repeatInterval = (Integer) ScriptEngineHelper.evaluateExpression( runtimeContext, theRepeatIntervalExpression, varContext); } StringBuffer buf = new StringBuffer(); buf.append(startTime.getTime()).append("|") .append(endTime == null ? "null" : endTime.getTime()) .append("|").append(repeatInterval); return buf.toString(); } private String triggeredByCron(WorkflowSession session, ActivityInstance activityInstance, TimerStartFeature timerDecorator) throws EngineException { RuntimeContext runtimeContext = ((WorkflowSessionLocalImpl) session) .getRuntimeContext(); WorkflowSessionLocalImpl sessionLocalImpl = (WorkflowSessionLocalImpl)session; ProcessInstance processInstance = sessionLocalImpl.getCurrentProcessInstance(); Expression theCronExpression = timerDecorator.getCronExpression(); if (theCronExpression == null) { log.error("The cron expression is null!"); throw new EngineException(activityInstance, "The cron expression is null"); } Map<String, Object> varContext = ScriptEngineHelper .fulfillScriptContext(session, runtimeContext, processInstance, activityInstance); try { Object obj = ScriptEngineHelper.evaluateExpression(runtimeContext, theCronExpression, varContext); return (String) obj; } catch (ClassCastException e) { log.error( "The result of the cron expression is not a java String object.", e); throw new EngineException(activityInstance, "The result of the cron expression is not a java String object." + e.getMessage()); } } public ContinueDirection continueOn(WorkflowSession session, Token token, Object workflowElement) { // 启动后续节点,同时 if (token.getState().getValue() != TokenState.RUNNING.getValue()) { return ContinueDirection.closeMe(); } List<PObjectKey> nextPObjectKeys = determineNextPObjectKeys(session, token, workflowElement); ContinueDirection direction = null; // 判断start节点的装饰器类型 StartNode startNode = (StartNode) workflowElement; Feature dec = startNode.getFeature(); // 只处理TimerStartDecorator if (dec == null || !(dec instanceof TimerStartFeature)) { direction = ContinueDirection.closeMe(); direction.setNextProcessObjectKeys(nextPObjectKeys); return direction; } else { // 只有依附在其他Activity上的timer才用ContinueDirection.startNextAndWaitingForClose(); SubProcess subflow = (SubProcess) ((ModelElement) startNode).getParent(); Node entry = subflow.getEntry(); if (entry != null && entry.getId().equals(startNode.getId())) { direction = ContinueDirection.closeMe(); direction.setNextProcessObjectKeys(nextPObjectKeys); return direction; } else { direction = ContinueDirection.startNextAndWaitingForClose(); direction.setNextProcessObjectKeys(nextPObjectKeys); } } return direction; } }