### Eclipse Workspace Patch 1.0 #P jbpm4 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 6285) +++ modules/test-db/src/test/java/org/jbpm/test/variables/VariableExpressionTest.java (working copy) @@ -27,6 +27,7 @@ import java.util.HashMap; import java.util.Map; +import org.jbpm.api.JbpmException; import org.jbpm.api.ProcessInstance; import org.jbpm.api.activity.ActivityBehaviour; import org.jbpm.api.activity.ActivityExecution; @@ -35,6 +36,7 @@ /** * @author Joram Barrez + * @author Maciej Swiderski */ public class VariableExpressionTest extends JbpmTestCase { @@ -72,6 +74,76 @@ assertEquals(new Integer(10), counter); } + public void testNullValueExpression() { + deployJpdlXmlString( + "" + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + "" + ); + + 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( + "" + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + "" + ); + + Map vars = new HashMap(); + try { + ProcessInstance processInstance = executionService.startProcessInstanceByKey("theProcess", vars); + + fail("Variable counter is not set, should fail"); + } catch (JbpmException e) { + + assertTrue(e.getMessage().indexOf("Cannot find property counter") != -1); + } + + } + public static class MyJavaActivity implements ActivityBehaviour { Index: modules/pvm/src/main/java/org/jbpm/pvm/internal/env/EnvironmentImpl.java =================================================================== --- modules/pvm/src/main/java/org/jbpm/pvm/internal/env/EnvironmentImpl.java (revision 6285) +++ modules/pvm/src/main/java/org/jbpm/pvm/internal/env/EnvironmentImpl.java (working copy) @@ -141,6 +141,10 @@ * @return the object if it exists in the environment, null if there is no object with the given name in the specified searchOrder contexts. */ public abstract Object get(String name, String[] searchOrder); + + public abstract Object get(String name,String[] searchOrder, boolean nullAllowed) throws JbpmException; + + public abstract Object get(String name, boolean nullAllowed) throws JbpmException; /** searches an object based on type. The search doesn take superclasses of the context elements * into account. Index: modules/pvm/src/main/java/org/jbpm/pvm/internal/env/BasicEnvironment.java =================================================================== --- modules/pvm/src/main/java/org/jbpm/pvm/internal/env/BasicEnvironment.java (revision 6285) +++ modules/pvm/src/main/java/org/jbpm/pvm/internal/env/BasicEnvironment.java (working copy) @@ -93,16 +93,30 @@ public Object get(String name) { return get(name, null); } - + public Object get(String name, String[] searchOrder) { - if (searchOrder==null) { - searchOrder = getDefaultSearchOrder(); - } - for (String contextName : searchOrder) { - Context context = contexts.get(contextName); - if (context.has(name)) return context.get(name); + return get(name, searchOrder, true); + } + + public Object get(String name, boolean nullIfNotFound) { + return get(name, null, nullIfNotFound); + } + + public Object get(String name, String[] searchOrder, boolean nullIfNotFound) { + if (searchOrder == null) { + searchOrder = getDefaultSearchOrder(); + } + for (String contextName : searchOrder) { + Context context = contexts.get(contextName); + if (context.has(name)) { + return context.get(name); + } + } + if (nullIfNotFound) { + return null; + } else { + throw new JbpmException("Null value found for " + name + " but null is not allowed"); } - return null; } public T get(Class type) { Index: modules/pvm/src/test/java/org/jbpm/pvm/internal/expr/UelExpressionTest.java =================================================================== --- modules/pvm/src/test/java/org/jbpm/pvm/internal/expr/UelExpressionTest.java (revision 0) +++ modules/pvm/src/test/java/org/jbpm/pvm/internal/expr/UelExpressionTest.java (revision 0) @@ -0,0 +1,54 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2005, JBoss Inc., and individual contributors as indicated + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.jbpm.pvm.internal.expr; + +import org.jbpm.pvm.activities.WaitState; +import org.jbpm.pvm.internal.builder.ProcessDefinitionBuilder; + +import org.jbpm.pvm.internal.el.Expression; +import org.jbpm.pvm.internal.el.UelValueExpression; +import org.jbpm.pvm.internal.model.ExecutionImpl; +import org.jbpm.test.JbpmTestCase; + + +/** + * @author Tom Baeyens + */ +public class UelExpressionTest extends JbpmTestCase { + + public void testUelExpression() { + ExecutionImpl execution = (ExecutionImpl) ProcessDefinitionBuilder + .startProcess() + .startActivity("initial", new WaitState()) + .initial() + .endActivity() + .endProcess() + .startProcessInstance(); + + Expression expression = Expression.create("#{pv}", Expression.LANGUAGE_UEL_VALUE); + UelValueExpression uve = ((UelValueExpression) expression); + + execution.setVariable("pv", null); + + assertEquals(null, uve.evaluate(execution)); + } +} Index: modules/pvm/src/main/java/org/jbpm/pvm/internal/el/JbpmEnvironmentElResolver.java =================================================================== --- modules/pvm/src/main/java/org/jbpm/pvm/internal/el/JbpmEnvironmentElResolver.java (revision 6285) +++ modules/pvm/src/main/java/org/jbpm/pvm/internal/el/JbpmEnvironmentElResolver.java (working copy) @@ -27,32 +27,36 @@ import javax.el.ELContext; import javax.el.ELResolver; +import org.jbpm.api.JbpmException; import org.jbpm.pvm.internal.env.EnvironmentImpl; - /** * @author Tom Baeyens */ public class JbpmEnvironmentElResolver extends ELResolver { - + EnvironmentImpl environment; - + public JbpmEnvironmentElResolver(EnvironmentImpl environment) { this.environment = environment; } public Object getValue(ELContext context, Object base, Object property) { - // this resolver only resolves top level variable names to execution variable names. + // this resolver only resolves top level variable names to execution + // variable names. // only handle if this is a top level variable - if (base==null) { + if (base == null) { // we assume a NPE-check for property is not needed - // i don't think the next cast can go wrong. can it? + // i don't think the next cast can go wrong. can it? String name = (String) property; - Object object = environment.get(name); - if (object!=null) { + try { + Object object = environment.get(name, false); context.setPropertyResolved(true); return object; + } catch (JbpmException je) { + // Property not found... ignore in this case and return null below... + // Will be interpreted as property not found } } Index: modules/pvm/src/main/java/org/jbpm/pvm/internal/script/JuelScriptEngine.java =================================================================== --- modules/pvm/src/main/java/org/jbpm/pvm/internal/script/JuelScriptEngine.java (revision 6285) +++ modules/pvm/src/main/java/org/jbpm/pvm/internal/script/JuelScriptEngine.java (working copy) @@ -21,14 +21,38 @@ */ package org.jbpm.pvm.internal.script; -import de.odysseus.el.util.SimpleResolver; - -import javax.el.*; -import javax.script.*; import java.io.IOException; import java.io.Reader; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.util.Properties; + +import javax.el.ArrayELResolver; +import javax.el.BeanELResolver; +import javax.el.CompositeELResolver; +import javax.el.ELContext; +import javax.el.ELException; +import javax.el.ELResolver; +import javax.el.ExpressionFactory; +import javax.el.FunctionMapper; +import javax.el.ListELResolver; +import javax.el.MapELResolver; +import javax.el.ResourceBundleELResolver; +import javax.el.ValueExpression; +import javax.el.VariableMapper; +import javax.script.AbstractScriptEngine; +import javax.script.Bindings; +import javax.script.Compilable; +import javax.script.CompiledScript; +import javax.script.ScriptContext; +import javax.script.ScriptEngine; +import javax.script.ScriptEngineFactory; +import javax.script.ScriptException; +import javax.script.SimpleBindings; + +import org.jbpm.pvm.internal.env.ExecutionContext; + +import de.odysseus.el.util.SimpleResolver; class JuelScriptEngine extends AbstractScriptEngine implements Compilable @@ -369,8 +393,16 @@ return exprFactory.createValueExpression( value, Object.class); + } else { + // to support null value for existing variables + Bindings b = this.ctx.getBindings(ScriptContext.ENGINE_SCOPE); + ExecutionContext execContext = (ExecutionContext) ((EnvironmentBindings) b).environment.getContext("execution"); + // if variable name exist then set value expression as null + // since it was not discovered by attribute scope method + if (execContext.getExecution().getVariables().containsKey(variable)) { + return exprFactory.createValueExpression(null, Object.class); + } } - return null; }