Index: modules/pvm/src/main/java/org/jbpm/pvm/internal/cmd/GetExecutionVariablesCmd.java =================================================================== --- modules/pvm/src/main/java/org/jbpm/pvm/internal/cmd/GetExecutionVariablesCmd.java (revision 6307) +++ modules/pvm/src/main/java/org/jbpm/pvm/internal/cmd/GetExecutionVariablesCmd.java (working copy) @@ -27,8 +27,12 @@ import org.jbpm.api.JbpmException; import org.jbpm.api.cmd.Environment; +import org.jbpm.api.model.OpenExecution; import org.jbpm.pvm.internal.client.ClientExecution; +import org.jbpm.pvm.internal.model.ExecutionImpl; +import org.jbpm.pvm.internal.model.ProcessDefinitionImpl; import org.jbpm.pvm.internal.session.DbSession; +import org.jbpm.pvm.internal.session.RepositorySession; /** * @author Tom Baeyens @@ -59,6 +63,17 @@ if (execution==null) { throw new JbpmException("execution "+executionId+" doesn't exist"); } + + //check if returned execution is of ExecutionImpl type + if (execution instanceof ExecutionImpl) { + + // if so process definition must be loaded to be able to perform class loading based on resources stored in db + RepositorySession repositorySession = environment.get(RepositorySession.class); + ProcessDefinitionImpl processDefinition = repositorySession.findProcessDefinitionById(execution.getProcessDefinitionId()); + + ((ExecutionImpl)execution).setProcessDefinition(processDefinition); + } + for (String variableName : variableNames) { Object value = execution.getVariable(variableName); variables.put(variableName, value); Index: modules/pvm/src/main/java/org/jbpm/pvm/internal/repository/DeploymentObjectInputStream.java =================================================================== --- modules/pvm/src/main/java/org/jbpm/pvm/internal/repository/DeploymentObjectInputStream.java (revision 0) +++ modules/pvm/src/main/java/org/jbpm/pvm/internal/repository/DeploymentObjectInputStream.java (revision 0) @@ -0,0 +1,59 @@ +/* + * 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.repository; + +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectStreamClass; + +/** + * Helper class responsible for providing classes while deserializing variables. + * + * @author Maciej Swiderski swiderski.maciej@gmail.com + * + */ +public class DeploymentObjectInputStream extends ObjectInputStream { + + private String deploymentId; + + public DeploymentObjectInputStream(InputStream stream, String deploymentId) throws IOException { + super(stream); + this.deploymentId = deploymentId; + } + + @Override + protected Class< ? > resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException { + + try { + Class< ? > clazz = Class.forName(desc.getName(), true, Thread.currentThread().getContextClassLoader()); + return clazz; + } catch (ClassNotFoundException e) { + //trying to get it from deployment + DeploymentClassLoader cl = new DeploymentClassLoader(Thread.currentThread().getContextClassLoader(), deploymentId); + return Class.forName(desc.getName(), true, cl); + } + } + + + +} Index: modules/pvm/src/main/java/org/jbpm/pvm/internal/type/converter/SerializableToBytesConverter.java =================================================================== --- modules/pvm/src/main/java/org/jbpm/pvm/internal/type/converter/SerializableToBytesConverter.java (revision 6307) +++ modules/pvm/src/main/java/org/jbpm/pvm/internal/type/converter/SerializableToBytesConverter.java (working copy) @@ -30,7 +30,9 @@ import org.jbpm.api.JbpmException; import org.jbpm.pvm.internal.env.EnvironmentImpl; +import org.jbpm.pvm.internal.model.ExecutionImpl; import org.jbpm.pvm.internal.model.ScopeInstanceImpl; +import org.jbpm.pvm.internal.repository.DeploymentObjectInputStream; import org.jbpm.pvm.internal.tx.DeserializedObject; import org.jbpm.pvm.internal.tx.Transaction; import org.jbpm.pvm.internal.type.Converter; @@ -71,7 +73,10 @@ byte[] bytes = (byte[]) o; try { ByteArrayInputStream bais = new ByteArrayInputStream(bytes); - ObjectInputStream ois = new ObjectInputStream(bais); + + ObjectInputStream ois = new DeploymentObjectInputStream(bais, + scopeInstance.getExecution().getProcessDefinition().getDeploymentId()); + Object object = ois.readObject(); Transaction transaction = EnvironmentImpl.getFromCurrent(Transaction.class, false); Index: modules/test-db/src/test/java/org/jbpm/test/variables/DeserializeVariableTest.java =================================================================== --- modules/test-db/src/test/java/org/jbpm/test/variables/DeserializeVariableTest.java (revision 0) +++ modules/test-db/src/test/java/org/jbpm/test/variables/DeserializeVariableTest.java (revision 0) @@ -0,0 +1,118 @@ +package org.jbpm.test.variables; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileWriter; +import java.util.List; + +import org.codehaus.janino.DebuggingInformation; +import org.codehaus.janino.util.StringPattern; +import org.codehaus.janino.util.enumerator.EnumeratorSet; +import org.jbpm.api.ProcessInstance; +import org.jbpm.api.task.Task; +import org.jbpm.test.JbpmTestCase; + + +public class DeserializeVariableTest extends JbpmTestCase { + + String deploymentId; + + protected void setUp() throws Exception { + + super.setUp(); + + generateBeanClass(); + + deploymentId = repositoryService.createDeployment() + .addResourceFromClasspath("org/jbpm/test/variables/DeserializeTaskTest.jpdl.xml") + .addResourceFromInputStream("org/jbpm/test/variables/Bean.class", new FileInputStream(new File("target/generated/org/jbpm/test/variables/Bean.class"))) + .deploy(); + + } + + protected void tearDown() throws Exception { + repositoryService.deleteDeploymentCascade(deploymentId); + super.tearDown(); + } + + + public void testDeserializeVariable() { + ProcessInstance processInstance = executionService.startProcessInstanceByKey("DeserializeTaskTest"); + String processInstanceId = processInstance.getId(); + + List tasks = taskService.findPersonalTasks("alex"); + + assertTrue(tasks.size() == 1); + + Task task = tasks.get(0); + + assertNotNull(taskService.getVariable(task.getId(), "bean")); + + assertNotNull(executionService.getVariable(processInstanceId, "bean")); + + taskService.completeTask(task.getId()); + } + + /** + * This method is used to generate source class that will be used within a process but should not be + * on class path while executing process but retrieved from db. + * + * Uses Janinio to compile the source. + */ + public void generateBeanClass() { + + log.debug("Inside generateBeanClass method"); + File directory = new File("target/generated/org/jbpm/test/variables"); + + if (!directory.exists()) { + log.debug("No generated class directory, about to create source file"); + try { + directory.mkdirs(); + File sourceFile = new File(directory, "Bean.java"); + FileWriter writer = new FileWriter(sourceFile); + + StringBuffer source = new StringBuffer(); + + source.append("package org.jbpm.test.variables;\n"); + source.append("import java.io.Serializable;\n"); + source.append("public class Bean implements Serializable {\n"); + source.append("private static final long serialVersionUID = -5510563444135221777L;\n"); + source.append(" private String value;\n"); + source.append(" public Bean getResult() {\n"); + source.append(" this.value = \"test\";\n"); + source.append(" return this;\n"); + source.append(" }\n"); + source.append("}\n"); + + writer.write(source.toString()); + + writer.close(); + log.debug("Source file create in " + directory.getAbsolutePath()); + + File destinationDirectory = org.codehaus.janino.Compiler.NO_DESTINATION_DIRECTORY; + File[] optionalSourcePath = null; + File[] classPath = { new File(".") }; + File[] optionalExtDirs = null; + File[] optionalBootClassPath = null; + String optionalCharacterEncoding = null; + boolean verbose = false; + EnumeratorSet debuggingInformation = DebuggingInformation.DEFAULT_DEBUGGING_INFORMATION; + StringPattern[] warningHandlePatterns = org.codehaus.janino.Compiler.DEFAULT_WARNING_HANDLE_PATTERNS; + boolean rebuild = false; + + log.debug("About to run Janinio compiler"); + + org.codehaus.janino.Compiler javac = new org.codehaus.janino.Compiler(optionalSourcePath, classPath, optionalExtDirs, optionalBootClassPath, + destinationDirectory, optionalCharacterEncoding, verbose, debuggingInformation, warningHandlePatterns, rebuild); + javac.compile(new File[] { sourceFile }); + + log.debug("Class compiled successfully"); + } catch (Exception e) { + + log.error("Error while creating additional resources", e); + } + } + + } + +}