Index: modules/jpdl/src/main/java/org/jbpm/jpdl/internal/activity/JmsActivity.java =================================================================== --- modules/jpdl/src/main/java/org/jbpm/jpdl/internal/activity/JmsActivity.java (revision 6436) +++ modules/jpdl/src/main/java/org/jbpm/jpdl/internal/activity/JmsActivity.java (working copy) @@ -55,7 +55,6 @@ import org.jbpm.internal.log.Log; import org.jbpm.pvm.internal.el.Expression; import org.jbpm.pvm.internal.model.ExecutionImpl; -import org.jbpm.pvm.internal.script.ScriptManager; import org.jbpm.pvm.internal.wire.Descriptor; import org.jbpm.pvm.internal.wire.WireContext; import org.jbpm.pvm.internal.wire.descriptor.MapDescriptor; Index: modules/jpdl/src/test/java/org/jbpm/jpdl/parsing/TaskParsingTest.java =================================================================== --- modules/jpdl/src/test/java/org/jbpm/jpdl/parsing/TaskParsingTest.java (revision 6436) +++ modules/jpdl/src/test/java/org/jbpm/jpdl/parsing/TaskParsingTest.java (working copy) @@ -5,10 +5,12 @@ import org.jbpm.jpdl.internal.activity.TaskActivity; import org.jbpm.pvm.internal.client.ClientProcessDefinition; import org.jbpm.pvm.internal.el.Expression; -import org.jbpm.pvm.internal.el.StaticTextExpression; import org.jbpm.pvm.internal.model.ActivityImpl; import org.jbpm.pvm.internal.task.TaskDefinitionImpl; +/** + * @author Huisheng Xu + */ public class TaskParsingTest extends JpdlParseTestCase { public void testTaskParse() { @@ -33,8 +35,8 @@ TaskDefinitionImpl taskDefinition = taskActivity.getTaskDefinition(); // check for properties not previously parsed - StaticTextExpression descriptionExpression = (StaticTextExpression) taskDefinition.getDescription(); - assertEquals("first task", descriptionExpression.getText()); + Expression descriptionExpression = taskDefinition.getDescription(); + assertEquals("first task", descriptionExpression.getExpressionString()); assertEquals(3, taskDefinition.getPriority()); assertEquals("aForm", taskDefinition.getFormResourceName()); assertEquals("1 day", taskDefinition.getDueDateDescription()); Index: modules/pvm/src/main/java/org/jbpm/pvm/internal/cal/Duration.java =================================================================== --- modules/pvm/src/main/java/org/jbpm/pvm/internal/cal/Duration.java (revision 6436) +++ modules/pvm/src/main/java/org/jbpm/pvm/internal/cal/Duration.java (working copy) @@ -31,26 +31,28 @@ import java.util.regex.Pattern; import org.jbpm.api.JbpmException; +import org.jbpm.pvm.internal.el.Expression; import org.jbpm.pvm.internal.env.EnvironmentImpl; -import org.jbpm.pvm.internal.script.ScriptManager; import org.jbpm.pvm.internal.util.Clock; /** * represents a time duration. - * - *

With the constructor {link {@link #Duration(String)} you can create a + * + *

With the constructor {link {@link #Duration(String)} you can create a * Duration from a text representation. The syntax is as follows *

- * + * *
  * duration = part [',' part | 'and' part]*
  * part = number ['business'] unit
  * number = (0..9)+
  * unit = (y|year|years|month|months|w|week|weeks|d|day|days|h|hour|hours|min|minute|minutes|s|sec|second|seconds|milli|millis|millisecond|milliseconds)
  * 
- * + * *

Duration is immutable. *

+ * + * @author Huisheng Xu */ public class Duration implements Serializable { @@ -65,12 +67,12 @@ protected int weeks; protected int months; protected int years; - + private final static String dateFormat = "yyyy-MM-dd HH:mm:ss"; - + private static final Pattern dateDurationPattern = Pattern.compile("\\s*(#\\{.+\\})\\s*" + "(?:(\\+|-)\\s*(\\d+\\s+(?:business\\s+)?\\w+))?\\s*"); - + private static final Pattern durationPattern = Pattern.compile("\\s*(\\d+\\s+(?:business\\s+)?" + "\\w+)\\s*"); @@ -78,13 +80,13 @@ protected Duration() { } - /** parses the duration from a text - * + /** parses the duration from a text + * * duration = part [',' part | 'and' part]* * part = number ['business'] unit * number = (0..9)+ * unit = (y|year|years|month|months|w|week|weeks|d|day|days|h|hour|hours|min|minute|minutes|s|sec|second|seconds|milli|millis|millisecond|milliseconds) - * + * * @throws JbpmException if the parsing is unsuccessful */ public Duration(String text) { @@ -93,23 +95,22 @@ for (String part: splitInParts(text)) { parsePart(part); } - + isBusinessTime = text.indexOf("business")!=-1; } - + public static boolean isValidExpression(String durationExpression) { try { - new Duration(durationExpression); + new Duration(durationExpression); } catch (JbpmException e) { return false; } return true; } - + public static Date calculateDueDate(String durationExpression) { Date duedate = null; if (durationExpression != null) { - ScriptManager scriptManager = ScriptManager.getScriptManager(); Date baseDate; String durationString = null; @@ -118,14 +119,15 @@ if (durationExpression.startsWith("#")) { String baseDateEL = durationExpression.substring(0, durationExpression.indexOf("}") + 1); - Object result = scriptManager.evaluateExpression(baseDateEL, null); + Object result = Expression.create(baseDateEL, null).evaluate(); if (result instanceof Date) { baseDate = (Date) result; } else if (result instanceof Calendar) { baseDate = ((Calendar) result).getTime(); } else { - throw new JbpmException("Invalid basedate type: " + baseDateEL + " is of type " + result.getClass().getName() + throw new JbpmException("Invalid basedate type: " + baseDateEL + " is of type " + + result.getClass().getName() + ". Only Date and Calendar are supported"); } @@ -173,40 +175,40 @@ this.months = months; this.years = years; } - + private List splitInParts(String text) { List parts = new ArrayList(2); while (text!=null) { int commaIndex = text.indexOf(','); int andIndex = text.indexOf(" and "); - if ( ( (commaIndex==-1) + if ( ( (commaIndex==-1) && (andIndex!=-1) - ) - || - ( ( (commaIndex!=-1) + ) + || + ( ( (commaIndex!=-1) && (andIndex!=-1) - ) + ) && (andIndexcommaIndex) ) ) { String part = text.substring(0, commaIndex).trim(); parts.add(part); text = text.substring(commaIndex+1); - + } else { parts.add(text.trim()); text = null; @@ -224,7 +226,7 @@ String quantityText = part.substring(0, spaceIndex).trim(); spaceIndex = part.lastIndexOf(' '); String unitText = part.substring(spaceIndex+1).trim().toLowerCase(); - + int quantity; try { quantity = Integer.parseInt(quantityText); @@ -237,7 +239,7 @@ } fieldSetter.set(this, quantity); } - + interface FieldSetter { void set(Duration duration, int quantity); } @@ -325,7 +327,7 @@ fieldSetters.put("year", fieldSetter); fieldSetters.put("years", fieldSetter); } - + public int getDays() { return days; } @@ -353,7 +355,7 @@ public int getSeconds() { return seconds; } - + public int getWeeks() { return weeks; } Index: modules/pvm/src/main/java/org/jbpm/pvm/internal/el/Expression.java =================================================================== --- modules/pvm/src/main/java/org/jbpm/pvm/internal/el/Expression.java (revision 6436) +++ modules/pvm/src/main/java/org/jbpm/pvm/internal/el/Expression.java (working copy) @@ -36,8 +36,9 @@ /** handles all expression resolving - * + * * @author Tom Baeyens + * @author Huisheng Xu */ public abstract class Expression implements Serializable { @@ -55,7 +56,7 @@ if (expressionText==null) { throw new JbpmException("expressionText is null"); } - + if (language==null || language.startsWith(LANGUAGE_UEL)) { if (expressionText.indexOf('{')==-1) { return new StaticTextExpression(expressionText); @@ -65,26 +66,28 @@ // by default, expr is interpreted as a value expression if (language==null || LANGUAGE_UEL_VALUE.equals(language)) { try { - ValueExpression valueExpression = expressionFactory.createValueExpression(elContext, expressionText, Object.class); - + ValueExpression valueExpression = expressionFactory + .createValueExpression(elContext, expressionText, Object.class); + return new UelValueExpression(valueExpression); - + // if the expr is not a valid value expr... } catch (ELException e) { - // ... and the expr-type was not specified + // ... and the expr-type was not specified if (language==null) { // then try to parse it as a method expression language = LANGUAGE_UEL_METHOD; } - } - } + } + } if (LANGUAGE_UEL_METHOD.equals(language)) { - MethodExpression methodExpression = expressionFactory.createMethodExpression(elContext, expressionText, null, new Class[]{}); + MethodExpression methodExpression = expressionFactory + .createMethodExpression(elContext, expressionText, null, new Class[]{}); return new UelMethodExpression(methodExpression); } - } + } return new ScriptExpression(expressionText, language); } @@ -97,7 +100,11 @@ } // runtime evaluation /////////////////////////////////////////////////////// - + + public Object evaluate() { + return evaluateInScope(null); + } + public Object evaluate(Execution execution) { return evaluateInScope((ScopeInstanceImpl)execution); } @@ -105,7 +112,7 @@ public Object evaluate(Task task) { return evaluateInScope((ScopeInstanceImpl)task); } - + public abstract Object evaluateInScope(ScopeInstanceImpl scopeInstance); protected ELContext getElContext(ScopeInstanceImpl scopeInstance) { @@ -120,4 +127,8 @@ } return elContext; } + + public abstract String getExpressionString(); + + public abstract boolean isLiteralText(); } Index: modules/pvm/src/main/java/org/jbpm/pvm/internal/el/ScriptExpression.java =================================================================== --- modules/pvm/src/main/java/org/jbpm/pvm/internal/el/ScriptExpression.java (revision 6436) +++ modules/pvm/src/main/java/org/jbpm/pvm/internal/el/ScriptExpression.java (working copy) @@ -26,15 +26,18 @@ /** + * This is script expression, it will use ScriptManager to evaluate the expr by specified language. + * * @author Tom Baeyens + * @author Huisheng Xu */ public class ScriptExpression extends Expression { private static final long serialVersionUID = 1L; - + protected String expressionText; protected String language; - + public ScriptExpression(String expressionText, String language) { this.expressionText = expressionText; this.language = language; @@ -44,4 +47,12 @@ ScriptManager scriptManager = ScriptManager.getScriptManager(); return scriptManager.evaluateExpression(expressionText, language); } + + public String getExpressionString() { + return expressionText; + } + + public boolean isLiteralText() { + return false; + } } Index: modules/pvm/src/main/java/org/jbpm/pvm/internal/el/StaticTextExpression.java =================================================================== --- modules/pvm/src/main/java/org/jbpm/pvm/internal/el/StaticTextExpression.java (revision 6436) +++ modules/pvm/src/main/java/org/jbpm/pvm/internal/el/StaticTextExpression.java (working copy) @@ -25,14 +25,17 @@ /** + * This is a static text expression, didn't contains any script expression. + * * @author Tom Baeyens + * @author Huiheng Xu */ public class StaticTextExpression extends Expression { private static final long serialVersionUID = 1L; String text; - + public StaticTextExpression(String text) { this.text = text; } @@ -41,7 +44,11 @@ return text; } - public String getText() { + public String getExpressionString() { return text; } + + public boolean isLiteralText() { + return true; + } } Index: modules/pvm/src/main/java/org/jbpm/pvm/internal/el/UelMethodExpression.java =================================================================== --- modules/pvm/src/main/java/org/jbpm/pvm/internal/el/UelMethodExpression.java (revision 6436) +++ modules/pvm/src/main/java/org/jbpm/pvm/internal/el/UelMethodExpression.java (working copy) @@ -29,11 +29,12 @@ /** * @author Tom Baeyens + * @author Huisheng Xu */ public class UelMethodExpression extends Expression { private static final long serialVersionUID = 1L; - + protected MethodExpression methodExpression; public UelMethodExpression(MethodExpression methodExpression) { @@ -44,4 +45,12 @@ ELContext elContext = getElContext(scopeInstance); return methodExpression.invoke(elContext, null); } + + public String getExpressionString() { + return methodExpression.getExpressionString(); + } + + public boolean isLiteralText() { + return false; + } } Index: modules/pvm/src/main/java/org/jbpm/pvm/internal/el/UelValueExpression.java =================================================================== --- modules/pvm/src/main/java/org/jbpm/pvm/internal/el/UelValueExpression.java (revision 6436) +++ modules/pvm/src/main/java/org/jbpm/pvm/internal/el/UelValueExpression.java (working copy) @@ -32,11 +32,12 @@ /** * @author Tom Baeyens + * @author Huisheng Xu */ public class UelValueExpression extends Expression { private static final long serialVersionUID = 1L; - + protected ValueExpression valueExpression; public UelValueExpression(ValueExpression valueExpression) { @@ -54,14 +55,22 @@ public void setValue(Task task, Object value) { setValue((ScopeInstanceImpl)task, value); } - + public void setValue(Execution execution, Object value) { setValue((ScopeInstanceImpl)execution, value); } - + public void setValue(ScopeInstanceImpl scopeInstance, Object value) { ELContext elContext = getElContext(scopeInstance); valueExpression.setValue(elContext, value); } + public String getExpressionString() { + return valueExpression.getExpressionString(); + } + + public boolean isLiteralText() { + return false; + } + } Index: modules/pvm/src/main/java/org/jbpm/pvm/internal/email/impl/MailProducerImpl.java =================================================================== --- modules/pvm/src/main/java/org/jbpm/pvm/internal/email/impl/MailProducerImpl.java (revision 6436) +++ modules/pvm/src/main/java/org/jbpm/pvm/internal/email/impl/MailProducerImpl.java (working copy) @@ -49,16 +49,17 @@ import org.jbpm.api.JbpmException; import org.jbpm.api.identity.Group; import org.jbpm.api.identity.User; +import org.jbpm.pvm.internal.el.Expression; import org.jbpm.pvm.internal.email.spi.AddressResolver; import org.jbpm.pvm.internal.email.spi.MailProducer; import org.jbpm.pvm.internal.env.EnvironmentImpl; import org.jbpm.pvm.internal.identity.spi.IdentitySession; -import org.jbpm.pvm.internal.script.ScriptManager; /** * Default mail producer. - * + * * @author Alejandro Guizar + * @author Huisheng Xu */ public class MailProducerImpl implements MailProducer, Serializable { @@ -96,7 +97,7 @@ * Fills the from attribute of the given email. The sender addresses are an * optional element in the mail template. If absent, each mail server supplies the current * user's email address. - * + * * @see {@link InternetAddress#getLocalAddress(Session)} */ protected void fillFrom(Execution execution, Message email) throws MessagingException { @@ -138,8 +139,7 @@ } private T evaluateExpression(String expression, Class type) { - ScriptManager scriptManager = ScriptManager.getScriptManager(); - Object value = scriptManager.evaluateExpression(expression, template.getLanguage()); + Object value = Expression.create(expression, template.getLanguage()).evaluate(); return type.cast(value); } @@ -265,7 +265,7 @@ // obtain interface to data DataHandler dataHandler = createDataHandler(attachmentTemplate); attachmentPart.setDataHandler(dataHandler); - + // resolve file name String name = attachmentTemplate.getName(); if (name != null) { Index: modules/pvm/src/main/java/org/jbpm/pvm/internal/model/ExecutionImpl.java =================================================================== --- modules/pvm/src/main/java/org/jbpm/pvm/internal/model/ExecutionImpl.java (revision 6436) +++ modules/pvm/src/main/java/org/jbpm/pvm/internal/model/ExecutionImpl.java (working copy) @@ -66,7 +66,6 @@ import org.jbpm.pvm.internal.model.op.AtomicOperation; import org.jbpm.pvm.internal.model.op.MoveToChildActivity; import org.jbpm.pvm.internal.model.op.Signal; -import org.jbpm.pvm.internal.script.ScriptManager; import org.jbpm.pvm.internal.session.DbSession; import org.jbpm.pvm.internal.session.MessageSession; import org.jbpm.pvm.internal.session.RepositorySession; @@ -82,6 +81,7 @@ /** * @author Tom Baeyens + * @author Huisheng Xu */ public class ExecutionImpl extends ScopeInstanceImpl implements ClientProcessInstance, ActivityExecution, EventListenerExecution { @@ -89,13 +89,13 @@ private static final long serialVersionUID = 1L; private static final Log log = Log.getLog(ExecutionImpl.class.getName()); - - /** an optional name for this execution. can be used to - * differentiate concurrent paths of execution like e.g. + + /** an optional name for this execution. can be used to + * differentiate concurrent paths of execution like e.g. * the 'shipping' and 'billing' paths. */ protected String name; - /** a key for this execution. typically this is an externally provided reference + /** a key for this execution. typically this is an externally provided reference * that is unique within the scope of the process definition. */ protected String key; @@ -109,10 +109,10 @@ * concurrency. */ protected ExecutionImpl parent; protected ExecutionImpl processInstance; - - /** the super process link in case this is a sub process execution */ + + /** the super process link in case this is a sub process execution */ protected ExecutionImpl superProcessExecution; - + /** the sub process link in case of sub process execution */ protected ExecutionImpl subProcessInstance; @@ -121,7 +121,7 @@ /** reference to the current activity instance history record */ protected Long historyActivityInstanceDbid; - + /** start time of the activity for history purposes (not persisted) */ protected Date historyActivityStart; @@ -130,10 +130,10 @@ protected Map systemVariables = new HashMap(); // persistent indicators of the current position //////////////////////////// - + /** persistent process definition reference */ protected String processDefinitionId; - + /** persistent activity reference */ protected String activityName; @@ -141,7 +141,7 @@ /** transient cached process definition. persistence is managed in {@link #processDefinitionId} */ protected ProcessDefinitionImpl processDefinition; - + /** transient cached current activity pointer. persistence is managed in {@link #activityName} */ private ActivityImpl activity; @@ -157,7 +157,7 @@ protected ObservableElementImpl eventSource; // cached named executions ////////////////////////////////////////////////// - + /** caches the child executions by execution name. This member might be * null and is only created from the executions in case its needed. Note * that not all executions are forced to have a name and duplicates are allowed. @@ -175,7 +175,7 @@ protected Propagation propagation; // construction ///////////////////////////////////////////////////////////// - + public void initializeProcessInstance(ProcessDefinitionImpl processDefinition, String key) { setProcessDefinition(processDefinition); setActivity(processDefinition.getInitial()); @@ -184,7 +184,7 @@ this.key = key; save(); - + HistoryEvent.fire(new ProcessInstanceCreate(), this); } @@ -211,7 +211,7 @@ } this.state = STATE_ACTIVE_ROOT; ExecutionImpl scopedExecution = initializeScopes(); - + fire(Event.START, getProcessDefinition()); if (getActivity()!=null) { scopedExecution.performAtomicOperation(AtomicOperation.EXECUTE_ACTIVITY); @@ -223,7 +223,7 @@ ActivityImpl initial = getProcessDefinition().getInitial(); ExecutionImpl scopedExecution = null; - + if (initial!=null) { enteredActivities.add(initial); ActivityImpl parentActivity = initial.getParentActivity(); @@ -231,19 +231,19 @@ enteredActivities.addFirst(parentActivity); parentActivity = parentActivity.getParentActivity(); } - + scopedExecution = this; initializeVariables(getProcessDefinition(), this); initializeTimers(getProcessDefinition()); - + for (ActivityImpl enteredActivity: enteredActivities) { if (enteredActivity.isLocalScope()) { scopedExecution.setActivity(enteredActivity); scopedExecution = scopedExecution.createScope(enteredActivity); } } - + scopedExecution.setActivity(initial); } return scopedExecution; @@ -251,29 +251,29 @@ public ExecutionImpl createScope(ScopeElementImpl scope) { ExecutionImpl child = createExecution(scope.getName()); - + setState(STATE_INACTIVE_SCOPE); child.setState(STATE_ACTIVE_ROOT); - + // copy the current state from the child execution to the parent execution child.setActivity(getActivity()); child.setTransition(getTransition()); child.setPropagation(getPropagation()); - + child.initializeVariables(scope, this); child.initializeTimers(scope); - + return child; } - + public ExecutionImpl destroyScope(CompositeElementImpl scope) { destroyTimers(scope); - + // copy the current state from the child execution to the parent execution parent.setActivity(getActivity()); parent.setTransition(getTransition()); parent.setPropagation(getPropagation()); - + ExecutionImpl parentsParent = parent.getParent(); if (parentsParent!=null && STATE_INACTIVE_CONCURRENT_ROOT.equals(parentsParent.getState())) { @@ -282,16 +282,16 @@ else { parent.setState(STATE_ACTIVE_ROOT); } - - // capture the parent execution cause the + + // capture the parent execution cause the // subsequent invocation of end() will set the parent to null ExecutionImpl parent = this.parent; - + end(); return parent; } - + @Override protected void destroyTimers(CompositeElementImpl scope) { TimerSession timerSession = EnvironmentImpl.getFromCurrent(TimerSession.class, false); @@ -319,7 +319,7 @@ } return "execution"; } - + // execution method : end /////////////////////////////////////////////////// public void end() { @@ -341,7 +341,7 @@ || state.equals(STATE_ASYNC)) { throw new JbpmException("invalid end state: "+state); } - + if (log.isDebugEnabled()) { if (state==STATE_ENDED) { log.debug(toString()+" ends"); @@ -350,32 +350,32 @@ log.debug(toString()+" ends with state "+state); } } - + // end all child executions // making a copy of the executions to prevent ConcurrentMoidificationException List executionsToEnd = new ArrayList(executions); for (ExecutionImpl child: executionsToEnd) { child.end(state); } - + setState(state); this.propagation = Propagation.EXPLICIT; - + DbSession dbSession = EnvironmentImpl.getFromCurrent(DbSession.class, false); - - + + if (parent!=null) { - + if (dbSession!=null) { - + // make sure task attached to this execution are completed or skipped TaskImpl task = dbSession.findTaskByExecution(this); if (task != null && !task.isCompleted()) { task.skip(null); } - + dbSession.delete(this); } parent.removeExecution(this); @@ -397,7 +397,7 @@ } } } - + public void end(OpenExecution executionToEnd) { ((ExecutionImpl)executionToEnd).end(); } @@ -415,7 +415,7 @@ public void signal(String signal) { signal(signal, (Map)null); } - + public void signal(Map parameters) { signal(null, parameters); } @@ -436,7 +436,7 @@ throw new JbpmException("execution is not in a activity or in a transition"); } } - + public void signal(Execution execution) { ((ExecutionImpl)execution).signal(null, (Map)null); } @@ -454,7 +454,7 @@ } // execution method : take //////////////////////////////////////////////// - + /** @see Execution#takeDefaultTransition() */ public void takeDefaultTransition() { TransitionImpl defaultTransition = getActivity().getDefaultOutgoingTransition(); @@ -483,7 +483,7 @@ setPropagation(Propagation.EXPLICIT); setTransition((TransitionImpl) transition); - + fire(Event.END, getActivity(), AtomicOperation.TRANSITION_END_ACTIVITY); } @@ -504,24 +504,24 @@ } execute(nestedActivity); } - + /** @see Execution#execute(Activity) */ public void execute(Activity activity) { if (activity==null) { throw new JbpmException("activity is null"); } checkActive(); - + this.propagation = Propagation.EXPLICIT; performAtomicOperation(new MoveToChildActivity((ActivityImpl) activity)); } - + // execution method : waitForSignal ///////////////////////////////////////// - + public void waitForSignal() { propagation = Propagation.WAIT; } - + // execution method : proceed /////////////////////////////////////////////// public void proceed() { @@ -533,8 +533,8 @@ if (defaultTransition!=null) { take(defaultTransition); } - // in block structured processDefinition languages we assume that - // there is no default transition and that there is a + // in block structured processDefinition languages we assume that + // there is no default transition and that there is a // parent activity of the current activity else { ActivityImpl parentActivity = getActivity().getParentActivity(); @@ -545,9 +545,9 @@ performAtomicOperation(AtomicOperation.PROPAGATE_TO_PARENT); } else { - // When we don't know how to proceed, i don't know if it's best to + // When we don't know how to proceed, i don't know if it's best to // throw new PvmException("don't know how to proceed"); - // or to end the execution. Because of convenience for testing, + // or to end the execution. Because of convenience for testing, // I opted to end the execution. end(); } @@ -563,7 +563,7 @@ } // events /////////////////////////////////////////////////////////////////// - + public void fire(String eventName, ObservableElement eventSource) { fire(eventName, (ObservableElementImpl) eventSource, null); } @@ -582,17 +582,17 @@ performAtomicOperationSync(eventCompletedOperation); } } - + public static EventImpl findEvent(ObservableElementImpl observableElement, String eventName) { if (observableElement==null) { return null; } - + EventImpl event = observableElement.getEvent(eventName); if (event!=null) { return event; } - + return findEvent(observableElement.getParent(), eventName); } @@ -622,7 +622,7 @@ return propagatingExecution; } - // asynchronous continuations //////////////////////////////////////////////// + // asynchronous continuations //////////////////////////////////////////////// public synchronized void performAtomicOperation(AtomicOperation operation) { if (operation.isAsync(this)) { @@ -632,7 +632,7 @@ performAtomicOperationSync(operation); } } - + public void sendContinuationMessage(AtomicOperation operation) { EnvironmentImpl environment = EnvironmentImpl.getCurrent(); MessageSession messageSession = environment.get(MessageSession.class); @@ -649,8 +649,8 @@ // initialise the fifo queue of atomic operations atomicOperations = new LinkedList(); atomicOperations.offer(operation); - - ExecutionContext originalExecutionContext = null; + + ExecutionContext originalExecutionContext = null; ExecutionContext executionContext = null; EnvironmentImpl environment = EnvironmentImpl.getCurrent(); if (environment!=null) { @@ -665,7 +665,7 @@ environment.setContext(executionContext); } } - + try { while (! atomicOperations.isEmpty()) { AtomicOperation atomicOperation = atomicOperations.poll(); @@ -674,7 +674,7 @@ } finally { atomicOperations = null; - + if (executionContext!=null) { environment.removeContext(executionContext); } @@ -688,13 +688,13 @@ } } - /** + /** * Important: Only use this if resolving an expression on another execution then the current execution - * + * * TODO: remove this operation once the environment/executionContext is refactored */ public Object resolveExpression(String expression, String language) { - ExecutionContext originalExecutionContext = null; + ExecutionContext originalExecutionContext = null; ExecutionContext executionContext = null; EnvironmentImpl environment = EnvironmentImpl.getCurrent(); if (environment!=null) { @@ -709,10 +709,9 @@ environment.setContext(executionContext); } } - + try { - ScriptManager scriptManager = ScriptManager.getScriptManager(); - return scriptManager.evaluateScript(expression, language); + return Expression.create(expression, language).evaluate(); } catch (RuntimeException e) { log.error("Error while evaluation script " + expression, e); @@ -730,7 +729,7 @@ public void handleException(ObservableElementImpl observableElement, EventImpl event, EventListenerReference eventListenerReference, Exception exception, String rethrowMessage) { - + List processElements = new ArrayList(); if (eventListenerReference!=null) { processElements.add(eventListenerReference); @@ -742,7 +741,7 @@ processElements.add(observableElement); observableElement = observableElement.getParent(); } - + for (ProcessElementImpl processElement: processElements) { List exceptionHandlers = processElement.getExceptionHandlers(); if (exceptionHandlers!=null) { @@ -766,7 +765,7 @@ log.trace("rethrowing exception cause no exception handler for "+exception); ExceptionHandlerImpl.rethrow(exception, rethrowMessage+": "+exception.getMessage()); } - + // tasks //////////////////////////////////////////////////////////////////// /** tasks and swimlane assignment. @@ -778,10 +777,10 @@ if (assigneeExpression!=null) { String assignee = (String) assigneeExpression.evaluate(this); assignable.setAssignee(assignee); - + if (log.isTraceEnabled()) log.trace("task "+name+" assigned to "+assignee+" using expression "+assigneeExpression); } - + Expression candidateUsersExpression = assignableDefinition.getCandidateUsersExpression(); if (candidateUsersExpression!=null) { String candidateUsers = (String) candidateUsersExpression.evaluate(this); @@ -792,7 +791,7 @@ assignable.addCandidateUser(candidateUser); } } - + Expression candidateGroupsExpression = assignableDefinition.getCandidateGroupsExpression(); if (candidateGroupsExpression!=null) { String candidateGroups = (String) candidateGroupsExpression.evaluate(this); @@ -802,11 +801,11 @@ assignable.addCandidateGroup(candidateGroup); } } - + UserCodeReference assignmentHandlerReference = assignableDefinition .getAssignmentHandlerReference(); if (assignmentHandlerReference!=null) { - // JBPM-2758 + // JBPM-2758 // TODO Find out why processdefinition is null in at this time.... if (processDefinition == null) { processDefinition = getProcessDefinition(); @@ -825,25 +824,25 @@ } protected String resolveAssignmentExpression(String expression, String expressionLanguage) { - ScriptManager scriptManager = EnvironmentImpl.getFromCurrent(ScriptManager.class); - Object result = scriptManager.evaluateExpression(expression, expressionLanguage); + Object result = Expression.create(expression, expressionLanguage).evaluate(); if (result == null || result instanceof String) { return (String) result; } - throw new JbpmException("result of assignment expression "+expression+" is "+result+" ("+result.getClass().getName()+") instead of String"); + throw new JbpmException("result of assignment expression " + expression + + " is " + result + " (" + result.getClass().getName() + ") instead of String"); } - + // swimlanes //////////////////////////////////////////////////////////////// - + public void addSwimlane(SwimlaneImpl swimlane) { swimlanes.put(swimlane.getName(), swimlane); swimlane.setExecution(this); } - + public SwimlaneImpl getSwimlane(String swimlaneName) { return swimlanes.get(swimlaneName); } - + public void removeSwimlane(SwimlaneImpl swimlane) { swimlanes.remove(swimlane.getName()); swimlane.setExecution(null); @@ -875,7 +874,7 @@ swimlanes.put(swimlaneName, swimlane); return swimlane; } - + // child executions ///////////////////////////////////////////////////////// public ExecutionImpl createExecution() { @@ -884,22 +883,22 @@ public ExecutionImpl createExecution(String name) { // when an activity calls createExecution, propagation is explicit. - // this means that the default propagation (proceed()) will not be called + // this means that the default propagation (proceed()) will not be called propagation = Propagation.EXPLICIT; // create new execution ExecutionImpl childExecution = newChildExecution(); - // initialize child execution + // initialize child execution childExecution.setProcessDefinition(getProcessDefinition()); childExecution.processInstance = this.processInstance; childExecution.name = name; - + // composeIds uses the parent so the childExecution has to be added before the ids are composed - childExecution.setParent(this); + childExecution.setParent(this); childExecution.save(); // make sure that child execution are saved before added to a persistent collection - // cause of the 'assigned' id strategy, adding the childExecution to the persistent collection + // cause of the 'assigned' id strategy, adding the childExecution to the persistent collection // before the dbid is assigned will result in identifier of an instance of ExecutionImpl altered from 0 to x addExecution(childExecution); @@ -953,7 +952,7 @@ } return executionsMap; } - + public boolean hasExecution(String name) { return getExecutionsMap() != null && executionsMap.containsKey(name); } @@ -971,11 +970,11 @@ && activityName != null) { activityNames.add(activityName); } - + for (ExecutionImpl childExecution: executions) { childExecution.addActiveActivityNames(activityNames); } - + return activityNames; } @@ -993,9 +992,9 @@ return null; } - + // system variables ///////////////////////////////////////////////////////// - + public void createSystemVariable(String key, Object value) { createSystemVariable(key, value, null); } @@ -1016,7 +1015,7 @@ createSystemVariable(key, value, null); } } - + public Object getSystemVariable(String key) { Variable variable = systemVariables.get(key); if (variable!=null) { @@ -1024,7 +1023,7 @@ } return null; } - + public boolean removeSystemVariable(String key) { if (systemVariables.containsKey(key)) { return systemVariables.remove(key) != null; @@ -1037,7 +1036,7 @@ public ClientProcessInstance createSubProcessInstance(ClientProcessDefinition processDefinition) { return createSubProcessInstance(processDefinition, null); } - + public ClientProcessInstance createSubProcessInstance(ClientProcessDefinition processDefinition, String key) { if (subProcessInstance!=null) { throw new JbpmException(toString()+" already has a sub process instance: "+subProcessInstance); @@ -1046,11 +1045,11 @@ subProcessInstance.setSuperProcessExecution(this); return subProcessInstance; } - + public ClientProcessInstance startSubProcessInstance(ClientProcessDefinition processDefinition) { return startSubProcessInstance(processDefinition, null); } - + public ClientProcessInstance startSubProcessInstance(ClientProcessDefinition processDefinition, String key) { createSubProcessInstance(processDefinition, key); subProcessInstance.start(); @@ -1084,11 +1083,11 @@ if (!isActive()) { throw new JbpmException(toString()+" is not active: "+state); } else if (this.subProcessInstance != null && !Execution.STATE_ENDED.equals(this.subProcessInstance.getState())) { - throw new JbpmException(toString() + " has running subprocess: " + throw new JbpmException(toString() + " has running subprocess: " + this.subProcessInstance.toString() + " in state " + this.subProcessInstance.getState()); } } - + public boolean isEnded() { if (Execution.STATE_ENDED.equals(state)) { return true; @@ -1120,7 +1119,7 @@ //////////////////////////////////////////////////////////////////////////////// // overriding the ScopeInstanceImpl methods ///////////////////////////////// - + public ScopeInstanceImpl getParentVariableScope() { return parent; } @@ -1130,10 +1129,10 @@ } // overridable by process languages ///////////////////////////////////////// - - /** by default this will use {@link ActivityImpl#findOutgoingTransition(String)} to - * search for the outgoing transition, which includes a search over the parent chain - * of the current activity. This method allows process languages to overwrite this default + + /** by default this will use {@link ActivityImpl#findOutgoingTransition(String)} to + * search for the outgoing transition, which includes a search over the parent chain + * of the current activity. This method allows process languages to overwrite this default * implementation of the transition lookup by transitionName.*/ protected TransitionImpl findTransition(String transitionName) { return getActivity().findOutgoingTransition(transitionName); @@ -1142,7 +1141,7 @@ protected TransitionImpl findDefaultTransition() { return getActivity().findDefaultTransition(); } - + // history ////////////////////////////////////////////////////////////////// public void historyAutomatic() { @@ -1152,7 +1151,7 @@ public void historyDecision(String transitionName) { HistoryEvent.fire(new DecisionEnd(transitionName), this); } - + public void historyActivityStart() { HistoryEvent.fire(new ActivityStart(), this); } @@ -1172,12 +1171,12 @@ public boolean equals(Object o) { return EqualsUtil.equals(this, o); } - + // process definition getter and setter ///////////////////////////////////// - // this getter and setter is special because persistence is based on the // + // this getter and setter is special because persistence is based on the // // process definition id. // ///////////////////////////////////////////////////////////////////////////// - + public ProcessDefinitionImpl getProcessDefinition() { if (processDefinition == null && processDefinitionId != null) { RepositorySession repositorySession = EnvironmentImpl @@ -1193,19 +1192,19 @@ this.processDefinition = processDefinition; this.processDefinitionId = processDefinition.getId(); } - + // activity getter and setter /////////////////////////////////////////////// - // this getter and setter is special because persistence is based on the // + // this getter and setter is special because persistence is based on the // // activity name. // ///////////////////////////////////////////////////////////////////////////// - + public ActivityImpl getActivity() { if (activity == null && activityName != null) { activity = getProcessDefinition().findActivity(activityName); } return activity; } - + public void setActivity(ActivityImpl activity) { this.activity = activity; if (activity!=null) { @@ -1237,14 +1236,14 @@ } // getters and setters for scope instance ////////////////////////////////////// - + @Override public ExecutionImpl getExecution() { return this; } // getters and setters ///////////////////////////////////////////////////////// - + public TransitionImpl getTransition() { return transition; } Index: modules/pvm/src/main/java/org/jbpm/pvm/internal/model/ExpressionCondition.java =================================================================== --- modules/pvm/src/main/java/org/jbpm/pvm/internal/model/ExpressionCondition.java (revision 6436) +++ modules/pvm/src/main/java/org/jbpm/pvm/internal/model/ExpressionCondition.java (working copy) @@ -23,34 +23,34 @@ import org.jbpm.api.JbpmException; import org.jbpm.api.model.OpenExecution; -import org.jbpm.pvm.internal.script.ScriptManager; +import org.jbpm.pvm.internal.el.Expression; /** * @author Tom Baeyens + * @author Huisheng Xu */ public class ExpressionCondition implements Condition { private static final long serialVersionUID = 1L; - + protected String expression; protected String language; - + public boolean evaluate(OpenExecution execution) { - ScriptManager scriptManager = ScriptManager.getScriptManager(); - Object result = scriptManager.evaluateExpression(expression, language); + Object result = Expression.create(expression, language).evaluate(); if (result instanceof Boolean) { return ((Boolean) result).booleanValue(); } - throw new JbpmException("expression condition '"+expression+"' did not return a boolean: "+result); + throw new JbpmException("expression condition '" + expression + "' did not return a boolean: "+result); } public void setExpression(String expression) { this.expression = expression; } - + public void setLanguage(String language) { this.language = language; } - + } Index: modules/pvm/src/main/java/org/jbpm/pvm/internal/model/VariableOutDefinitionSet.java =================================================================== --- modules/pvm/src/main/java/org/jbpm/pvm/internal/model/VariableOutDefinitionSet.java (revision 6436) +++ modules/pvm/src/main/java/org/jbpm/pvm/internal/model/VariableOutDefinitionSet.java (working copy) @@ -26,16 +26,17 @@ import java.util.Collections; import java.util.List; +import org.jbpm.pvm.internal.el.Expression; import org.jbpm.pvm.internal.env.EnvironmentImpl; -import org.jbpm.pvm.internal.script.ScriptManager; /** * @author Tom Baeyens + * @author Huisheng Xu */ public class VariableOutDefinitionSet implements Serializable { - + private static final long serialVersionUID = 1L; - + protected List variableOutDefinitions; public void processOutVariables(ExecutionImpl outerExecution, ScopeInstanceImpl innerScopeInstance) { @@ -44,13 +45,11 @@ for (VariableOutDefinitionImpl variableOutDefinition: variableOutDefinitions) { String variableName = variableOutDefinition.getName(); if (variableName!=null) { - ScriptManager scriptManager = EnvironmentImpl.getFromCurrent(ScriptManager.class); - // TODO update evaluateExpression so that scopeInstance can be passed in directly String expression = variableOutDefinition.getExpression(); String language = variableOutDefinition.getLanguage(); - Object value = scriptManager.evaluateExpression(expression, language); + Object value = Expression.create(expression, language).evaluateInScope(innerScopeInstance); outerExecution.setVariable(variableName, value); } } @@ -62,7 +61,7 @@ && (!variableOutDefinitions.isEmpty()) ); } - + public List getVariableOutDefinitions() { if (variableOutDefinitions==null) { return Collections.emptyList(); Index: modules/pvm/src/main/java/org/jbpm/pvm/internal/wire/descriptor/ExpressionDescriptor.java =================================================================== --- modules/pvm/src/main/java/org/jbpm/pvm/internal/wire/descriptor/ExpressionDescriptor.java (revision 6436) +++ modules/pvm/src/main/java/org/jbpm/pvm/internal/wire/descriptor/ExpressionDescriptor.java (working copy) @@ -21,23 +21,23 @@ */ package org.jbpm.pvm.internal.wire.descriptor; -import org.jbpm.pvm.internal.script.ScriptManager; +import org.jbpm.pvm.internal.el.Expression; import org.jbpm.pvm.internal.wire.WireContext; /** * @author Tom Baeyens + * @author Huisheng Xu */ public class ExpressionDescriptor extends AbstractDescriptor { private static final long serialVersionUID = 1L; - + protected String expression; protected String language; - + public Object construct(WireContext wireContext) { - ScriptManager scriptManager = ScriptManager.getScriptManager(); - Object result = scriptManager.evaluateExpression(expression, language); + Object result = Expression.create(expression, language).evaluate(); return result; } Index: modules/pvm/src/test/java/org/jbpm/pvm/internal/el/ExpressionTest.java =================================================================== --- modules/pvm/src/test/java/org/jbpm/pvm/internal/el/ExpressionTest.java (revision 0) +++ modules/pvm/src/test/java/org/jbpm/pvm/internal/el/ExpressionTest.java (revision 0) @@ -0,0 +1,43 @@ + +package org.jbpm.pvm.internal.el; + +import junit.framework.*; +import org.jbpm.api.*; +import org.jbpm.pvm.internal.model.*; + +/** + * @author Huisheng Xu + */ +public class ExpressionTest extends TestCase { + public void testStaticEl() { + Expression expr = Expression.create("Lingo", null); + assertEquals("Lingo", expr.evaluate((Execution) null)); + } + + public void testValueEl() { + Expression expr = Expression.create("#{name}", null); + ExecutionImpl execution = new ExecutionImpl(); + execution.setVariable("name", "Lingo"); + assertEquals("Lingo", expr.evaluate(execution)); + } + + public void testFunctionEl() { + Expression expr = Expression.create("#{length(array)}", null); + ExecutionImpl execution = new ExecutionImpl(); + execution.setVariable("array", new String[] {"1", "2", "3"}); + assertEquals(3, expr.evaluate(execution)); + } + + public void testMethodEl() { + Expression expr = Expression.create("#{action.login()}", null); + ExecutionImpl execution = new ExecutionImpl(); + execution.setVariable("action", new Demo()); + assertEquals("Lingo", expr.evaluate(execution)); + } + + public static class Demo { + public String login() { + return "Lingo"; + } + } +} Index: modules/test-db/src/test/java/org/jbpm/test/variables/VariableExpressionTest.java =================================================================== --- modules/test-db/src/test/java/org/jbpm/test/variables/VariableExpressionTest.java (revision 6436) +++ modules/test-db/src/test/java/org/jbpm/test/variables/VariableExpressionTest.java (working copy) @@ -20,7 +20,7 @@ * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ /** - * + * */ package org.jbpm.test.variables; @@ -39,7 +39,7 @@ * @author Maciej Swiderski */ public class VariableExpressionTest extends JbpmTestCase { - + public void testExpression() { deployJpdlXmlString( "" + @@ -51,7 +51,7 @@ " " + " " + " " + - " " + + " " + " " + " " + " " + @@ -63,17 +63,17 @@ " " + "" ); - + Map vars = new HashMap(); vars.put("counter", 0); - + ProcessInstance processInstance = executionService.startProcessInstanceByKey("theProcess", vars); assertActivityActive(processInstance.getId(), "waitHere"); - + Integer counter = (Integer) executionService.getVariable(processInstance.getId(), "counter"); assertEquals(new Integer(10), counter); } - + public void testNullValueExpression() { deployJpdlXmlString( "" + @@ -85,7 +85,7 @@ " " + " " + " " + - " " + + " " + " " + " " + " " + @@ -97,17 +97,17 @@ " " + "" ); - + Map vars = new HashMap(); vars.put("counter", null); - + ProcessInstance processInstance = executionService.startProcessInstanceByKey("theProcess", vars); assertActivityActive(processInstance.getId(), "waitHere"); - + Object value = executionService.getVariable(processInstance.getId(), "counter"); assertEquals(null, value); } - + public void testMissingVariableExpression() { deployJpdlXmlString( "" + @@ -119,7 +119,7 @@ " " + " " + " " + - " " + + " " + " " + " " + " " + @@ -131,20 +131,21 @@ " " + "" ); - + Map vars = new HashMap(); try { ProcessInstance processInstance = executionService.startProcessInstanceByKey("theProcess", vars); fail("Variable counter is not set, should fail"); - } catch (JbpmException e) { + } catch (Exception e) { - assertTrue(e.getMessage().indexOf("Cannot find property counter") != -1); + assertEquals("Cannot resolve identifier 'counter'", + e.getMessage()); } } - - + + public static class MyJavaActivity implements ActivityBehaviour { private static final long serialVersionUID = 1L; @@ -154,7 +155,7 @@ counter++; execution.setVariable("counter", counter); } - + } }