Java tutorial
/** * The Clican-Pluto software suit is Copyright 2009, Clican Company and individual contributors, and is licensed under the GNU LGPL. * * @author wei.zhang * */ package com.clican.pluto.fsm.engine.state; import java.io.Serializable; import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.mvel2.MVEL; import org.springframework.transaction.annotation.Transactional; import com.clican.pluto.common.calendar.BusinessCalendar; import com.clican.pluto.fsm.dao.EventDao; import com.clican.pluto.fsm.dao.JobDao; import com.clican.pluto.fsm.dao.SessionDao; import com.clican.pluto.fsm.dao.StateDao; import com.clican.pluto.fsm.dao.TaskDao; import com.clican.pluto.fsm.engine.EngineContext; import com.clican.pluto.fsm.engine.IState; import com.clican.pluto.fsm.engine.JobContext; import com.clican.pluto.fsm.enumeration.Propagation; import com.clican.pluto.fsm.enumeration.Status; import com.clican.pluto.fsm.listener.StateListener; import com.clican.pluto.fsm.listener.TimeOutListener; import com.clican.pluto.fsm.model.Event; import com.clican.pluto.fsm.model.Job; import com.clican.pluto.fsm.model.Session; import com.clican.pluto.fsm.model.State; import com.clican.pluto.fsm.model.Task; import com.clican.pluto.fsm.model.Variable; /** * ? * * ??startListener * <p> * ???endListener * <p> * ?? * * @author wei.zhang * */ public class DefaultStateImpl implements IState { protected final Log log = LogFactory.getLog(getClass()); protected StateDao stateDao; protected SessionDao sessionDao; protected EventDao eventDao; protected TaskDao taskDao; protected JobDao jobDao; protected JobContext jobContext; protected String name; protected Integer value; protected List<IState> nextStates; protected List<StateListener> stateListeners; protected Map<String, TimeOutListener> timeoutListeners; protected Map<String, String> params; protected BusinessCalendar businessCalendar; protected Propagation propagation; protected int previousStateNumber = 1; protected EngineContext engineContext; protected Map<String, List<IState>> nextCondStates; public void setPropagation(String propagation) { this.propagation = Propagation.convert(propagation); } public void setNextStates(List<IState> nextStates) { this.nextStates = nextStates; } public void setPreviousStateNumber(int previousStateNumber) { this.previousStateNumber = previousStateNumber; } public void setEngineContext(EngineContext engineContext) { this.engineContext = engineContext; } public void setValue(Integer value) { this.value = value; } public void setJobDao(JobDao jobDao) { this.jobDao = jobDao; } public void setNextCondStates(Map<String, List<IState>> nextCondStates) { this.nextCondStates = nextCondStates; } @Transactional public void onEnd(Event event) { State state = event.getState(); List<IState> nextStateList = null; if (this.nextStates != null && this.nextStates.size() != 0) { nextStateList = nextStates; } else if (this.nextCondStates != null && this.nextCondStates.size() != 0) { for (String expr : this.nextCondStates.keySet()) { Boolean result = (Boolean) this.getVariableValueByEL(expr, event, true); if (result) { nextStateList = this.nextCondStates.get(expr); } } if (nextStateList == null) { throw new RuntimeException("There is no match condition"); } } if (stateListeners != null) { for (StateListener listener : stateListeners) { if (log.isDebugEnabled()) { log.debug("execute state listener[" + listener.getClass().getName() + "]"); } listener.onEnd(state, nextStateList, event); } } Session session = state.getSession(); state.setStatus(Status.INACTIVE.getStatus()); state.setEndTime(new Date()); session.setLastUpdateTime(new Date()); jobDao.deleteJobsByStateId(state.getId()); taskDao.completeTasksByStateId(state.getId()); stateDao.save(state); sessionDao.save(session); if (nextStateList != null) { for (IState istate : nextStateList) { istate.onStart(session, this, event); } } } @Transactional public void onStart(Session session, IState previousState, Event event) { State state; if (previousStateNumber != 1) { state = stateDao.getPendingState(session.getId(), this.getName()); if (state == null) { state = new State(); state.setValue(value); state.setStatus(Status.PENDING.getStatus()); state.setSession(session); state.setName(name); state.setJobSet(new HashSet<Job>()); prepareStateConstants(state); stateDao.save(state); session.getStateSet().add(state); sessionDao.save(session); } else { state.setPreviousStateNumber(state.getPreviousStateNumber() + 1); if (state.getPreviousStateNumber() == previousStateNumber) { state.setStatus(Status.ACTIVE.getStatus()); state.setStartTime(new Date()); } stateDao.save(state); } } else { state = new State(); state.setValue(value); state.setStatus(Status.ACTIVE.getStatus()); state.setSession(session); state.setName(name); state.setJobSet(new HashSet<Job>()); state.setStartTime(new Date()); prepareStateConstants(state); stateDao.save(state); session.getStateSet().add(state); sessionDao.save(session); } if (Status.convert(state.getStatus()) != Status.ACTIVE) { if (log.isDebugEnabled()) { log.debug("state=[" + this.getName() + "] is pending and wait for other substate to be end."); } return; } if (log.isDebugEnabled()) { log.debug("state=[" + this.getName() + "] is started"); } if (stateListeners != null) { for (StateListener listener : stateListeners) { if (log.isDebugEnabled()) { log.debug("execute state listener[" + listener.getClass().getName() + "]"); } listener.onStart(state, previousState, event); } } prepareJobs(state, event, null); } /** * ?? * * @param state */ private void prepareStateConstants(State state) { if (params == null || params.isEmpty()) { return; } Set<Variable> variableSet = state.getVariableSet(); if (variableSet == null) { variableSet = new HashSet<Variable>(); state.setVariableSet(variableSet); } for (String key : params.keySet()) { Variable var = new Variable(); var.setState(state); var.setName(key); var.setValue(params.get(key)); var.setChangeDate(new Date()); variableSet.add(var); } } /** * ???timeOutListenner??Job * * @param state * @param event * @param startTime * ?job */ protected void prepareJobs(State state, Event event, Date startTime) { if (timeoutListeners != null && !timeoutListeners.isEmpty()) { for (String name : timeoutListeners.keySet()) { if (log.isDebugEnabled()) { log.debug("prepare timeout listener[" + name + "] of state[" + state.getName() + "]."); } TimeOutListener listener = timeoutListeners.get(name); BusinessCalendar businessCalendar = listener.getBusinessCalendar() != null ? listener.getBusinessCalendar() : this.businessCalendar; Calendar temp = Calendar.getInstance(); if (StringUtils.isNotEmpty(listener.getStartTime())) { Serializable startTimeSer = getVariableValueByEL(listener.getStartTime(), event, true); if (startTimeSer instanceof Date) { temp.setTime((Date) startTimeSer); } else if (startTimeSer instanceof Calendar) { temp.setTime(((Calendar) startTimeSer).getTime()); } else { if (StringUtils.isNumeric(startTimeSer.toString())) { temp.setTimeInMillis(Long.parseLong(startTimeSer.toString())); } } } Job job = new Job(); job.setName(name); job.setBusinessCalendarName(listener.getBusinessCalendarName()); Serializable dueTime = this.getVariableValueByEL(listener.getDueTime(), event, true); if (dueTime == null) { // Job, ?Job if (startTime == null) { log.warn("Job: " + name + " have no dueTime, create fail!"); continue; } else { job.setExecuteTime(startTime); } } else { if (dueTime instanceof Date) { temp.setTimeInMillis(((Date) dueTime).getTime()); } else if (dueTime instanceof Calendar) { temp.setTimeInMillis(((Calendar) dueTime).getTimeInMillis()); } else if (dueTime instanceof Long) { temp.setTimeInMillis((Long) dueTime); } else if (dueTime instanceof String) { temp.setTimeInMillis(businessCalendar.add(temp.getTime(), (String) dueTime).getTime()); } else { throw new RuntimeException("Unsupported DueTime format"); } job.setExecuteTime(temp.getTime()); } if (StringUtils.isNotEmpty(listener.getRepeatDuration())) { job.setRepeatDuration((String) getVariableValueByEL(listener.getRepeatDuration(), event, true)); } if (StringUtils.isNotEmpty(listener.getRepeatTime())) { job.setRepeatTime(Integer .valueOf(getVariableValueByEL(listener.getRepeatTime(), event, true).toString())); } job.setState(state); jobContext.addJob(job); } } else { if (log.isDebugEnabled()) { log.debug("there is no timeout listener in state[" + state.getName() + "]."); } } } /** * ?Event??Scope Context * <p> * spring xml. * * @see Propagation * @param event */ protected void propagateVariables(Event event) { State state = event.getState(); if (this.propagation == Propagation.STATE || this.propagation == Propagation.SESSION) { for (Variable var : event.getVariableSet()) { stateDao.setVariable(state, var.getName(), var.getValue()); } } stateDao.save(state); Session session = state.getSession(); if (this.propagation == Propagation.SESSION) { for (Variable var : event.getVariableSet()) { sessionDao.setVariable(session, var.getName(), var.getValue()); } } session.setLastUpdateTime(new Date()); sessionDao.save(session); } @Transactional public void handle(Event event) { try { // for the DefaultStateImpl we will go to the end if (log.isDebugEnabled()) { log.debug("receive event[" + event + "]"); } propagateVariables(event); onEnd(event); } catch (Exception e) { log.error("", e); throw new RuntimeException(e); } } public List<StateListener> getStateListeners() { return stateListeners; } public void setStateListeners(List<StateListener> stateListeners) { this.stateListeners = stateListeners; } public Map<String, TimeOutListener> getTimeoutListeners() { return timeoutListeners; } public void setTimeoutListeners(Map<String, TimeOutListener> timeoutListeners) { this.timeoutListeners = timeoutListeners; } public Map<String, String> getParams() { return params; } public void setParams(Map<String, String> params) { this.params = params; } public void setTaskDao(TaskDao taskDao) { this.taskDao = taskDao; } public String getName() { return name; } public void setName(String name) { this.name = name; } public void setStateDao(StateDao stateDao) { this.stateDao = stateDao; } public void setSessionDao(SessionDao sessionDao) { this.sessionDao = sessionDao; } public void setBusinessCalendar(BusinessCalendar businessCalendar) { this.businessCalendar = businessCalendar; } public void setJobContext(JobContext jobContext) { this.jobContext = jobContext; } public void setEventDao(EventDao eventDao) { this.eventDao = eventDao; } protected Serializable getVariableValue(String variableName, Task task, boolean nested) { Serializable variableValue = this.getVariableValue(variableName, task.getVariableSet()); if (variableValue != null) { return variableValue; } if (nested) { variableValue = this.getVariableValue(variableName, task.getState(), nested); } return variableValue; } protected Serializable getVariableValue(String variableName, Event event, boolean nested) { Serializable variableValue = this.getVariableValue(variableName, event.getVariableSet()); if (variableValue != null) { return variableValue; } if (nested) { variableValue = this.getVariableValue(variableName, event.getState(), nested); } return variableValue; } protected Serializable getVariableValue(String variableName, State state, boolean nested) { Serializable variableValue = this.getVariableValue(variableName, state.getVariableSet()); if (variableValue != null) { return variableValue; } if (nested) { variableValue = this.getVariableValue(variableName, state.getSession()); } return variableValue; } protected Serializable getVariableValue(String variableName, Session session) { Serializable variableValue = this.getVariableValue(variableName, session.getVariableSet()); if (variableValue != null) { return variableValue; } return variableValue; } protected Serializable getVariableValue(String variableName, Set<Variable> variableSet) { if (variableSet == null || variableName == null) { return null; } for (Variable var : variableSet) { if (var.getName().equals(variableName)) { return var.getValue(); } } return null; } protected Serializable getVariableValueByEL(String variableName, Task task, boolean nested) { Serializable variableValue = this.getVariableValueByEL(variableName, task.getVariableSet()); if (variableValue != null) { return variableValue; } if (nested) { variableValue = this.getVariableValueByEL(variableName, task.getState(), nested); } return variableValue; } protected Serializable getVariableValueByEL(String variableName, Event event, boolean nested) { Serializable variableValue = this.getVariableValueByEL(variableName, event.getVariableSet()); if (variableValue != null) { return variableValue; } if (nested) { variableValue = this.getVariableValueByEL(variableName, event.getState(), nested); } return variableValue; } protected Serializable getVariableValueByEL(String variableName, State state, boolean nested) { Serializable variableValue = this.getVariableValueByEL(variableName, state.getVariableSet()); if (variableValue != null) { return variableValue; } if (nested) { variableValue = this.getVariableValueByEL(variableName, state.getSession()); } return variableValue; } protected Serializable getVariableValueByEL(String variableName, Session session) { Serializable variableValue = this.getVariableValueByEL(variableName, session.getVariableSet()); if (variableValue != null) { return variableValue; } return variableValue; } protected Serializable getVariableValueByEL(String variableName, Set<Variable> variableSet) { if (variableSet == null || variableName == null) { return null; } Map<String, Object> map = new HashMap<String, Object>(); for (Variable var : variableSet) { map.put(var.getName(), var.getValue()); } try { return (Serializable) MVEL.eval(variableName, map); } catch (Exception e) { } return null; } protected State getLatestState(Session session) { State lastest = null; for (State state : session.getStateSet()) { if (state == null) { continue; } if (lastest == null || lastest.getId() < state.getId()) { lastest = state; } } return lastest; } } // $Id$