From 254ee6f47eebfc00462c10756a92066e82cc1a96 Mon Sep 17 00:00:00 2001 From: Andrew Branson Date: Tue, 21 Jun 2011 15:46:02 +0200 Subject: Initial commit --- .../com/c2kernel/lifecycle/instance/Activity.java | 689 +++++++++++++++++++++ 1 file changed, 689 insertions(+) create mode 100755 source/com/c2kernel/lifecycle/instance/Activity.java (limited to 'source/com/c2kernel/lifecycle/instance/Activity.java') diff --git a/source/com/c2kernel/lifecycle/instance/Activity.java b/source/com/c2kernel/lifecycle/instance/Activity.java new file mode 100755 index 0000000..458c0a5 --- /dev/null +++ b/source/com/c2kernel/lifecycle/instance/Activity.java @@ -0,0 +1,689 @@ +package com.c2kernel.lifecycle.instance; +import java.util.ArrayList; +import java.util.Vector; + +import com.c2kernel.common.AccessRightsException; +import com.c2kernel.common.GTimeStamp; +import com.c2kernel.common.InvalidDataException; +import com.c2kernel.common.InvalidTransitionException; +import com.c2kernel.common.ObjectAlreadyExistsException; +import com.c2kernel.common.ObjectNotFoundException; +import com.c2kernel.entity.agent.Job; +import com.c2kernel.events.Event; +import com.c2kernel.events.History; +import com.c2kernel.graph.model.Vertex; +import com.c2kernel.lifecycle.WfCastorHashMap; +import com.c2kernel.lifecycle.instance.stateMachine.StateMachine; +import com.c2kernel.lifecycle.instance.stateMachine.States; +import com.c2kernel.lifecycle.instance.stateMachine.Transitions; +import com.c2kernel.lookup.AgentPath; +import com.c2kernel.lookup.EntityPath; +import com.c2kernel.lookup.InvalidEntityPathException; +import com.c2kernel.lookup.LDAPRoleManager; +import com.c2kernel.lookup.RolePath; +import com.c2kernel.persistency.ClusterStorage; +import com.c2kernel.persistency.TransactionManager; +import com.c2kernel.persistency.outcome.Outcome; +import com.c2kernel.persistency.outcome.Viewpoint; +import com.c2kernel.process.Gateway; +import com.c2kernel.scripting.ScriptingEngineException; +import com.c2kernel.utils.DateUtility; +import com.c2kernel.utils.Logger; +/** + * @version $Revision: 1.222 $ $Date: 2005/10/05 07:39:37 $ + * @author $Author: abranson $ + */ +public class Activity extends WfVertex +{ + /** + * vector of errors (Strings) that is constructed each time verify() is launched + */ + protected Vector mErrors; + /** @associates a State machine engine */ + private StateMachine machine; + /** true is avalaibe to be executed */ + public boolean active = false; + /** used in verify() */ + private boolean loopTested; + //public Vector eventIds; + /** Storage of eventIds thrown by the Activity */ + public EventStorage eventIds; + private GTimeStamp mStartDate; + private GTimeStamp mActiveDate; + private String mType; + private EntityPath mEntityPath; + public Activity() + { + super(); + setProperties(new WfCastorHashMap()); + mErrors = new Vector(0, 1); + machine = new StateMachine(this); + eventIds = new EventStorage(); + mStartDate = new GTimeStamp(); + mActiveDate = new GTimeStamp(); + DateUtility.setToNow(mActiveDate); + DateUtility.setToNow(mStartDate); + } + /** @return the SystemKey of the item that contains the workflow */ + public EntityPath getItemEntityPath() + { + if (mEntityPath == null) + try + { + Integer i = (Integer) (getWf().getProperties().get("ItemSystemKey")); + if (i == null) + return null; // no item yet + EntityPath entityPath = new EntityPath(i.intValue()); + mEntityPath = entityPath; + } + catch (InvalidEntityPathException ex) + { + Logger.error("InvalidEntityPathException::Activity::getItemSystemKey() " + ex.toString()); + return null; + } + return mEntityPath; + } + /** @return the StateMachine */ + public StateMachine getMachine() + { + return machine; + } + /** sets the StateMachine (Only for Serialisation) */ + public void setMachine(StateMachine sm) + { + machine = sm; + } + /** add the activity which id is idNext as next of the current one */ + void addNext(String idNext) + { + new Next(this, (WfVertex) getParent().search(idNext)); + } + /** + * adds a New link between the current Activity and the WfVertex passed in param + */ + public Next addNext(WfVertex vertex) + { + return new Next(this, vertex); + } + /** return the current State of the State machine */ + public int getCurrentState() + { + return machine.getCurrentState(); + } + /** return the current State of the State machine (Used in Serialisation) */ + public int getState() + { + if (machine == null) + machine = new StateMachine(this); + return getCurrentState(); + } + /** Sets a new State in a State machine */ + public void setState(int stat) + { + if (machine == null) + machine = new StateMachine(this); + machine.state = stat; + } + /** check the abiltity of the agent passed in param to act on the activity */ + //return's the agentName + public String checkAccessRights(AgentPath agent) throws AccessRightsException + { + String agentID = getCurrentAgentName(); + boolean authorised = agentID.equals(agent.getAgentName()); + String actRole = getCurrentAgentRole(); + if (!authorised) + { + authorised = actRole == null || actRole.equals("") || actRole.equals("all"); + } + if (!authorised) + { + RolePath[] roles = agent.getRoles(); + for (int i = 0; !authorised && i < roles.length; i++) + { + if (roles[i].getName().equalsIgnoreCase("Admin")) + authorised = true; + if (roles[i].getName().equalsIgnoreCase(actRole)) + authorised = true; + if (roles[i].getName().equalsIgnoreCase("Guest")) + throw new AccessRightsException("Guest execution forbidden"); + } + } + if (!authorised) + throw new AccessRightsException("Activity::checkAccessRights() - Agent does not hold the correct role."); + return agent.getAgentName(); + } + /** cf Item request */ + public void request(AgentPath agent, int transitionID, String requestData) throws AccessRightsException, InvalidTransitionException, InvalidDataException, ObjectAlreadyExistsException + { + int state = getState(); + String agentName = checkAccessRights(agent); + if (machine.traverse(transitionID)) + { + setReservation(transitionID, agentName); + sendEventStoreOutcome(transitionID, requestData, agent); + if (transitionID == Transitions.REPEAT) + { + setActive(true); + if (getIsComposite()) + { + WfVertex v = (WfVertex) ((CompositeActivity) this).search(getPath() + "/" + ((CompositeActivity) this).getChildGraphModel().getStartVertexId()); + v.reinit(getID()); + try + { + runfirst(agent); + } + catch (ScriptingEngineException e) + { + Logger.error(e); + } + } + } + if (transitionID == Transitions.COMPLETE && state == States.RSTARTED) + setActive(false); + if (transitionID == Transitions.START) + start(); + if ((transitionID == Transitions.SKIP && getActive()) + || transitionID == Transitions.DONE + || (transitionID == Transitions.COMPLETE && state == States.STARTED) + || transitionID == Transitions.PROCEED) + try + { + try + { + GTimeStamp t = DateUtility.setToNow(new GTimeStamp()); + } + catch (Exception e) + { + } + runNext(agent); + } + catch (ScriptingEngineException e) + { + Logger.error(e); + } + // run post execution script now + try + { + String postSubmitScr = (String) getProperties().get("PostExecScriptName"); + String postSubmitVer = (String) getProperties().get("PostExecScriptVersion"); + if (postSubmitScr != null && (transitionID == Transitions.COMPLETE || transitionID == Transitions.DONE)) + evaluateScript(postSubmitScr, postSubmitVer); + } + catch (ScriptingEngineException ex) + { + Logger.error(ex); + } + //refresh all the job lists + pushJobsToAgents(); + } + else + throw new InvalidTransitionException("Activity is in the wrong state."); + } + public void setReservation(int transitionID, String agentName) + { + String actAgentName = (String) getProperties().get("Agent Name"); + switch (transitionID) + { + // these transition reserve the activity + case Transitions.REASSIGN : + case Transitions.RESERVE : + case Transitions.START : + actAgentName = agentName; + break; + // these clear any current reservation + case Transitions.COMPLETE : + case Transitions.DONE : + case Transitions.IGNORE : + case Transitions.SKIP : + actAgentName = ""; + // other transitions have no effect on the reservations + default : + } + getProperties().put("Agent Name", actAgentName); + } + public String getTransitions() + { + String result = ""; + int i; + for (i = 0; i < machine.possibleTransition().length; i++) + { + result += machine.possibleTransition()[i] + ","; + } + //cuts out the last comma(',') if required + if (i > 0) + { + result = result.substring(0, result.length() - 1); + } + result += ""; + return result; + } + /** launch the verification of the activity */ + public boolean verify() + { + mErrors.removeAllElements(); + int nbInEdgres = getInEdges().length; + int nbOutEdges = getOutEdges().length; + if (nbInEdgres == 0 && this.getID() != getParent().getChildrenGraphModel().getStartVertexId()) + { + mErrors.add("Unreachable"); + return false; + } + else if (nbInEdgres > 1) + { + mErrors.add("Bad nb of previous"); + return false; + } + else if (nbOutEdges > 1) + { + mErrors.add("too many next"); + return false; + } + else if (nbOutEdges == 0) + { + if (!((CompositeActivity) getParent()).hasGoodNumberOfActivity()) + { + mErrors.add("too many endpoints"); + return false; + } + } +// else +// { +// Vertex[] outV = getOutGraphables(); +// Vertex[] anteVertices = GraphTraversal.getTraversal(getParent().getChildrenGraphModel(), this, GraphTraversal.kUp, false); +// boolean errInLoop = false; +// for (int i = 0; i < outV.length; i++) +// { +// for (int j = 0; j < anteVertices.length; j++) +// if (!loop() && outV[i].getID() == anteVertices[j].getID()) +// errInLoop = true; +// } +// if (errInLoop) +// { +// mErrors.add("Error In Loop"); +// return false; +// } +// } + return true; + } + /** Used in verify() */ + public boolean loop() + { + boolean loop2 = false; + if (!loopTested) + { + loopTested = true; + if (getOutGraphables().length != 0) + loop2 = ((WfVertex) getOutGraphables()[0]).loop(); + } + loopTested = false; + return loop2; + } + /** sets the next activity available if possible */ + public void runNext(AgentPath agent) throws ScriptingEngineException + { + setActive(false); + try + { + Vertex[] outVertices = getOutGraphables(); + Vertex[] outVertices2 = getOutGraphables(); + boolean hasNoNext = false; + boolean out = false; + while (!out) + if (outVertices2.length > 0) + { + if (outVertices2[0] instanceof Join) + outVertices2 = ((WfVertex) outVertices2[0]).getOutGraphables(); + else + out = true; + } + else + { + hasNoNext = true; + out = true; + } + Logger.debug(8, outVertices + " " + outVertices2); + if (!hasNoNext) + ((WfVertex) outVertices[0]).run(agent); + else + { + if (getParent() != null && getParent().getName().equals("domain")) // workflow + // finished + setActive(true); + else + { + CompositeActivity parent = (CompositeActivity) getParent(); + if (parent != null) + parent.runNext(agent); + } + } + } + catch (ScriptingEngineException s) + { + setActive(true); + throw s; + } + } + /** @return the only Next of the Activity */ + public Next getNext() + { + if (getOutEdges().length > 0) + return (Next) getOutEdges()[0]; + else + return null; + } + /** reinitialises the Activity and propagate (for Loop) */ + public void reinit(int idLoop) + { + Logger.debug(7, "reinit " + getItemEntityPath().getSysKey() + " " + getPath()); + Vertex[] outVertices = getOutGraphables(); + machine.state = States.WAITING; + if (outVertices.length > 0) + { + WfVertex nextAct = (WfVertex) outVertices[0]; + nextAct.reinit(idLoop); + } + } + /** return the String that identifies the errors found in th activity */ + public String getErrors() + { + String errors = ""; + if (mErrors.size() == 0) + return "No error"; + return (String) mErrors.elementAt(0); + } + /** + * called by precedent Activity runNext() for setting the activity able to be executed + */ + public void run(AgentPath agent) throws ScriptingEngineException + { + Logger.debug(8, getPath() + " run " + getCurrentState()); + if (!getActive()) + setActive(true); + + if (getMachine().getCurrentState() == States.FINISHED) + { + runNext(agent); + } + else + { + DateUtility.setToNow(mActiveDate); + if (((Boolean) getProperties().get(StateMachine.AUTOSTART)).booleanValue() && machine.state == States.WAITING) + { + machine.traverse(Transitions.START); + start(); + } + pushJobsToAgents(); + } + } + /** + * sets the activity available to be executed on start of Workflow or composite activity (when it is the first one of the (sub)process + */ + public void runfirst(AgentPath agent) throws ScriptingEngineException + { + Logger.debug(8, getPath() + " runfirst"); + run(agent); + } + /** @return the current ability to be executed */ + public boolean getActive() + { + return active; + } + /** sets the ability to be executed */ + public void setActive(boolean acti) + { + active = acti; + } + /** @return the Description field of properties */ + public String getDescription() + { + if (getProperties().containsKey("Description")) + return (String) (getProperties().get("Description")); + return "No description"; + } + public String getCurrentAgentName() + { + return (String) getProperties().get("Agent Name"); + } + public String getCurrentAgentRole() + { + return (String) getProperties().get("Agent Role"); + } + /** + * @return an array of Steps that matches the querry + * @param agentID + * Agent concerned by the query + * @param agentRole + * Agent concerned by the query @int stateID state to test in the query, use -1 for all + * @param filter + * if tru will be filtered by agent, else won't + */ + public Activity[] query(AgentPath agent, int stateID, boolean filter) + { + if (getCurrentState() == stateID || stateID == -1) + { + Activity[] steps = { this }; + if (!filter) + return steps; + else + { + try + { + checkAccessRights(agent); + return steps; + } + catch (AccessRightsException e) + { + //case that agent is not allowed + Logger.msg(7, "Activity :: AccessRightsException in " + this.getItemEntityPath() + "/" + this.getPath()); + } + } + } + return new Activity[0]; + } + /** + * returns the lists of jobs for the activity and children (cf com.c2kernel.entity.Job) + */ + public ArrayList calculateJobs(AgentPath agent, boolean recurse) + { + return calculateJobsBase(agent, false); + } // + public ArrayList calculateAllJobs(AgentPath agent, boolean recurse) + { + return calculateJobsBase(agent, true); + } + private ArrayList calculateJobsBase(AgentPath agent, boolean all) + { + Logger.msg(7, "calculateJobs - " + getPath()); + int[] transitions = { + }; + ArrayList jobs = new ArrayList(); + try + { + String agentName = checkAccessRights(agent); + String currentAgentName = getCurrentAgentName(); + boolean isCurrent = currentAgentName == null || currentAgentName.equals("") || agentName.equals(currentAgentName); + if ((all || getActive()) && !getName().equals("domain")) + transitions = machine.possibleTransition(); + Logger.msg(7, "Activity.calculateJobs() - Got " + transitions.length + " transitions."); + for (int i = 0; i < transitions.length; i++) + { + Logger.msg(7, "Creating Job object for transition " + transitions[i]); + if ((isCurrent && !(transitions[i] == Transitions.REASSIGN && agentName.equals(currentAgentName))) || (transitions[i] == Transitions.REASSIGN && !agentName.equals(currentAgentName))) + jobs.add(new Job(getItemEntityPath().getSysKey(), getPath(), transitions[i], getCurrentState(), machine.simulate(transitions[i]), getName(), getProperties(), getType(), agentName)); + } + } + catch (AccessRightsException ex) + { + Logger.msg(6, "Agent "+ agent.getAgentName() +" is not allowed to interact with "+getItemEntityPath().getSysKey()+":"+getPath()); + } // empty joblist then + return jobs; + } + // + //methods written by kovax + // + /** Adds an event to the AuditTrail of the Item if any */ + private Event auditEvent(int transitionID, AgentPath agent) + { + EntityPath entityPath = getItemEntityPath(); + if (entityPath != null) + { + Event event = null; + History hist = null; + try + { + hist = (History) Gateway.getStorage().get(entityPath.getSysKey(), ClusterStorage.HISTORY, this); + event = hist.addEvent(agent.getAgentName(), getCurrentAgentRole(), transitionID, getName(), getPath(), getType(), getCurrentState()); + Logger.msg(7, "Activity::auditEvent() - Event:" + event.getName() + " was added to the AuditTrail"); + } + catch (Exception ex) + { + Logger.error("Activity::auditEvent() - Item '" + entityPath.toString() + "'!"); + Logger.error(ex); + } + return event; + } + else + return null; + } /** + * Stores the request data as an outcome of the Item It does a great deal of storing outcomes in different configuration + */ //requestdata is xmlstring + private String storeOutcome(int eventID, String requestData) + { + EntityPath entityPath = getItemEntityPath(); + if (entityPath != null) + { + String schemaType = (String) getProperties().get("SchemaType"); + if (schemaType == null || schemaType.length() == 0) // no + // outcome + // required + return null; + int schemaVersion = 0; + String versionString = (String) getProperties().get("SchemaVersion"); + try + { + schemaVersion = Integer.parseInt(versionString); + } + catch (Exception e) + { + Logger.error("Activity.storeOutcome() - invalid schemaVersion " + versionString); + } + Logger.msg(5, "Activity::storeOutcome() - type:" + schemaType + " version:" + schemaVersion); + try + { + Outcome newOutcome = new Outcome(eventID, requestData, schemaType, schemaVersion); + Gateway.getStorage().put(entityPath.getSysKey(), newOutcome, this); + // update specific view if defined + String specificView = (String) getProperties().get("Viewpoint"); + if (specificView != null && !specificView.equals("")) + { + Viewpoint currentView = new Viewpoint(entityPath.getSysKey(), schemaType, specificView, schemaVersion, eventID); + Gateway.getStorage().put(entityPath.getSysKey(), currentView, this); + } // update last view + Viewpoint currentView = new Viewpoint(entityPath.getSysKey(), schemaType, "last", schemaVersion, eventID); + Gateway.getStorage().put(entityPath.getSysKey(), currentView, this); + return schemaType + "/" + schemaVersion + "/" + eventID; + } + catch (Exception ex) + { + Logger.error("ActivityBase::storeOutcome() - Item '" + entityPath.toString() + "'!"); + Logger.error(ex); + } + return null; + } + else + return null; + } /** the method to be called by the requestAction() method */ + public void sendEventStoreOutcome(int transitionID, String requestData, AgentPath agent) + { + int eventID = -1; + Event event = null; + event = auditEvent(transitionID, agent); + if (event != null) + eventID = event.getID(); + if (Boolean.TRUE.equals(getProperties().get("AlwaysUseOutcome")) || transitionID == Transitions.DONE || transitionID == Transitions.COMPLETE) + storeOutcome(eventID, requestData); + EntityPath entityPath = getItemEntityPath(); + TransactionManager storage = Gateway.getStorage(); + if (entityPath != null) + { + storage.commit(this); + } + } + public void pushJobsToAgents() + { + String agentRole = getCurrentAgentRole(); + if (agentRole == null || agentRole.length()==0) return; + + LDAPRoleManager roleMan = Gateway.getLDAPLookup().getRoleManager(); + RolePath myRole; + try { + myRole = roleMan.getRolePath(agentRole); + } catch (ObjectNotFoundException ex) { // non-existent role + Logger.msg(7, "Activity.pushJobsToAgents() - Activity role '"+agentRole+" not found."); + return; + } + + if (myRole.hasJobList()) + new JobPusher(this, myRole).start(); + } + + + /** + * Returns the activeDate. + * + * @return GTimeStamp + */ + public GTimeStamp getActiveDate() + { + return mActiveDate; + } /** + * Returns the startDate. + * + * @return GTimeStamp + */ + public GTimeStamp getStartDate() + { + return mStartDate; + } /** + * Sets the activeDate. + * + * @param activeDate + * The activeDate to set + */ + public void setActiveDate(GTimeStamp activeDate) + { + mActiveDate = activeDate; + } /** + * Sets the startDate. + * + * @param startDate + * The startDate to set + */ + public void setStartDate(GTimeStamp startDate) + { + mStartDate = startDate; + } /** + * Returns the type. + * + * @return String + */ + public String getType() + { + return mType; + } /** + * Sets the type. + * + * @param type + * The type to set + */ + public void setType(String type) + { + mType = type; + } + private void start() + { + Logger.debug(8, getPath() + " start"); + DateUtility.setToNow(mStartDate); + } + +} -- cgit v1.2.3