From d43164830403245353080f5d6f838ed9f56d9a35 Mon Sep 17 00:00:00 2001 From: Andrew Branson Date: Mon, 18 Nov 2013 09:48:03 +0100 Subject: 3.0-SNAPSHOT (Will be first open source version) New StateMachine desc IssueID #28 --- .../instance/stateMachine/Transition.java | 292 +++++++++++++++++++++ 1 file changed, 292 insertions(+) create mode 100644 src/main/java/com/c2kernel/lifecycle/instance/stateMachine/Transition.java (limited to 'src/main/java/com/c2kernel/lifecycle/instance/stateMachine/Transition.java') diff --git a/src/main/java/com/c2kernel/lifecycle/instance/stateMachine/Transition.java b/src/main/java/com/c2kernel/lifecycle/instance/stateMachine/Transition.java new file mode 100644 index 0000000..9922c7c --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/instance/stateMachine/Transition.java @@ -0,0 +1,292 @@ +package com.c2kernel.lifecycle.instance.stateMachine; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +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; +import com.c2kernel.utils.Logger; + +public class Transition implements Serializable { + + int id; + String name; + + int originStateId; + int targetStateId; + State originState; + State targetState; + String reservation; + + String enabledProp; // Boolean property that permits this transition e.g. 'Skippable' + + // activation properties + boolean requiresActive = true; // Whether the activity must be active for this transition to be available + boolean finishing; // whether the target state is a finishing state; + + // permissions + String roleOverride; + + TransitionOutcome outcome; + TransitionScript script; + + public Transition() { + } + + + public Transition(int id, String name, int originStateId, int targetStateId) { + super(); + this.id = id; + this.name = name; + this.originStateId = originStateId; + this.targetStateId = targetStateId; + } + + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public State getOriginState() { + return originState; + } + + public void setOriginState(State originState) { + this.originState = originState; + } + + public State getTargetState() { + return targetState; + } + + public void setTargetState(State targetState) { + this.targetState = targetState; + finishing = targetState.finished; + } + + public String getEnabledProp() { + return enabledProp; + } + + public void setEnabledProp(String enabledProp) { + this.enabledProp = enabledProp; + } + + public boolean isRequiresActive() { + return requiresActive; + } + + public boolean isFinishing() { + return finishing; + } + + public void setRequiresActive(boolean requiresActive) { + this.requiresActive = requiresActive; + } + + public String getRoleOverride() { + return roleOverride; + } + + public void setRoleOverride(String roleOverride) { + this.roleOverride = roleOverride; + } + + public TransitionOutcome getOutcome() { + return outcome; + } + + public void setOutcome(TransitionOutcome outcome) { + this.outcome = outcome; + } + + public TransitionScript getScript() { + return script; + } + + public void setScript(TransitionScript script) { + this.script = script; + } + + public String getReservation() { + return reservation; + } + + public void setReservation(String reservation) { + this.reservation = reservation; + } + + protected boolean resolveStates(HashMap states) { + boolean allFound = true; + if (states.keySet().contains(originStateId)) { + originState = states.get(originStateId); + originState.addPossibleTransition(this); + } + else + allFound = false; + if (states.keySet().contains(targetStateId)) + targetState = states.get(targetStateId); + else + allFound = false; + return allFound; + } + + public int getOriginStateId() { + return originStateId; + } + + public void setOriginStateId(int originStateId) { + this.originStateId = originStateId; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public int getTargetStateId() { + return targetStateId; + } + + public void setTargetStateId(int targetStateId) { + this.targetStateId = targetStateId; + } + + 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", ""); + + 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 = targetState.finished?"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; + String result = key; + Pattern propField = Pattern.compile("\\$\\{(.+?)\\}"); + Matcher propMatcher = propField.matcher(result); + while (propMatcher.find()) { + String propName = propMatcher.group(1); + Object propValue = props.get(propName); + Logger.debug("Replacing Property "+propName+" as "+propValue); + String propValString = propValue==null?"":propValue.toString(); + result = result.replace("${"+propName+"}", propValString); + } + return result; + } + + public boolean isEnabled(CastorHashMap props) { + if (enabledProp == null) + return true; + return (Boolean)props.get(enabledProp); + } + + public boolean hasOutcome() { + return outcome!=null + && outcome.schemaName!=null && outcome.schemaName.length()>0 + && outcome.schemaVersion!=null && outcome.schemaVersion.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; + } + + public String getScriptName(CastorHashMap actProps) { + return resolveValue(script.scriptName, actProps); + } + + public int getScriptVersion(CastorHashMap actProps) throws InvalidDataException { + try { + return Integer.parseInt(resolveValue(script.scriptVersion, actProps)); + } catch (NumberFormatException ex) { + throw new InvalidDataException("Bad Script version number: "+script.scriptVersion+" ("+resolveValue(script.scriptVersion, actProps)); + } + } + + public boolean hasScript() { + return script!=null + && script.scriptName!=null && script.scriptName.length()>0 + && script.scriptVersion!=null && script.scriptVersion.length()>0; + } +} -- cgit v1.2.3