From 217204c44c4a09b34610701de3afe7c6734dcc39 Mon Sep 17 00:00:00 2001 From: Andrew Branson Date: Sat, 20 Jul 2013 11:55:01 +0200 Subject: StateMachine mapfile --- .../lifecycle/instance/stateMachine/State.java | 31 +++-- .../instance/stateMachine/StateMachine.java | 77 +++++++++++-- .../instance/stateMachine/Transition.java | 125 +++++++++++++++++++-- .../instance/stateMachine/TransitionOutcome.java | 28 ++--- 4 files changed, 221 insertions(+), 40 deletions(-) (limited to 'src/main/java/com/c2kernel/lifecycle/instance/stateMachine') 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 possibleTransitionIds; - ArrayList possibleTransitions; + HashMap possibleTransitions; public State() { - possibleTransitions = new ArrayList(); - possibleTransitionIds = new ArrayList(); + possibleTransitions = new HashMap(); } 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 getPossibleTransitions() { + return possibleTransitions; + } + + protected void addPossibleTransition(Transition possibleTransition) { + possibleTransitions.put(possibleTransition.getId(), possibleTransition); + } + + public Set 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 states; private ArrayList transitions; private final HashMap 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 getPossibleTransitions(Activity act, AgentPath agent) throws ObjectNotFoundException { + HashMap returnList = new HashMap(); + 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 states) { + protected boolean resolveStates(HashMap 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; } } -- cgit v1.2.3