/** * 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.enginemodules; import java.util.ArrayList; import java.util.List; import java.util.StringTokenizer; import org.fireflow.engine.context.AbsEngineModule; import org.fireflow.engine.context.RuntimeContext; import org.fireflow.engine.entity.repository.ProcessKey; import org.fireflow.engine.entity.repository.ProcessRepository; import org.fireflow.engine.exception.WorkflowProcessNotFoundException; import org.fireflow.engine.modules.persistence.PersistenceService; import org.fireflow.engine.modules.persistence.ProcessPersister; import org.fireflow.model.InvalidModelException; import org.fireflow.pdl.fpdl.behavior.ActivityBehavior; import org.fireflow.pdl.fpdl.behavior.EndNodeBehavior; import org.fireflow.pdl.fpdl.behavior.RouterBehavior; import org.fireflow.pdl.fpdl.behavior.SubProcessBehavior; import org.fireflow.pdl.fpdl.misc.FpdlConstants; import org.fireflow.pdl.fpdl.process.Activity; import org.fireflow.pdl.fpdl.process.EndNode; import org.fireflow.pdl.fpdl.process.Router; import org.fireflow.pdl.fpdl.process.StartNode; import org.fireflow.pdl.fpdl.process.SubProcess; import org.fireflow.pdl.fpdl.process.Transition; import org.fireflow.pdl.fpdl.process.WorkflowProcess; 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.pvm.kernel.PObject; import org.fireflow.pvm.kernel.PObjectKey; import org.fireflow.pvm.kernel.impl.ArcInstanceImpl; import org.fireflow.pvm.kernel.impl.NetInstanceImpl; import org.fireflow.pvm.kernel.impl.NodeInstanceImpl; import org.fireflow.pvm.pdllogic.WorkflowBehavior; import org.fireflow.pvm.translate.Process2PObjectTranslator; /** * * @author 非也 * @version 2.0 */ public class Process2PObjectTranslatorFpdl20Impl extends AbsEngineModule implements Process2PObjectTranslator { private WorkflowBehavior transitionBehavior = null; private WorkflowBehavior startNodeBehavior = null; private EndNodeBehavior endNodeBehavior = null; private ActivityBehavior activityBehavior = null; private RouterBehavior routerBehavior = null; private SubProcessBehavior subProcessBehavior = null; // private WorkflowProcessBehavior workflowProcessBehavior = null; public WorkflowBehavior getTransitionBehavior() { return transitionBehavior; } public void setTransitionBehavior(WorkflowBehavior transitionBehavior) { this.transitionBehavior = transitionBehavior; } public WorkflowBehavior getStartNodeBehavior() { return startNodeBehavior; } public void setStartNodeBehavior(WorkflowBehavior startNodeBehavior) { this.startNodeBehavior = startNodeBehavior; } public EndNodeBehavior getEndNodeBehavior() { return endNodeBehavior; } public void setEndNodeBehavior(EndNodeBehavior endNodeBehavior) { this.endNodeBehavior = endNodeBehavior; } public ActivityBehavior getActivityBehavior() { return activityBehavior; } public void setActivityBehavior(ActivityBehavior activityBehavior) { this.activityBehavior = activityBehavior; } public RouterBehavior getRouterBehavior() { return routerBehavior; } public void setRouterBehavior(RouterBehavior routerBehavior) { this.routerBehavior = routerBehavior; } public SubProcessBehavior getSubProcessBehavior() { return subProcessBehavior; } public void setSubProcessBehavior(SubProcessBehavior subProcessBehavior) { this.subProcessBehavior = subProcessBehavior; } /* (non-Javadoc) * @see org.fireflow.pvm.translate.PDL2ProcessObjectTranslator#translatePDL2ProcessObjects(org.fireflow.engine.entity.repository.ProcessRepository) */ public List<PObject> translateProcess(ProcessKey processKey ,Object process) { WorkflowProcess fpdl20Process = (WorkflowProcess)process; List<SubProcess> subflows = fpdl20Process.getLocalSubProcesses(); List<PObject> allPObject = new ArrayList<PObject>(); for (SubProcess subflow:subflows){ List<PObject> pobjectList = translateSubflow(subflow,processKey); if (pobjectList!=null) allPObject.addAll(pobjectList); } return allPObject; } private List<PObject> translateSubflow(SubProcess subflow,ProcessKey processKey){ PObjectKey key = new PObjectKey(processKey.getProcessId(), processKey.getVersion(), processKey.getProcessType(), subflow.getId()); PObject pObject = new NetInstanceImpl(key); pObject.setWorkflowBehavior(subProcessBehavior); pObject.setWorkflowElement(subflow); List<PObject> pobjectList = new ArrayList<PObject>(); pobjectList.add(pObject); ProcessKey pk = ProcessKey.valueOf(key); List<StartNode> startNodes = subflow.getStartNodes(); if (startNodes!=null && startNodes.size()>0){ List<PObject> pos = this.translateStartNodes(startNodes, pk); pobjectList.addAll(pos); } List<Router> routers = subflow.getRouters(); if (routers!=null && routers.size()>0){ List<PObject> pos = this.translateRouters(routers, pk); pobjectList.addAll(pos); } List<EndNode> endNodes = subflow.getEndNodes(); if (endNodes!=null && endNodes.size()>0){ List<PObject> pos = this.translateEndNodes(endNodes, pk); pobjectList.addAll(pos); } List<Activity> activities = subflow.getActivities(); if (activities!=null && activities.size()>0){ List<PObject> pos = this.translateActivities(activities, pk); pobjectList.addAll(pos); } List<Transition> transitions = subflow.getTransitions(); if (transitions!=null && transitions.size()>0){ List<PObject> pos = this.translateTransitions(transitions, pk); pobjectList.addAll(pos); } assemblePObject(subflow,pobjectList,pk); return pobjectList; } private List<PObject> translateStartNodes(List<StartNode> startNodes,ProcessKey pk){ List<PObject> result = new ArrayList<PObject>(); for (StartNode startNode:startNodes){ PObjectKey key = new PObjectKey(pk.getProcessId(), pk.getVersion(), pk .getProcessType(), startNode.getId()); PObject pObject = new NodeInstanceImpl(key); pObject.setCancellable(true); pObject.setCompensable(false); pObject.setWorkflowBehavior(startNodeBehavior); pObject.setWorkflowElement(startNode); result.add(pObject); } return result; } private List<PObject> translateRouters(List<Router> routers,ProcessKey pk){ List<PObject> result = new ArrayList<PObject>(); for (Router router:routers){ PObjectKey key = new PObjectKey(pk.getProcessId(), pk.getVersion(), pk .getProcessType(), router.getId()); PObject pObject = new NodeInstanceImpl(key); pObject.setCancellable(true); pObject.setCompensable(false); pObject.setWorkflowBehavior(routerBehavior); pObject.setWorkflowElement(router); result.add(pObject); } return result; } private List<PObject> translateEndNodes(List<EndNode> endNodes,ProcessKey pk){ List<PObject> result = new ArrayList<PObject>(); for (EndNode endNode:endNodes){ PObjectKey key = new PObjectKey(pk.getProcessId(), pk.getVersion(), pk .getProcessType(), endNode.getId()); PObject pObject = new NodeInstanceImpl(key); pObject.setCancellable(true); pObject.setCompensable(false); pObject.setWorkflowBehavior(endNodeBehavior ); pObject.setWorkflowElement(endNode); result.add(pObject); } return result; } private List<PObject> translateActivities(List<Activity> activities,ProcessKey pk){ List<PObject> result = new ArrayList<PObject>(); for (Activity activity:activities){ PObjectKey key = new PObjectKey(pk.getProcessId(), pk.getVersion(), pk .getProcessType(), activity.getId()); PObject pObject = new NodeInstanceImpl(key); pObject.setCancellable(true); pObject.setCompensable(true); pObject.setWorkflowBehavior(activityBehavior ); pObject.setWorkflowElement(activity); result.add(pObject); } return result; } private List<PObject> translateTransitions(List<Transition> transitions,ProcessKey pk){ List<PObject> result = new ArrayList<PObject>(); for (Transition transition:transitions){ PObjectKey key = new PObjectKey(pk.getProcessId(), pk.getVersion(), pk .getProcessType(), transition.getId()); PObject pObject = new ArcInstanceImpl(key); pObject.setCancellable(false); pObject.setCompensable(false); pObject.setWorkflowBehavior(transitionBehavior); pObject.setWorkflowElement(transition);//TODO 流程对象被众多PObject引用,是否浪费内存? result.add(pObject); } return result; } /** * 组装异常处理器,补偿处理器等 * @param subflow * @param pobjectList */ private void assemblePObject(SubProcess subflow ,List<PObject> pobjectList,ProcessKey pk){ List<Activity> activities = subflow.getActivities(); if (activities==null || activities.size()==0){ return; } for (Activity activity : activities){ PObjectKey pkey4Activity = new PObjectKey(pk.getProcessId(),pk.getVersion(),pk.getProcessType(),activity.getId()); PObject pobject4Activity = this.findPObject(pobjectList, pkey4Activity); List<StartNode> attachedStartNodes = activity.getAttachedStartNodes(); if (attachedStartNodes!=null && attachedStartNodes.size()>0){ for (StartNode startNode : attachedStartNodes){ Feature decorator = startNode.getFeature(); if (decorator!=null && decorator instanceof CatchCompensationFeature){ CatchCompensationFeature compensationDecorator = (CatchCompensationFeature)decorator; PObjectKey pkey = new PObjectKey(pk.getProcessId(),pk.getVersion(),pk.getProcessType(),startNode.getId()); PObject po = this.findPObject(pobjectList, pkey); if (po!=null){ String compensationCode = compensationDecorator.getCompensationCode(); if (compensationCode==null || compensationCode.trim().equals("")){ compensationCode = CatchCompensationFeature.CATCH_ALL_COMPENSATION; }else{ //分号分割 StringTokenizer tokenizer = new StringTokenizer(compensationCode,";"); while (tokenizer.hasMoreTokens()){ String code = tokenizer.nextToken(); if (code==null || code.trim().equals("")){ continue; } if (CatchCompensationFeature.CATCH_ALL_COMPENSATION.equals(code.trim())){ ((NodeInstanceImpl)pobject4Activity).setCompensationHandler(code.trim(), po,true); }else{ ((NodeInstanceImpl)pobject4Activity).setCompensationHandler(code.trim(), po); } } } } }else if (decorator!=null && decorator instanceof CatchFaultFeature){ CatchFaultFeature exceptionDecorator = (CatchFaultFeature)decorator; PObjectKey pkey = new PObjectKey(pk.getProcessId(),pk.getVersion(),pk.getProcessType(),startNode.getId()); PObject po = this.findPObject(pobjectList, pkey); if (po!=null){ String errorCode = exceptionDecorator.getErrorCode(); if (errorCode==null || errorCode.trim().equals("")){ ((NodeInstanceImpl)pobject4Activity).setFaultHandler(CatchFaultFeature.CATCH_ALL_FAULT, po,true); } else{ //分号分割 StringTokenizer tokenizer = new StringTokenizer(errorCode,";"); while (tokenizer.hasMoreTokens()){ String code = tokenizer.nextToken(); if (code==null || code.trim().equals("")){ continue; } if (CatchFaultFeature.CATCH_ALL_FAULT.equals(code.trim())){ ((NodeInstanceImpl)pobject4Activity).setFaultHandler(CatchFaultFeature.CATCH_ALL_FAULT, po,true); } else{ ((NodeInstanceImpl)pobject4Activity).setFaultHandler(code.trim(), po); } } } } } //TODO 需要catch cancellation decorator吗? // else if (decorator!=null && decorator instanceof CatchCancellationDecorator){ // // } // else if ( is catchTimerDecorator){ // // } } } } //装配流程级别的handler List<StartNode> startNodes = subflow.getStartNodes(); PObject pobject4Process = this.findPObject(pobjectList, new PObjectKey(pk.getProcessId(),pk.getVersion(),pk.getProcessType(),subflow.getId())); if (startNodes!=null && startNodes.size()>0){ for (StartNode start : startNodes) { PObjectKey pkey4Start = new PObjectKey(pk.getProcessId(), pk .getVersion(), pk.getProcessType(), start.getId()); PObject pobject4Start = this.findPObject(pobjectList, pkey4Start); Feature decorator = start.getFeature(); if (decorator != null && (decorator instanceof CatchFaultFeature)) { CatchFaultFeature faultDecorator = (CatchFaultFeature) decorator; if (faultDecorator.getAttachedToActivity()==null){ String errorCode = faultDecorator.getErrorCode(); if (errorCode == null || errorCode.trim().equals("")) { pobject4Process .setFaultHandler("", pobject4Start, true); } else { pobject4Process.setFaultHandler(errorCode, pobject4Start); } } } else if (decorator != null && (decorator instanceof CatchCompensationFeature)) { CatchCompensationFeature compensationDecorator = (CatchCompensationFeature) decorator; if (compensationDecorator.getAttachedToActivity() == null) { String compensationCode = compensationDecorator .getCompensationCode(); if (compensationCode == null || compensationCode.trim().equals("")) { compensationCode = CatchCompensationFeature.CATCH_ALL_COMPENSATION; } if (compensationCode .equals(CatchCompensationFeature.CATCH_ALL_COMPENSATION)) { pobject4Process.setCompensationHandler( compensationCode, pobject4Start, true); } else { pobject4Process.setCompensationHandler( compensationCode, pobject4Start); } } } } } } private PObject findPObject(List<PObject> pobjectList,PObjectKey pkey){ if (pobjectList==null || pobjectList.size()==0){ return null; } for (PObject pobject : pobjectList){ if (pobject.getKey().equals(pkey)){ return pobject; } } return null; } /* (non-Javadoc) * @see org.fireflow.pvm.translate.Process2PObjectTranslator#translateProcess(org.fireflow.engine.entity.repository.ProcessKey) */ public List<PObject> translateProcess(ProcessKey processKey) throws InvalidModelException,WorkflowProcessNotFoundException{ PersistenceService persistenceService = runtimeContext.getEngineModule(PersistenceService.class, FpdlConstants.PROCESS_TYPE_FPDL20); ProcessPersister processPersister = persistenceService.getProcessPersister(); ProcessRepository repository = processPersister.findProcessRepositoryByProcessKey(processKey); if (repository==null){ throw new WorkflowProcessNotFoundException("The process is not found, id="+processKey.getProcessId()+", version="+processKey.getVersion()+", processType="+processKey.getProcessType()); }else{ return this.translateProcess(processKey, repository.getProcessObject()); } } /* (non-Javadoc) * @see org.fireflow.engine.context.RuntimeContextAware#getRuntimeContext() */ public RuntimeContext getRuntimeContext() { return runtimeContext; } /* (non-Javadoc) * @see org.fireflow.engine.context.RuntimeContextAware#setRuntimeContext(org.fireflow.engine.context.RuntimeContext) */ public void setRuntimeContext(RuntimeContext ctx) { this.runtimeContext = ctx; } private RuntimeContext runtimeContext = null; }