summaryrefslogtreecommitdiff
path: root/source/com/c2kernel/lifecycle/instance/Activity.java
diff options
context:
space:
mode:
Diffstat (limited to 'source/com/c2kernel/lifecycle/instance/Activity.java')
-rwxr-xr-xsource/com/c2kernel/lifecycle/instance/Activity.java689
1 files changed, 689 insertions, 0 deletions
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 = "<PossibleTransitions>";
+ 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 += "</PossibleTransitions>";
+ 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);
+ }
+
+}