All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cz.wicketstuff.boss.flow.processor.basic.AbstractFlowProcessor Maven / Gradle / Ivy

There is a newer version: 1.3.1
Show newest version
/*
 * Et netera, http://boss.etnetera.cz - Copyright (C) 2012 
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License (version 2.1) as published by the Free Software
 * Foundation.
 *
 * This library 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 Lesser General Public License for more details:
 * http://www.gnu.org/licenses/lgpl-3.0.txt
 * 
 */
package cz.wicketstuff.boss.flow.processor.basic;

import java.io.Serializable;
import java.util.Iterator;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cz.wicketstuff.boss.flow.FlowException;
import cz.wicketstuff.boss.flow.model.IFlowCarter;
import cz.wicketstuff.boss.flow.model.IFlowState;
import cz.wicketstuff.boss.flow.model.IFlowTransition;
import cz.wicketstuff.boss.flow.processor.FlowAlreadyFinishedException;
import cz.wicketstuff.boss.flow.processor.FlowInitializationException;
import cz.wicketstuff.boss.flow.processor.FlowMaxHitsReachedException;
import cz.wicketstuff.boss.flow.processor.FlowTransitionIsRunningException;
import cz.wicketstuff.boss.flow.processor.IFlowProcessor;
import cz.wicketstuff.boss.flow.processor.NoSuchTransitionException;

public abstract class AbstractFlowProcessor implements IFlowProcessor, Serializable {

	private static final long serialVersionUID = 1L;
	
	private Integer maxFlowHits;
	
	private static final Logger log = LoggerFactory.getLogger(AbstractFlowProcessor.class);
	
	public AbstractFlowProcessor() {
	}

	@Override
	public IFlowCarter initFlow(Long flowProcessId, T payload) throws FlowException {
		return initFlow(flowProcessId, payload, getDefaultInitialState());
	}

	@Override
	public IFlowCarter initFlow(Long flowProcessId, T payload, IFlowState initialState) throws FlowException {
		if(!initialState.isInitialState()) {
			throw new FlowInitializationException("Cannot initialize flow, '" + initialState.getStateName() + "' is not an initial state of flow '" + getFlowName() + "'.");
		}
		IFlowCarter flow = createFlowCarter(flowProcessId, initialState);
		flow.setPayload(payload);
		onFlowInitialized(flow);
		if(initialState.isRequireStateData()) {
			flow.setStateData(createStateData(initialState));			
		}
		onStateEntry(flow);
		log.trace("State " + flow.getCurrentState().getStateName() + " persistable " + flow.getCurrentState().isPersistableState());
		if(flow.getCurrentState().isPersistableState()) {
			persistFlowState(flow);
		}
		processState(flow);
		IFlowTransition nextTransition = flow.getNextTransition(); 
		if(nextTransition != null) {
			invokeTransition(flow, nextTransition);
		}
		return flow;
	}
	
	@Override
	public boolean invokeTransition(IFlowCarter flow, IFlowTransition transition)
			throws FlowException {
		if(flow.isFlowProcessed()) {
			throw new FlowTransitionIsRunningException("Transition " + transition.getTransitionName() + " is currently running on " + flow.getCurrentState().getStateName());
		}
		flow.setFlowProcessed(true);		
		try {			
			if(log.isDebugEnabled()) {
				log.debug("Running transition '" + transition.getTransitionName() + "' on step '" + flow.getCurrentState().getStateName() + "'");			
			}
			flow.setNextTransition(transition);
			int stateHit = flow.getStateHit();
			
			do {
				if(flow.getCurrentState().isFinalState()) {
					throw new FlowAlreadyFinishedException("The state '" + flow.getCurrentState().getStateName() + "' of flow '" + getFlowName() + "' is a final state, no transition is allowed here.");
				}
				
				if(!checkTransition(flow, flow.getNextTransition())) {
					throw new NoSuchTransitionException("Transition '" + flow.getNextTransition().getTransitionName() + "' is not a valid transition of state '" + flow.getCurrentState().getStateName() + "'.");
				}
				
				if(flow.getCurrentState().isStateValidatable()) {
					if(validateState(flow).isValid()) {
						onStateValid(flow);				
					} else {
						onStateInvalid(flow);
						flow.setNextTransition(null);
						return false;
					}
				}
				onTransitionStart(flow);
				onStateLeaving(flow);
				onTransitionFinished(flow);
				flow.shiftFlow();
				onStateEntry(flow);
				if(flow.getCurrentState().isPersistableState()) {
					persistFlowState(flow);
				}
				if(isMaxHitsReached(flow)) {
					throw new FlowMaxHitsReachedException(getMaxFlowHits(), flow.getStateHit());
				}
				processState(flow);
			} while (flow.getNextTransition() != null);
			flow.setFlowProcessed(false);			
			return flow.getStateHit() == stateHit;
		} catch (Exception e) {
			flow.setFlowProcessed(false);
			throw e;
		}
	}
	
	public boolean isMaxHitsReached(IFlowCarter flow) {
		Integer max = getMaxFlowHits(); 
		if(max == null) {
			return false;
		}
		return max <= flow.getStateHit();
	}

	@Override
	public boolean isCurrentState(IFlowCarter flow, IFlowState testedFlowState) {
		return flow.getCurrentState().equals(testedFlowState);
	}

	@Override
	public boolean isCurrentState(IFlowCarter flow, String testedFlowStateName) {
		return flow.getCurrentState().getStateName().equals(testedFlowStateName);
	}

	@Override
	public boolean checkTransition(IFlowCarter flow,
			IFlowTransition nextTransition) {
		for(Iterator it = flow.getCurrentState().getAvailableTransitions(); it.hasNext();) {
			IFlowTransition t = it.next();
			if(nextTransition.equals(t)) {
				return true;				
			}
		}
		return false;
	}

	public Integer getMaxFlowHits() {
		return maxFlowHits;
	}

	public void setMaxFlowHits(Integer maxFlowHits) {
		this.maxFlowHits = maxFlowHits;
	}
	
	abstract public void onFlowInitialized(IFlowCarter flow);

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy