/**
* 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.pvm.kernel.impl;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Vector;
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.AbsEngineModule;
import org.fireflow.engine.context.RuntimeContext;
import org.fireflow.engine.context.RuntimeContextAware;
import org.fireflow.engine.entity.repository.ProcessKey;
import org.fireflow.engine.entity.runtime.ProcessInstance;
import org.fireflow.engine.exception.WorkflowProcessNotFoundException;
import org.fireflow.engine.modules.persistence.PersistenceService;
import org.fireflow.engine.modules.persistence.TokenPersister;
import org.fireflow.model.InvalidModelException;
import org.fireflow.pvm.kernel.BookMark;
import org.fireflow.pvm.kernel.ExecutionEntrance;
import org.fireflow.pvm.kernel.KernelException;
import org.fireflow.pvm.kernel.KernelManager;
import org.fireflow.pvm.kernel.PObject;
import org.fireflow.pvm.kernel.PObjectKey;
import org.fireflow.pvm.kernel.Token;
import org.fireflow.pvm.translate.Process2PObjectTranslator;
/**
* @author 非也
* @version 2.0
*/
public class KernelManagerImpl extends AbsEngineModule implements KernelManager, RuntimeContextAware {
private static Log log = LogFactory.getLog(KernelManagerImpl.class);
protected RuntimeContext runtimeContext = null;
protected ThreadLocal<Vector<BookMark>> bookMarkQueue = new ThreadLocal<Vector<BookMark>>() {
public Vector<BookMark> initialValue() {
return new Vector<BookMark>();
}
};
protected Map<PObjectKey,PObject> processObjectStorage = new HashMap<PObjectKey,PObject>();
protected Map<ProcessKey,Boolean> loadedProcesses = new HashMap<ProcessKey,Boolean>();
/* (non-Javadoc)
* @see org.fireflow.pvm.kernel.KernelManager#executeProcessObject(org.fireflow.engine.WorkflowSession, org.fireflow.pvm.kernel.ProcessObjectKey)
*/
// public void startPObject1(WorkflowSession session,
// PObjectKey processObjectKey) {
// this.loadProcess(ProcessKey.valueOf(processObjectKey));
//
// PObject processObject = this.getProcessObject(processObjectKey);
// if (processObject==null){
// throw new KernelException("No process object for "+processObjectKey.toString());
// }
// Token token = new TokenImpl();
// token.setBusinessPermitted(true);
// token.setState(TokenState.INITIALIZED);
// token.setProcessId(processObjectKey.getProcessId());
// token.setVersion(processObjectKey.getVersion());
// token.setElementId(processObjectKey.getWorkflowElementId());
// token.setProcessType(processObjectKey.getProcessType());
// token.setStepNumber(0);
// token.setProcessType( processObjectKey.getProcessType());
//
//
// BookMark bookMark = new BookMark();
// bookMark.setToken(token);
// bookMark.setExecutionEntrance(ExecutionEntrance.TAKE_TOKEN);
// this.addBookMark(bookMark);
//
// this.execute(session);
// }
public void startPObject(WorkflowSession session,PObjectKey childPObjectKey,
Token parentToken,ProcessInstance childProcessInstance){
this.loadProcess(ProcessKey.valueOf(childPObjectKey));
Token childToken = new TokenImpl(parentToken);
if (childProcessInstance!=null){
childToken.setProcessInstanceId(childProcessInstance.getId());
childToken.setElementInstanceId(childProcessInstance.getId());
}
childToken.setProcessId(childPObjectKey.getProcessId());
childToken.setProcessType(childPObjectKey.getProcessType());
childToken.setVersion(childPObjectKey.getVersion());
childToken.setElementId(childPObjectKey.getWorkflowElementId());
if (parentToken!=null){
childToken.setParentTokenId(parentToken.getId());
}
BookMark bookMark = new BookMark();
bookMark.setToken(childToken);
bookMark.setExecutionEntrance(ExecutionEntrance.TAKE_TOKEN);
this.addBookMark(bookMark);
}
public void loadProcess(ProcessKey pk ){
if (this.loadedProcesses.get(pk)!=null && this.loadedProcesses.get(pk)){
return;//已经装载
}
else{
Process2PObjectTranslator translator = this.runtimeContext.getEngineModule(Process2PObjectTranslator.class, pk.getProcessType());
List<PObject> processObjectList = null;
try {
processObjectList = translator.translateProcess(pk);
} catch (InvalidModelException e) {
throw new KernelException(null,e);
} catch (WorkflowProcessNotFoundException e) {
throw new KernelException(null,e);
}
if (processObjectList!=null){
for(PObject po:processObjectList){
this.processObjectStorage.put(po.getKey(), po);
}
}
this.loadedProcesses.put(pk,Boolean.TRUE);
}
}
public void addBookMark(BookMark bookMark){
if (bookMark.getExecutionEntrance().equals(ExecutionEntrance.TAKE_TOKEN)){
Token token = bookMark.getToken();
PersistenceService persistenceStrategy = this.runtimeContext.getEngineModule(PersistenceService.class, token.getProcessType());
TokenPersister tokenPersistenceService = persistenceStrategy.getTokenPersister();
tokenPersistenceService.saveOrUpdate(token);
}
bookMarkQueue.get().add(bookMark);
}
public boolean hasChildrenInQueue(Token token){
Vector<BookMark> queue = bookMarkQueue.get();
if (queue.size()==0){
return false;
}
for (BookMark bookMark:queue){
Token tk = bookMark.getToken();
if (tk.getParentTokenId()!=null && tk.getParentTokenId().equals(token.getId())){
return true;
}
}
return false;
}
private BookMark getBookMark(){
log.debug(this.viewTheBookMarkQueue());
if (bookMarkQueue.get().size()>0){
return bookMarkQueue.get().remove(0);
}else{
return null;
}
}
public void execute(WorkflowSession session){
BookMark bookMark = null;
while((bookMark=this.getBookMark())!=null){
Token token = bookMark.getToken();
Token sourceToken = (Token)bookMark.getExtraArg(BookMark.SOURCE_TOKEN);
PObject po = this.getProcessObject(token);
ExecutionEntrance entrance = bookMark.getExecutionEntrance();
switch (entrance){
case TAKE_TOKEN:
po.takeToken(session, token, sourceToken);
break;
case FORWARD_TOKEN:
po.forwardToken(session, token, sourceToken);
break;
//(2012-02-05,该动作容易和handleTermination混淆,意义也不是特别大,暂且注销)
/*
case HANDLE_CANCELLATION:
po.handleCancellation(session, token, sourceToken);
break;
*/
case HANDLE_COMPENSATION:
String compensationCode = (String)bookMark.getExtraArg(BookMark.COMPENSATION_CODE);
po.handleCompensation(session, token, sourceToken, compensationCode);
break;
case HANDLE_FAULT:
String faultCode = (String)bookMark.getExtraArg(BookMark.ERROR_CODE);
po.handleFault(session, token, sourceToken, faultCode);
break;
case HANDLE_TERMINATION:
po.handleTermination(session, token, sourceToken);
;
}
}
}
public void fireTerminationEvent(WorkflowSession session,Token listenerToken,Token sourceToken){
BookMark bookMark = new BookMark();
bookMark.setToken(listenerToken);
bookMark.setExtraArg(BookMark.SOURCE_TOKEN, sourceToken);
bookMark.setExecutionEntrance(ExecutionEntrance.HANDLE_TERMINATION);
this.addBookMark(bookMark);
}
public void fireCompensationEvent(WorkflowSession session,Token listenerToken,Token sourceToken,List<String> compensationCodes){
if (compensationCodes!=null && compensationCodes.size()>0){
for (String compensationCode : compensationCodes){
BookMark bookMark = new BookMark();
bookMark.setToken(listenerToken);
bookMark.setExecutionEntrance(ExecutionEntrance.HANDLE_COMPENSATION);
bookMark.setExtraArg(BookMark.COMPENSATION_CODE, compensationCode);
bookMark.setExtraArg(BookMark.SOURCE_TOKEN, sourceToken);
this.addBookMark(bookMark);
}
}
}
public void fireFaultEvent(WorkflowSession session,Token listenerToken,Token sourceToken, String faultCode){
BookMark bookMark = new BookMark();
bookMark.setToken(listenerToken);
bookMark.setExtraArg(BookMark.SOURCE_TOKEN, sourceToken);
bookMark.setExecutionEntrance(ExecutionEntrance.HANDLE_FAULT);
bookMark.setExtraArg(BookMark.ERROR_CODE, faultCode);
this.addBookMark(bookMark);
}
/* (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) {
runtimeContext = ctx;
}
/* (non-Javadoc)
* @see org.fireflow.pvm.kernel.KernelManager#getParentToken(org.fireflow.pvm.kernel.Token)
*/
public Token getParentToken(Token currentToken) {
if (currentToken.getParentTokenId()==null || currentToken.getParentTokenId().trim().equals("")){
return null;
}
PersistenceService persistenceStrategy = this.runtimeContext.getEngineModule(PersistenceService.class, currentToken.getProcessType());
TokenPersister tokenPersistenceService = persistenceStrategy.getTokenPersister();
return tokenPersistenceService.findParentToken(currentToken);
}
/* (non-Javadoc)
* @see org.fireflow.pvm.kernel.KernelManager#getProcessObject(org.fireflow.pvm.kernel.Token)
*/
public PObject getProcessObject(Token token) {
if (token==null )return null;
ProcessKey processKey = new ProcessKey(token.getProcessId(),token.getVersion(),token.getProcessType());
this.loadProcess(processKey);
PObjectKey pObjectKey = new PObjectKey(token.getProcessId(),token.getVersion(),token.getProcessType(),token.getElementId());
return this.processObjectStorage.get(pObjectKey);
}
/* (non-Javadoc)
* @see org.fireflow.pvm.kernel.KernelManager#getProcessObject(org.fireflow.pvm.kernel.ProcessObjectKey)
*/
public PObject getProcessObject(PObjectKey key) {
ProcessKey processKey = new ProcessKey(key.getProcessId(),key.getVersion(),key.getProcessType());
this.loadProcess(processKey);
return processObjectStorage.get(key);
}
public Object getWorkflowElement(PObjectKey key){
PObject pobj = this.getProcessObject(key);
if (pobj==null)return null;
return pobj.getWorkflowElement();
}
/* (non-Javadoc)
* @see org.fireflow.pvm.kernel.KernelManager#getToken(java.lang.String, java.lang.String)
*/
public Token getTokenById(String tokenId,String processType) {
PersistenceService persistenceStrategy = this.runtimeContext.getEngineModule(PersistenceService.class, processType);
TokenPersister tokenPersistenceService = persistenceStrategy.getTokenPersister();
return tokenPersistenceService.fetch(Token.class, tokenId);
}
public Token getTokenByElementInstanceId(String elementInstanceId,String processType){
PersistenceService persistenceStrategy = this.runtimeContext.getEngineModule(PersistenceService.class, processType);
TokenPersister tokenPersistenceService = persistenceStrategy.getTokenPersister();
return tokenPersistenceService.findTokenByElementInstanceId(elementInstanceId);
}
/* (non-Javadoc)
* @see org.fireflow.pvm.kernel.KernelManager#getChildren(org.fireflow.pvm.kernel.Token)
*/
public List<Token> getChildren(Token token) {
PersistenceService persistenceStrategy = this.runtimeContext.getEngineModule(PersistenceService.class, token.getProcessType());
TokenPersister tokenPersistenceService = persistenceStrategy.getTokenPersister();
return tokenPersistenceService.findChildTokens(token);
}
/* (non-Javadoc)
* @see org.fireflow.pvm.kernel.KernelManager#getChildren4Compensation(org.fireflow.pvm.kernel.Token)
*/
public List<Token> getChildren4Compensation(Token token) {
PersistenceService persistenceStrategy = this.runtimeContext.getEngineModule(PersistenceService.class, token.getProcessType());
TokenPersister tokenPersistenceService = persistenceStrategy.getTokenPersister();
return tokenPersistenceService.findChildTokens4Compensation(token);
}
public void saveOrUpdateToken(Token token){
PersistenceService persistenceStrategy = this.runtimeContext.getEngineModule(PersistenceService.class, token.getProcessType());
TokenPersister tokenPersistenceService = persistenceStrategy.getTokenPersister();
tokenPersistenceService.saveOrUpdate(token);
}
/**
* 显示bookmark队列,用于调试
* @return
*/
public String viewTheBookMarkQueue(){
Vector<BookMark> queue = bookMarkQueue.get();
StringBuffer buf = new StringBuffer("The bookmark queue is :\n======================\n");
int index = 0;
for(BookMark bookMark:queue){
buf.append(bookMark.getToken().getElementId())
.append("[").append(bookMark.getToken().getState().name()).append("]")
.append("-->")
.append(bookMark.getExecutionEntrance().name());
index++;
if (index<queue.size()){
buf.append("\n");
}
}
buf.append("\n======================");
return buf.toString();
}
public void clearCachedPObject(){
this.processObjectStorage.clear();
this.loadedProcesses.clear();
}
}