summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Branson <andrew.branson@cern.ch>2013-07-20 11:55:01 +0200
committerAndrew Branson <andrew.branson@cern.ch>2013-09-16 12:39:15 +0200
commit217204c44c4a09b34610701de3afe7c6734dcc39 (patch)
treeef24ddc673d768244b220e8954fcfe5f08608525
parentbce2990a1434bf78e85adbfc66cec1a402342f3c (diff)
StateMachine mapfile
-rw-r--r--src/main/java/com/c2kernel/lifecycle/instance/stateMachine/State.java31
-rw-r--r--src/main/java/com/c2kernel/lifecycle/instance/stateMachine/StateMachine.java77
-rw-r--r--src/main/java/com/c2kernel/lifecycle/instance/stateMachine/Transition.java125
-rw-r--r--src/main/java/com/c2kernel/lifecycle/instance/stateMachine/TransitionOutcome.java28
-rw-r--r--src/main/resources/boot/OD/StateMachine.xsd51
-rw-r--r--src/main/resources/boot/SM/Default.xml17
-rw-r--r--src/main/resources/mapFiles/StateMachineMap.xml94
-rw-r--r--src/main/resources/mapFiles/index1
8 files changed, 343 insertions, 81 deletions
diff --git a/src/main/java/com/c2kernel/lifecycle/instance/stateMachine/State.java b/src/main/java/com/c2kernel/lifecycle/instance/stateMachine/State.java
index b4488c0..8ad53bb 100644
--- a/src/main/java/com/c2kernel/lifecycle/instance/stateMachine/State.java
+++ b/src/main/java/com/c2kernel/lifecycle/instance/stateMachine/State.java
@@ -1,20 +1,19 @@
package com.c2kernel.lifecycle.instance.stateMachine;
import java.io.Serializable;
-import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Set;
public class State implements Serializable {
- int code;
+ int id;
String name;
boolean proceeds = false; // If true, this state deactivates the current activity and the lifecycle proceeds
- ArrayList<Integer> possibleTransitionIds;
- ArrayList<Transition> possibleTransitions;
+ HashMap<Integer, Transition> possibleTransitions;
public State() {
- possibleTransitions = new ArrayList<Transition>();
- possibleTransitionIds = new ArrayList<Integer>();
+ possibleTransitions = new HashMap<Integer, Transition>();
}
public String getName() {
@@ -26,12 +25,12 @@ public class State implements Serializable {
}
- public int getCode() {
- return code;
+ public int getId() {
+ return id;
}
- public void setCode(int code) {
- this.code = code;
+ public void setId(int id) {
+ this.id = id;
}
public boolean isProceeds() {
@@ -41,4 +40,16 @@ public class State implements Serializable {
public void setProceeds(boolean proceeds) {
this.proceeds = proceeds;
}
+
+ public HashMap<Integer, Transition> getPossibleTransitions() {
+ return possibleTransitions;
+ }
+
+ protected void addPossibleTransition(Transition possibleTransition) {
+ possibleTransitions.put(possibleTransition.getId(), possibleTransition);
+ }
+
+ public Set<Integer> getPossibleTransitionIds() {
+ return possibleTransitions.keySet();
+ }
}
diff --git a/src/main/java/com/c2kernel/lifecycle/instance/stateMachine/StateMachine.java b/src/main/java/com/c2kernel/lifecycle/instance/stateMachine/StateMachine.java
index 29ad7da..6d8033c 100644
--- a/src/main/java/com/c2kernel/lifecycle/instance/stateMachine/StateMachine.java
+++ b/src/main/java/com/c2kernel/lifecycle/instance/stateMachine/StateMachine.java
@@ -1,15 +1,23 @@
package com.c2kernel.lifecycle.instance.stateMachine;
-import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.Map;
-public class StateMachine implements Serializable
+import com.c2kernel.common.AccessRightsException;
+import com.c2kernel.common.InvalidTransitionException;
+import com.c2kernel.common.ObjectNotFoundException;
+import com.c2kernel.lifecycle.instance.Activity;
+import com.c2kernel.lookup.AgentPath;
+import com.c2kernel.utils.DescriptionObject;
+import com.c2kernel.utils.Logger;
+
+public class StateMachine implements DescriptionObject
{
- public String machineName;
- public int machineVersion;
-
+ public String name;
+ public String version;
+
private ArrayList<State> states;
private ArrayList<Transition> transitions;
private final HashMap<String, State> stateNames;
@@ -47,7 +55,7 @@ public class StateMachine implements Serializable
transitionCodes.clear();
for (Transition trans : transitions) {
- transitionCodes.put(trans.getCode(), trans);
+ transitionCodes.put(trans.getId(), trans);
}
}
@@ -65,7 +73,7 @@ public class StateMachine implements Serializable
public void setInitialState(State initialState) {
this.initialState = initialState;
- initialStateCode = initialState.getCode();
+ initialStateCode = initialState.getId();
}
public int getInitialStateCode() {
@@ -77,4 +85,59 @@ public class StateMachine implements Serializable
initialState = stateCodes.get(initialStateCode);
if (initialState == null) isCoherent = false;
}
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public String getVersion() {
+ return version;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public void setVersion(String version) {
+ this.version = version;
+ }
+
+ public Transition getTransition(int transitionID) {
+ return transitionCodes.get(transitionID);
+ }
+
+ public State getState(int stateID) {
+ return stateCodes.get(stateID);
+ }
+
+ public Map<Transition, String> getPossibleTransitions(Activity act, AgentPath agent) throws ObjectNotFoundException {
+ HashMap<Transition, String> returnList = new HashMap<Transition, String>();
+ State currentState = getState(act.getState());
+ for (Integer transCode : currentState.getPossibleTransitionIds()) {
+ Transition possTrans = currentState.getPossibleTransitions().get(transCode);
+ try {
+ String role = possTrans.getPerformingRole(act, agent);
+ returnList.put(possTrans, role);
+ } catch (AccessRightsException ex) {
+ if (Logger.doLog(5))
+ Logger.msg(5, "Transition '"+possTrans+"' not possible for "+agent.getAgentName()+": "+ex.getMessage());
+ }
+ }
+ return returnList;
+ }
+
+ public State traverse(Activity act, Transition transition, AgentPath agent) throws InvalidTransitionException, AccessRightsException, ObjectNotFoundException {
+ State currentState = getState(act.getState());
+ if (transition.originState.equals(currentState)) {
+ transition.getPerformingRole(act, agent);
+ return transition.terminalState;
+ }
+ else
+ throw new InvalidTransitionException();
+
+ }
+
+
} \ No newline at end of file
diff --git a/src/main/java/com/c2kernel/lifecycle/instance/stateMachine/Transition.java b/src/main/java/com/c2kernel/lifecycle/instance/stateMachine/Transition.java
index 36a3d50..471e72c 100644
--- a/src/main/java/com/c2kernel/lifecycle/instance/stateMachine/Transition.java
+++ b/src/main/java/com/c2kernel/lifecycle/instance/stateMachine/Transition.java
@@ -3,17 +3,27 @@ package com.c2kernel.lifecycle.instance.stateMachine;
import java.io.Serializable;
import java.util.HashMap;
+import com.c2kernel.common.AccessRightsException;
+import com.c2kernel.common.InvalidDataException;
+import com.c2kernel.common.ObjectNotFoundException;
+import com.c2kernel.lifecycle.instance.Activity;
+import com.c2kernel.lookup.AgentPath;
+import com.c2kernel.lookup.RolePath;
+import com.c2kernel.persistency.outcome.Schema;
+import com.c2kernel.process.Gateway;
import com.c2kernel.utils.CastorHashMap;
+import com.c2kernel.utils.LocalObjectLoader;
public class Transition implements Serializable {
- int code;
+ int id;
String name;
int originStateCode;
int terminalStateCode;
State originState;
State terminalState;
+ String reservation;
String enabledProp; // Boolean property that permits this transition e.g. 'Skippable'
@@ -26,6 +36,9 @@ public class Transition implements Serializable {
TransitionOutcome outcome;
TransitionScript script;
+ public Transition() {
+ }
+
public String getName() {
return name;
}
@@ -89,14 +102,21 @@ public class Transition implements Serializable {
public void setScript(TransitionScript script) {
this.script = script;
}
+
+ public String getReservation() {
+ return reservation;
+ }
- public Transition() {
+ public void setReservation(String reservation) {
+ this.reservation = reservation;
}
- public boolean resolveStates(HashMap<String, State> states) {
+ protected boolean resolveStates(HashMap<String, State> states) {
boolean allFound = true;
- if (states.keySet().contains(originStateCode))
+ if (states.keySet().contains(originStateCode)) {
originState = states.get(originStateCode);
+ originState.addPossibleTransition(this);
+ }
else
allFound = false;
if (states.keySet().contains(terminalStateCode))
@@ -114,12 +134,12 @@ public class Transition implements Serializable {
this.originStateCode = originStateCode;
}
- public int getCode() {
- return code;
+ public int getId() {
+ return id;
}
- public void setCode(int code) {
- this.code = code;
+ public void setId(int id) {
+ this.id = id;
}
public int getTerminalStateCode() {
@@ -129,10 +149,97 @@ public class Transition implements Serializable {
public void setTerminalStateCode(int terminalStateCode) {
this.terminalStateCode = terminalStateCode;
}
-
+
+ public String getPerformingRole(Activity act, AgentPath agent) throws ObjectNotFoundException, AccessRightsException {
+
+ // check available
+ if (!isEnabled(act.getProperties()))
+ throw new AccessRightsException("Transition '"+name+"' is disabled by the '"+enabledProp+"' property.");
+
+ // check active
+ if (isRequiresActive() && !act.getActive())
+ throw new AccessRightsException("Activity must be active to perform this transition", null);
+
+ RolePath role = null;
+ String overridingRole = resolveValue(roleOverride, act.getProperties());
+ boolean override = overridingRole != null;
+ boolean isOwner = false, isOwned = true;
+
+ // Check agent name
+ String agentName = act.getCurrentAgentName();
+ if (agentName != null && agentName.length() >0) {
+ if (agent.getAgentName().equals(agentName))
+ isOwner = true;
+ }
+ else isOwned = false;
+
+ // determine transition role
+ if (override) {
+ role = Gateway.getLDAPLookup().getRoleManager().getRolePath(overridingRole);
+ }
+ else {
+ String actRole = act.getCurrentAgentRole();
+ if (actRole != null && actRole.length() > 0)
+ role = Gateway.getLDAPLookup().getRoleManager().getRolePath(actRole);
+ }
+
+ // Decide the access
+ if (isOwned && !override && !isOwner)
+ throw new AccessRightsException("Agent '"+agent.getAgentName()
+ +"' cannot perform this transition because the activity '"+act.getName()+"' is currently owned by "+agentName, null);
+
+ if (role != null) {
+ if (agent.hasRole(role))
+ return role.getName();
+ else if (agent.hasRole("Admin"))
+ return "Admin";
+ else
+ throw new AccessRightsException("Agent '"+agent.getAgentName()
+ +"' does not hold a suitable role '"+role.getName()+"' for the activity "+act.getName(), null);
+ }
+ else
+ return null;
+ }
+
+ public String getReservation(Activity act, AgentPath agent) {
+ if (reservation == null || reservation.length() == 0)
+ reservation = terminalState.proceeds?"clear":"set";
+
+ String reservedAgent = act.getCurrentAgentName();
+ if (reservation.equals("set"))
+ reservedAgent = agent.getAgentName();
+ else if (reservation.equals("clear"))
+ reservedAgent = "";
+ return reservedAgent;
+
+ }
+
+ private static String resolveValue(String key, CastorHashMap props) {
+ if (key==null) return null;
+ if (key.startsWith("$"))
+ return (String)props.get(key.substring(1));
+ return key;
+ }
+
public boolean isEnabled(CastorHashMap props) {
if (enabledProp == null)
return true;
return (Boolean)props.get(enabledProp);
}
+
+ public boolean hasOutcome() {
+ return outcome.schemaName!=null && outcome.schemaName.length()>0;
+ }
+
+ public Schema getSchema(CastorHashMap actProps) throws InvalidDataException, ObjectNotFoundException {
+ if (hasOutcome())
+ try {
+ return LocalObjectLoader.getSchema(resolveValue(outcome.schemaName, actProps),
+ Integer.parseInt(resolveValue(outcome.schemaVersion, actProps)));
+ } catch (NumberFormatException ex) {
+ throw new InvalidDataException("Bad schema version number: "+outcome.schemaVersion+" ("+resolveValue(outcome.schemaVersion, actProps));
+ }
+ else
+ return null;
+ }
}
diff --git a/src/main/java/com/c2kernel/lifecycle/instance/stateMachine/TransitionOutcome.java b/src/main/java/com/c2kernel/lifecycle/instance/stateMachine/TransitionOutcome.java
index 9646bc3..71ba3b3 100644
--- a/src/main/java/com/c2kernel/lifecycle/instance/stateMachine/TransitionOutcome.java
+++ b/src/main/java/com/c2kernel/lifecycle/instance/stateMachine/TransitionOutcome.java
@@ -3,34 +3,34 @@ package com.c2kernel.lifecycle.instance.stateMachine;
public class TransitionOutcome extends TransitionResource {
// schema properties
- String outcomeSchemaName, outcomeSchemaVersion; // Name & version of the schema of the data required for this transition.
- boolean outcomeRequired = true; // If true, then the data must be supplied to perform the transition, otherwise it is optional
+ String schemaName, schemaVersion; // Name & version of the schema of the data required for this transition.
+ boolean required = true; // If true, then the data must be supplied to perform the transition, otherwise it is optional
public TransitionOutcome() {
}
- public String getOutcomeSchemaName() {
- return outcomeSchemaName;
+ public String getSchemaName() {
+ return schemaName;
}
- public void setOutcomeSchemaName(String outcomeSchemaName) {
- this.outcomeSchemaName = outcomeSchemaName;
+ public void setSchemaName(String schemaName) {
+ this.schemaName = schemaName;
}
- public String getOutcomeSchemaVersion() {
- return outcomeSchemaVersion;
+ public String getSchemaVersion() {
+ return schemaVersion;
}
- public void setOutcomeSchemaVersion(String outcomeSchemaVersion) {
- this.outcomeSchemaVersion = outcomeSchemaVersion;
+ public void setSchemaVersion(String schemaVersion) {
+ this.schemaVersion = schemaVersion;
}
- public boolean isOutcomeRequired() {
- return outcomeRequired;
+ public boolean isRequired() {
+ return required;
}
- public void setOutcomeRequired(boolean outcomeRequired) {
- this.outcomeRequired = outcomeRequired;
+ public void setRequired(boolean required) {
+ this.required = required;
}
}
diff --git a/src/main/resources/boot/OD/StateMachine.xsd b/src/main/resources/boot/OD/StateMachine.xsd
new file mode 100644
index 0000000..f21e39d
--- /dev/null
+++ b/src/main/resources/boot/OD/StateMachine.xsd
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
+ <xs:element name="StateMachine">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="State" maxOccurs="unbounded">
+ <xs:complexType>
+ <xs:attribute name="id" type="xs:int" use="required"/>
+ <xs:attribute name="name" type="xs:string" use="required"/>
+ <xs:attribute name="proceeds" type="xs:string"/>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="Transition" maxOccurs="unbounded">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="Outcome">
+ <xs:complexType>
+ <xs:attribute name="name" type="xs:string" use="required"/>
+ <xs:attribute name="version" type="xs:string" use="required"/>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="Script">
+ <xs:complexType>
+ <xs:attribute name="name" type="xs:string" use="required"/>
+ <xs:attribute name="version" type="xs:string" use="required"/>
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ <xs:attribute name="id" type="xs:int" use="required"/>
+ <xs:attribute name="name" type="xs:string" use="required"/>
+ <xs:attribute name="origin" type="xs:int" use="required"/>
+ <xs:attribute name="terminus" type="xs:int" use="required"/>
+ <xs:attribute name="enablingProperty" type="xs:string"/>
+ <xs:attribute name="roleOverride" type="xs:string"/>
+ <xs:attribute name="reservation">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="set"/>
+ <xs:enumeration value="clear"/>
+ <xs:enumeration value="preserve"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ <xs:attribute name="initialState" type="xs:string"/>
+ </xs:complexType>
+ </xs:element>
+</xs:schema>
+
diff --git a/src/main/resources/boot/SM/Default.xml b/src/main/resources/boot/SM/Default.xml
new file mode 100644
index 0000000..237506e
--- /dev/null
+++ b/src/main/resources/boot/SM/Default.xml
@@ -0,0 +1,17 @@
+<StateMachine initialState="0">
+ <State id="0" name="Waiting"/>
+ <State id="1" name="Finished" proceeds="true"/>
+ <State id="2" name="Suspended"/>
+
+ <Transition id="0" name="Done" origin="0" terminus="1">
+ <Outcome name="${SchemaType}" version="${SchemaVersion}"/>
+ <Script name="${ScriptName}" version="${ScriptVersion}"/>
+ </Transition>
+ <Transition id="1" name="Suspend" origin="0" terminus="2">
+ <Outcome name="Errors" version="0"/>
+ </Transition>
+ <Transition id="2" name="Retry" origin="2" terminus="0" roleOverride="Admin"/>
+</StateMachine>
+
+
+
diff --git a/src/main/resources/mapFiles/StateMachineMap.xml b/src/main/resources/mapFiles/StateMachineMap.xml
index cab2c89..fb13789 100644
--- a/src/main/resources/mapFiles/StateMachineMap.xml
+++ b/src/main/resources/mapFiles/StateMachineMap.xml
@@ -1,69 +1,81 @@
<?xml version="1.0"?>
<mapping>
<class name="com.c2kernel.lifecycle.instance.stateMachine.StateMachine">
- <map-to xml="StateMachine"/>
- <field name="states"
- type="com.c2kernel.lifecycle.instance.stateMachine.State"
- collection="arraylist"
- container="true"
- direct="false">
- <bind-xml name="States" node="element"/>
- </field>
- <field name="transitions"
- type="com.c2kernel.lifecycle.instance.stateMachine.Transition"
- collection="arraylist"
- container="true"
- direct="false">
- <bind-xml name="Transitions" node="element"/>
+ <map-to xml="StateMachine" />
+ <field name="states" type="com.c2kernel.lifecycle.instance.stateMachine.State"
+ collection="arraylist" container="false" direct="false">
+ <bind-xml name="State" node="element" />
+ </field>
+ <field name="transitions"
+ type="com.c2kernel.lifecycle.instance.stateMachine.Transition"
+ collection="arraylist" container="false" direct="false">
+ <bind-xml name="Transition" node="element" />
</field>
<field name="initialStateCode" type="integer">
- <bind-xml name="initialState" node="attribute"/>
+ <bind-xml name="initialState" node="attribute" />
</field>
</class>
<class name="com.c2kernel.lifecycle.instance.stateMachine.State">
- <map-to xml="State"/>
- <field name="id" type="integer" direct="false">
- <bind-xml name="id" node="attribute"/>
+ <field name="code" type="integer" direct="false">
+ <bind-xml name="code" node="attribute" />
</field>
<field name="name" type="string" direct="false">
- <bind-xml name="name" node="attribute"/>
+ <bind-xml name="name" node="attribute" />
</field>
<field name="proceeds" type="boolean" direct="false">
- <bind-xml name="proceeds" node="attribute"/>
+ <bind-xml name="proceeds" node="attribute" />
</field>
</class>
<class name="com.c2kernel.lifecycle.instance.stateMachine.Transition">
- <map-to xml="Transition"/>
- <field name="id" type="integer" direct="false">
- <bind-xml name="id" node="attribute"/>
+ <field name="code" type="integer" direct="false">
+ <bind-xml name="code" node="attribute" />
</field>
<field name="name" type="string" direct="false">
- <bind-xml name="name" node="attribute"/>
- </field>
- int originStateCode;
- int terminalStateCode;
- String enabledProp;
- String roleOverride;
- outcome;
- script;
+ <bind-xml name="name" node="attribute" />
+ </field>
<field name="originStateCode" type="integer" direct="false">
- <bind-xml name="origin" node="attribute"/>
+ <bind-xml name="origin" node="attribute" />
</field>
<field name="terminalStateCode" type="integer" direct="false">
- <bind-xml name="terminus" node="attribute"/>
+ <bind-xml name="terminus" node="attribute" />
</field>
<field name="enabledProp" type="string" direct="false">
- <bind-xml name="enablingProperty" node="attribute"/>
+ <bind-xml name="enablingProperty" node="attribute" />
</field>
<field name="roleOverride" type="string" direct="false">
- <bind-xml name="roleOverride" node="attribute"/>
- </field>
- <field name="outcome" type="TransitionOutcome" direct="false">
- <bind-xml name="Outcome" node="element"/>
+ <bind-xml name="roleOverride" node="attribute" />
</field>
- <field name="script" type="TransitionScript" direct="false">
- <bind-xml name="Script" node="element"/>
+ <field name="reservation" type="string" direct="false">
+ <bind-xml name="reservation" node="attribute" />
</field>
+ <field name="outcome"
+ type="com.c2kernel.lifecycle.instance.stateMachine.TransitionOutcome"
+ direct="false" container="false">
+ <bind-xml name="Outcome" node="element" />
+ </field>
+ <field name="script"
+ type="com.c2kernel.lifecycle.instance.stateMachine.TransitionScript"
+ direct="false" container="false">
+ <bind-xml name="Script" node="element" />
+ </field>
+ </class>
+ <class name="com.c2kernel.lifecycle.instance.stateMachine.TransitionOutcome">
+ <field name="schemaName" type="string" direct="false">
+ <bind-xml name="name" node="attribute" />
+ </field>
+ <field name="schemaVersion" type="string" direct="false">
+ <bind-xml name="version" node="attribute" />
+ </field>
+ <field name="required" type="boolean" direct="false">
+ <bind-xml name="required" node="attribute" />
+ </field>
+ </class>
+ <class name="com.c2kernel.lifecycle.instance.stateMachine.TransitionScript">
+ <field name="scriptName" type="string" direct="false">
+ <bind-xml name="name" node="attribute" />
+ </field>
+ <field name="scriptVersion" type="string" direct="false">
+ <bind-xml name="version" node="attribute" />
+ </field>
</class>
-
</mapping>
diff --git a/src/main/resources/mapFiles/index b/src/main/resources/mapFiles/index
index 25fef77..4e378e4 100644
--- a/src/main/resources/mapFiles/index
+++ b/src/main/resources/mapFiles/index
@@ -9,3 +9,4 @@ ViewpointMap.xml
TransferMap.xml
NewEntityMap.xml
ModuleMap.xml
+StateMachineMap.xml