/**
* 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 org.fireflow.client.WorkflowSession;
import org.fireflow.client.impl.WorkflowSessionLocalImpl;
import org.fireflow.engine.context.RuntimeContext;
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.NetInstance;
import org.fireflow.pvm.kernel.NodeInstance;
import org.fireflow.pvm.kernel.OperationContextName;
import org.fireflow.pvm.kernel.PObject;
import org.fireflow.pvm.kernel.PObjectKey;
import org.fireflow.pvm.kernel.Token;
import org.fireflow.pvm.kernel.TokenState;
import org.fireflow.pvm.pdllogic.CancellationHandler;
import org.fireflow.pvm.pdllogic.CompensationHandler;
import org.fireflow.pvm.pdllogic.ExecuteResult;
import org.fireflow.pvm.pdllogic.FaultHandler;
import org.fireflow.pvm.pdllogic.WorkflowBehavior;
/**
* @author 非也
* @version 2.0
*/
public class NetInstanceImpl extends AbstractPObject implements
NetInstance {
protected NodeInstance parentNodeInstance = null;
public NetInstanceImpl(PObjectKey key){
super(key);
}
//////////////////////////////////////////////////////////////////
/////////////// 结构逻辑 ///////////////////////////////////
/////////////////////////////////////////////////////////////////
/* (non-Javadoc)
* @see org.fireflow.pvm.kernel.NetInstance#getParentNodeInstance()
*/
// @Override
// public NodeInstance getParentNodeInstance() {
// return parentNodeInstance;
// }
//
// public void setParentNodeInstance(NodeInstance nodeInst){
// this.parentNodeInstance = nodeInst;
// }
/* (non-Javadoc)
* @see org.fireflow.pvm.kernel.NetInstance#getCancellationHandle()
*/
public boolean isCancellable(){
return true;
}
public boolean isCompensable(){
return true;
}
//////////////////////////////////////////////////////////////////
/////////////// 行为逻辑 ///////////////////////////////////
/////////////////////////////////////////////////////////////////
/* (non-Javadoc)
* @see org.fireflow.pvm.kernel.NetInstance#catchFault(org.fireflow.engine.WorkflowSession, org.fireflow.pvm.kernel.Token)
*/
public void catchFault(WorkflowSession session, Token token,ExecuteResult result) {
String faultCode = result.getErrorCode();
BookMark bookMark = new BookMark();
bookMark.setToken(token);
bookMark.setExecutionEntrance(ExecutionEntrance.HANDLE_FAULT);
bookMark.setExtraArg(BookMark.ERROR_CODE, faultCode);
RuntimeContext ctx = ((WorkflowSessionLocalImpl) session)
.getRuntimeContext();
KernelManager kernelManager = ctx.getDefaultEngineModule(KernelManager.class);
kernelManager.addBookMark(bookMark);
}
/* (non-Javadoc)
* (2012-02-03,该动作容易和handleTermination混淆,意义也不是特别大,暂且注销)
* @see org.fireflow.pvm.kernel.NetInstance#handleCancellation(org.fireflow.engine.WorkflowSession, org.fireflow.pvm.kernel.Token)
*/
/*
public void handleCancellation(WorkflowSession session, Token existToken, Token sourceToken) {
if (!existToken.getState().equals(TokenState.RUNNING) || !existToken.getState().equals(TokenState.FAULTING)){
throw new KernelException(
"Illegal token state ,the TokenState.RUNNING or TokenState.FAULTING is expected,but it is "
+ existToken.getState().name());
}
//1、对已经完成的子token执行补偿操作
RuntimeContext runtimeContext = ((WorkflowSessionLocalImpl)session).getRuntimeContext();
KernelManager kernelManager = runtimeContext.getDefaultEngineModule(KernelManager.class);
boolean cancellationDone = true;//取消操作已经完成
List<Token> children = kernelManager.getChildren4Compensation(existToken);
for (Token childToken:children){
if (childToken.getState().equals(TokenState.COMPLETED)){
PObject tmp = kernelManager.getProcessObject(childToken);
if (tmp.isCompensable()) {
BookMark bookMark = new BookMark();
bookMark.setToken(childToken);
bookMark
.setExecutionEntrance(ExecutionEntrance.HANDLE_COMPENSATION);
bookMark.setExtraArg(BookMark.COMPENSATION_CODE, null);
kernelManager.addBookMark(bookMark);
cancellationDone = false;
}
}
}
//2、执行取消操作
PObject processObject = this.getCancellationHandler();
if (processObject!=null){
Token newToken = new TokenImpl(existToken);
newToken.setElementId(processObject.getKey().getWorkflowElementId());
newToken.setBusinessPermitted(true);
newToken.setCallbackTokenId(existToken.getId());
newToken.setOperationContextName(OperationContextName.CANCELLATION);
BookMark bookMark = new BookMark();
bookMark.setToken(newToken);
bookMark.setExecutionEntrance(ExecutionEntrance.TAKE_TOKEN);
kernelManager.addBookMark(bookMark);
cancellationDone = false;
}else{
CancellationHandler cancellationHandler = this.getWorkflowBehavior().getCancellationHandler();
if (cancellationHandler!=null){
cancellationHandler.handleCancellation(session, existToken, this.getWorkflowElement());
}else{
children = kernelManager.getChildren(existToken);
for (Token childToken:children){
if (childToken.getState().equals(TokenState.RUNNING)||childToken.getState().equals(TokenState.FAULTING)){
PObject tmp = kernelManager.getProcessObject(childToken);
if (tmp.isCancellable()){
BookMark bookMark = new BookMark();
bookMark.setToken(childToken);
bookMark.setExecutionEntrance(ExecutionEntrance.HANDLE_CANCELLATION);
kernelManager.addBookMark(bookMark);
cancellationDone = false;
}
}
}
}
}
//3、设置取消状态
if (cancellationDone){
existToken.setState(TokenState.CANCELLED);
kernelManager.saveOrUpdateToken(existToken);
WorkflowBehavior behavior = this.getWorkflowBehavior();
behavior.onTokenStateChanged(session, existToken, this.getWorkflowElement());
}else{
existToken.setState(TokenState.CANCELLING);
kernelManager.saveOrUpdateToken(existToken);
WorkflowBehavior behavior = this.getWorkflowBehavior();
behavior.onTokenStateChanged(session, existToken, this.getWorkflowElement());
}
}
*/
/* (non-Javadoc)
* @see org.fireflow.pvm.kernel.NetInstance#handleCompensation(org.fireflow.engine.WorkflowSession, org.fireflow.pvm.kernel.Token, java.lang.String)
*/
public void handleCompensation(WorkflowSession session, Token listenerToken, Token sourceToken, String compensationCode) {
if (!listenerToken.getState().equals(TokenState.COMPLETED) && !listenerToken.getState().equals(TokenState.RUNNING)
&& !listenerToken.getState().equals(TokenState.COMPENSATING)){
throw new KernelException(this,
"Illegal token state ,the TokenState.COMPLETED or TokenState.RUNNING is expected,but it is "
+ listenerToken.getState().name());
}
RuntimeContext runtimeContext = ((WorkflowSessionLocalImpl)session).getRuntimeContext();
KernelManager kernelManager = runtimeContext.getDefaultEngineModule(KernelManager.class);
boolean compensationDone = true;//补偿操作是否已经完成
//1、首先对正在运行的正常(operationContextName=NORMAL)的子token执行Abort操作
List<Token> children = kernelManager.getChildren(listenerToken);
for (Token token:children){
if ((token.getState().equals(TokenState.INITIALIZED)
|| token.getState().equals(TokenState.RUNNING))
&& token.getOperationContextName().equals(OperationContextName.NORMAL)){
PObject tmp = kernelManager.getProcessObject(token);
if (tmp.isCancellable()) {
BookMark bookMark = new BookMark();
bookMark.setToken(token);
bookMark.setExtraArg(BookMark.SOURCE_TOKEN, sourceToken);
bookMark
.setExecutionEntrance(ExecutionEntrance.HANDLE_TERMINATION);
kernelManager.addBookMark(bookMark);
compensationDone = false;
}
}
}
//2、然后执行补偿操作
PObject processObject = null;
if (compensationCode==null || compensationCode.trim().equals("")){
processObject = this.defaultCompensationHandler;
}else{
processObject = this.getCompensationHandler(compensationCode);
}
if (processObject!=null){
Token newToken = new TokenImpl(sourceToken);
newToken.setElementId(processObject.getKey().getWorkflowElementId());
newToken.setBusinessPermitted(true);
newToken.setCallbackTokenId(listenerToken.getId());
newToken.setOperationContextName(OperationContextName.COMPENSATION);
BookMark bookMark = new BookMark();
bookMark.setToken(newToken);
bookMark.setExtraArg(BookMark.SOURCE_TOKEN, sourceToken);
bookMark.setExecutionEntrance(ExecutionEntrance.TAKE_TOKEN);
kernelManager.addBookMark(bookMark);
compensationDone = false;
}else{
CompensationHandler compensationHandler = this.getWorkflowBehavior().getCompensationHandler(compensationCode);
if (compensationHandler!=null){
compensationHandler.handleCompensation(session, listenerToken, this.getWorkflowElement(), compensationCode);
} else {
//TODO 循环的情况难道要做多次补偿?
//2011-1-16,如果牵涉到补偿,流程场景不应该有循环,所以该处处理方案问题不大。
children = kernelManager.getChildren4Compensation(listenerToken);
if (children != null) {
boolean compensationDone2 = _handleCompensation(kernelManager,listenerToken,children,compensationCode,sourceToken);
compensationDone = compensationDone && compensationDone2;
}
}
}
//3、进入补偿状态
//2012-2-3,对于netinstance而言,应该不关心compensationDone的值,直接设置为COMPENSATING,而不需要设置为COMPENSATED
/**********
if (compensationDone){
listenerToken.setState(TokenState.COMPENSATED);
kernelManager.saveOrUpdateToken(listenerToken);
WorkflowBehavior behavior = this.getWorkflowBehavior();
behavior.onTokenStateChanged(session, listenerToken, this
.getWorkflowElement());
// 通知父token(一般是父流程中的某个活动),使之从Compensating状态转移到compensated状态
Token parentToken = kernelManager.getParentToken(listenerToken);
if (parentToken != null) {
PObject parent = null;
parent = kernelManager.getProcessObject(parentToken);
if (parent != null) {
BookMark bookMark = new BookMark();
bookMark.setToken(parentToken);
bookMark.setExecutionEntrance(ExecutionEntrance.FORWARD_TOKEN);
bookMark.setExtraArg(BookMark.SOURCE_TOKEN, listenerToken);
kernelManager.addBookMark(bookMark);
}
}
}else{
listenerToken.setState(TokenState.COMPENSATING);
kernelManager.saveOrUpdateToken(listenerToken);
WorkflowBehavior behavior = this.getWorkflowBehavior();
behavior.onTokenStateChanged(session, listenerToken, this.getWorkflowElement());
}
********/
listenerToken.setState(TokenState.COMPENSATING);
kernelManager.saveOrUpdateToken(listenerToken);
WorkflowBehavior behavior = this.getWorkflowBehavior();
behavior.onTokenStateChanged(session, listenerToken, this.getWorkflowElement());
}
public boolean isAcceptCompensation(Token token,String compensationCode){
if (this.isCompensable()){
return true;
}else{
return false;
}
}
}