Author: caleb.powell
Date: 2009-08-22 11:03:41 -0400 (Sat, 22 Aug 2009)
New Revision: 5506
Added:
projects/instance-migration/trunk/jbpm-instance-migrator/pom.xml
projects/instance-migration/trunk/jbpm-instance-migrator/src/
projects/instance-migration/trunk/jbpm-instance-migrator/src/main/
projects/instance-migration/trunk/jbpm-instance-migrator/src/main/java/
projects/instance-migration/trunk/jbpm-instance-migrator/src/main/java/org/
projects/instance-migration/trunk/jbpm-instance-migrator/src/main/java/org/jbpm/
projects/instance-migration/trunk/jbpm-instance-migrator/src/main/java/org/jbpm/instance/
projects/instance-migration/trunk/jbpm-instance-migrator/src/main/java/org/jbpm/instance/migration/
projects/instance-migration/trunk/jbpm-instance-migrator/src/main/java/org/jbpm/instance/migration/InvalidMigrationException.java
projects/instance-migration/trunk/jbpm-instance-migrator/src/main/java/org/jbpm/instance/migration/Migration.java
projects/instance-migration/trunk/jbpm-instance-migrator/src/main/java/org/jbpm/instance/migration/MigrationComparator.java
projects/instance-migration/trunk/jbpm-instance-migrator/src/main/java/org/jbpm/instance/migration/MigrationUtils.java
projects/instance-migration/trunk/jbpm-instance-migrator/src/main/java/org/jbpm/instance/migration/Migrator.java
projects/instance-migration/trunk/jbpm-instance-migrator/src/main/java/org/jbpm/instance/migration/StateNodeMap.java
projects/instance-migration/trunk/jbpm-instance-migrator/src/main/java/org/jbpm/instance/migration/util/
projects/instance-migration/trunk/jbpm-instance-migrator/src/main/java/org/jbpm/instance/migration/util/JbpmInstanceMigratorBaseTest.java
projects/instance-migration/trunk/jbpm-instance-migrator/src/main/java/org/jbpm/instance/migration/util/JbpmInstanceMigratorLogger.java
projects/instance-migration/trunk/jbpm-instance-migrator/src/main/java/org/jbpm/instance/migration/util/MigratorValiditionUtil.java
projects/instance-migration/trunk/jbpm-instance-migrator/src/site/
projects/instance-migration/trunk/jbpm-instance-migrator/src/site/apt/
projects/instance-migration/trunk/jbpm-instance-migrator/src/site/apt/cookbook.apt
projects/instance-migration/trunk/jbpm-instance-migrator/src/site/apt/fooprocessv1.gif
projects/instance-migration/trunk/jbpm-instance-migrator/src/site/apt/fooprocessv2.gif
projects/instance-migration/trunk/jbpm-instance-migrator/src/site/apt/index.apt
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/java/
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/java/org/
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/java/org/jbpm/
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/java/org/jbpm/instance/
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/java/org/jbpm/instance/migration/
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/java/org/jbpm/instance/migration/BaseTestCase.java
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/java/org/jbpm/instance/migration/BasicMigrationTest.java
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/java/org/jbpm/instance/migration/HibernateTestSupport.java
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/java/org/jbpm/instance/migration/MigrationComparatorTest.java
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/java/org/jbpm/instance/migration/MigrationUtilsTest.java
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/java/org/jbpm/instance/migration/MigratorAggregationTest.java
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/java/org/jbpm/instance/migration/SubprocessMigratorTest.java
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/java/org/jbpm/instance/migration/SuperstateMigratorTest.java
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/java/org/jbpm/instance/migration/TestMigration001.java
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/java/org/jbpm/instance/migration/TestMigration002.java
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/java/org/jbpm/instance/migration/TestMigration003.java
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/java/org/jbpm/instance/migration/util/
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/java/org/jbpm/instance/migration/util/MigratorValidityUtilTest.java
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/resources/
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/resources/hibernate.cfg.xml
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/resources/log4j.properties
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/resources/org/
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/resources/org/jbpm/
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/resources/org/jbpm/instance/
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/resources/org/jbpm/instance/migration/
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/resources/org/jbpm/instance/migration/mock-hibernate-spring.xml
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/resources/org/jbpm/instance/migration/simpleProcessDefinition_001.xml
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/resources/org/jbpm/instance/migration/simpleProcessDefinition_002.xml
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/resources/org/jbpm/instance/migration/simpleProcessDefinition_003.xml
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/resources/org/jbpm/instance/migration/simpleSubProcessDefinition_001.xml
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/resources/org/jbpm/instance/migration/simpleSubProcessDefinition_002.xml
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/resources/org/jbpm/instance/migration/simpleSuperProcessDefinition_001.xml
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/resources/org/jbpm/instance/migration/simpleSuperProcessDefinition_002.xml
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/resources/org/jbpm/instance/migration/superstateMigratorTest_001.xml
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/resources/org/jbpm/instance/migration/superstateMigratorTest_002.xml
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/resources/org/jbpm/instance/migration/superstateMigratorTest_003.xml
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/resources/org/jbpm/instance/migration/superstateMigratorTest_004.xml
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/resources/org/jbpm/instance/migration/util/
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/resources/org/jbpm/instance/migration/util/migratorValidityTestProcessDefinition_001.xml
Modified:
projects/instance-migration/trunk/jbpm-instance-migrator/
Log:
CP: Initial import
Property changes on: projects/instance-migration/trunk/jbpm-instance-migrator
___________________________________________________________________
Name: svn:ignore
+ target
Added: projects/instance-migration/trunk/jbpm-instance-migrator/pom.xml
===================================================================
--- projects/instance-migration/trunk/jbpm-instance-migrator/pom.xml
(rev 0)
+++ projects/instance-migration/trunk/jbpm-instance-migrator/pom.xml 2009-08-22 15:03:41
UTC (rev 5506)
@@ -0,0 +1,228 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>jbpm</groupId>
+ <artifactId>jbpm-instance-migration</artifactId>
+ <name>jBPM Instance Migrator</name>
+ <version>1.2-SNAPSHOT</version>
+ <description />
+
+ <scm>
+ <connection>scm:cvs:pserver:cvs:cvs@shroma:/data/cvsroot:jpbm-migrator</connection>
+ <developerConnection>scm:cvs:pserver:cvs:cvs@shroma:/data/cvsroot:jbpm-migrator</developerConnection>
+ <url>scm:cvs:pserver:cvs:cvs@shroma:/data/cvsroot:jpbm-migrator</url>
+ </scm>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.4</source>
+ <target>1.4</target>
+ </configuration>
+ </plugin>
+ </plugins>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-release-plugin</artifactId>
+ <version>2.0-beta-8</version>
+ <configuration>
+
<tagBase>scm:cvs:pserver:cvs:cvs@shroma:/data/cvsroot:${project.artifactId}</tagBase>
+ </configuration>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ </build>
+
+ <!--
+ <distributionManagement>
+ <site>
+ <id>intranet.intelliware.ca</id>
+
<url>dav:http://intranet/internal/intelliware/hwng-projects/jbpm-migrator</url>
+ </site>
+ <repository>
+ <id>intelliwareReleases</id>
+ <name>Intelliware Releases</name>
+ <url>dav:http://mvnrepo.intelliware.ca/release</url>
+ </repository>
+ <snapshotRepository>
+ <id>intelliwareSnapshots</id>
+ <name>Intelliware Snapshots</name>
+ <url>dav:http://mvnrepo.intelliware.ca/snapshot</url>
+ <uniqueVersion>false</uniqueVersion>
+ </snapshotRepository>
+ </distributionManagement>
+ -->
+
+ <dependencies>
+ <dependency>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ <version>1.2.6</version>
+ </dependency>
+ <dependency>
+ <groupId>jbpm</groupId>
+ <artifactId>jbpm-jpdl</artifactId>
+ <version>3.2.2</version>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>3.8.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.hibernate</groupId>
+ <artifactId>hibernate</artifactId>
+ <version>3.2.3.ga</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-beanutils</groupId>
+ <artifactId>commons-beanutils</artifactId>
+ <version>1.7.0</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-collections</groupId>
+ <artifactId>commons-collections</artifactId>
+ <version>3.2</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-lang</groupId>
+ <artifactId>commons-lang</artifactId>
+ <version>2.2</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-io</groupId>
+ <artifactId>commons-io</artifactId>
+ <version>1.2</version>
+ </dependency>
+ <dependency>
+ <groupId>antlr</groupId>
+ <artifactId>antlr</artifactId>
+ <version>2.7.6</version>
+ </dependency>
+ <dependency>
+ <groupId>bsh</groupId>
+ <artifactId>bsh</artifactId>
+ <version>1.3.0</version>
+ </dependency>
+
+ <!-- asm jars -->
+ <dependency>
+ <groupId>asm</groupId>
+ <artifactId>asm-attrs</artifactId>
+ <version>1.5.3</version>
+ </dependency>
+ <dependency>
+ <groupId>asm</groupId>
+ <artifactId>asm-tree</artifactId>
+ <version>1.5.3</version>
+ </dependency>
+ <dependency>
+ <groupId>asm</groupId>
+ <artifactId>asm-util</artifactId>
+ <version>1.5.3</version>
+ </dependency>
+ <dependency>
+ <groupId>dom4j</groupId>
+ <artifactId>dom4j</artifactId>
+ <version>1.6</version>
+ </dependency>
+ <dependency>
+ <groupId>cglib</groupId>
+ <artifactId>cglib</artifactId>
+ <version>2.1_3</version>
+ </dependency>
+
+ <!-- Test dependencies -->
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring</artifactId>
+ <version>2.0.2</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>hsqldb</groupId>
+ <artifactId>hsqldb</artifactId>
+ <version>1.8.0.7</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>jmock</groupId>
+ <artifactId>jmock-cglib</artifactId>
+ <version>1.1.0</version>
+ <exclusions>
+ <exclusion>
+ <groupId>cglib</groupId>
+ <artifactId>cglib-full</artifactId>
+ </exclusion>
+ </exclusions>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>javax.jcr</groupId>
+ <artifactId>jcr</artifactId>
+ <version>1.0</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>xml-apis</groupId>
+ <artifactId>xml-apis</artifactId>
+ <version>1.0.b2</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <reporting>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-report-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jxr-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-pmd-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-changelog-plugin</artifactId>
+ <configuration>
+ <type>range</type>
+ <range>10</range><!-- last 10 days -->
+ <basedir>.</basedir><!-- default base dir is src/main/java but we
want all files -->
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>cobertura-maven-plugin</artifactId>
+ <version>2.0</version> <!-- IMPORTANT: version 2.1 is badly broken
-->
+ <configuration>
+ <check>
+ <branchRate>85</branchRate>
+ <lineRate>85</lineRate>
+ <haltOnFailure>true</haltOnFailure> <!-- sadly, this doesn't
work from mvn site -->
+ <totalBranchRate>85</totalBranchRate>
+ <totalLineRate>85</totalLineRate>
+ <packageLineRate>85</packageLineRate>
+ <packageBranchRate>85</packageBranchRate>
+ </check>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>jdepend-maven-plugin</artifactId>
+ </plugin>
+ </plugins>
+ </reporting>
+</project>
\ No newline at end of file
Added:
projects/instance-migration/trunk/jbpm-instance-migrator/src/main/java/org/jbpm/instance/migration/InvalidMigrationException.java
===================================================================
---
projects/instance-migration/trunk/jbpm-instance-migrator/src/main/java/org/jbpm/instance/migration/InvalidMigrationException.java
(rev 0)
+++
projects/instance-migration/trunk/jbpm-instance-migrator/src/main/java/org/jbpm/instance/migration/InvalidMigrationException.java 2009-08-22
15:03:41 UTC (rev 5506)
@@ -0,0 +1,29 @@
+package org.jbpm.instance.migration;
+
+/**
+ * A {@link RuntimeException} that indicates a problem with a Migration implementation.
+ * @see Migration
+ * @author Caleb Powell <caleb.powell(a)intelliware.ca>
+ * @author David Harcombe <david.harcombe(a)intelliware.ca>
+ */
+public class InvalidMigrationException extends RuntimeException {
+
+ private static final long serialVersionUID = -2640461160746119847L;
+
+ public InvalidMigrationException() {
+ super();
+ }
+
+ public InvalidMigrationException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public InvalidMigrationException(String message) {
+ super(message);
+ }
+
+ public InvalidMigrationException(Throwable cause) {
+ super(cause);
+ }
+
+}
Added:
projects/instance-migration/trunk/jbpm-instance-migrator/src/main/java/org/jbpm/instance/migration/Migration.java
===================================================================
---
projects/instance-migration/trunk/jbpm-instance-migrator/src/main/java/org/jbpm/instance/migration/Migration.java
(rev 0)
+++
projects/instance-migration/trunk/jbpm-instance-migrator/src/main/java/org/jbpm/instance/migration/Migration.java 2009-08-22
15:03:41 UTC (rev 5506)
@@ -0,0 +1,18 @@
+package org.jbpm.instance.migration;
+
+
+/**
+ * Defines the interface for an individual Migration Class. Classes that implement this
interface can
+ * be read from a Migrator.
+ * @author Caleb Powell <caleb.powell(a)intelliware.ca>
+ * @author David Harcombe <david.harcombe(a)intelliware.ca>
+ */
+public interface Migration {
+
+ /**
+ *
+ * @return A Map of nodes.
+ */
+ public StateNodeMap createNodeMap();
+
+}
Added:
projects/instance-migration/trunk/jbpm-instance-migrator/src/main/java/org/jbpm/instance/migration/MigrationComparator.java
===================================================================
---
projects/instance-migration/trunk/jbpm-instance-migrator/src/main/java/org/jbpm/instance/migration/MigrationComparator.java
(rev 0)
+++
projects/instance-migration/trunk/jbpm-instance-migrator/src/main/java/org/jbpm/instance/migration/MigrationComparator.java 2009-08-22
15:03:41 UTC (rev 5506)
@@ -0,0 +1,20 @@
+package org.jbpm.instance.migration;
+
+import java.util.Comparator;
+
+/**
+ * A comparator that compares Migration instances based on their revision.
+ *
+ * @see Migration
+ * @author Caleb Powell <caleb.powell(a)intelliware.ca>
+ * @author David Harcombe <david.harcombe(a)intelliware.ca>
+ */
+public class MigrationComparator implements Comparator {
+
+ public int compare(Object o1, Object o2) {
+ Migration migration1 = (Migration) o1;
+ Migration migration2 = (Migration) o2;
+ return migration1.getClass().getName().compareTo(migration2.getClass().getName());
+ }
+
+}
Added:
projects/instance-migration/trunk/jbpm-instance-migrator/src/main/java/org/jbpm/instance/migration/MigrationUtils.java
===================================================================
---
projects/instance-migration/trunk/jbpm-instance-migrator/src/main/java/org/jbpm/instance/migration/MigrationUtils.java
(rev 0)
+++
projects/instance-migration/trunk/jbpm-instance-migrator/src/main/java/org/jbpm/instance/migration/MigrationUtils.java 2009-08-22
15:03:41 UTC (rev 5506)
@@ -0,0 +1,150 @@
+package org.jbpm.instance.migration;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang.StringUtils;
+import org.apache.log4j.Logger;
+import org.jbpm.JbpmContext;
+import org.jbpm.graph.def.ProcessDefinition;
+import org.jbpm.graph.exe.ProcessInstance;
+import org.jbpm.graph.exe.Token;
+import org.jbpm.instance.migration.util.JbpmInstanceMigratorLogger;
+
+
+/**
+ * Provides utility methods to the Migrator class.
+ *
+ * @see Migrator
+ * @author Caleb Powell <caleb.powell(a)intelliware.ca>
+ * @author David Harcombe <david.harcombe(a)intelliware.ca>
+ */
+public class MigrationUtils {
+
+ private static Logger logger = Logger.getLogger(JbpmInstanceMigratorLogger.class);
+
+ /**
+ * Convert an xml file into a valid jBPM ProcessDefinition class
+ *
+ * @param filename The xml file containing the ProcessDefinition definition
+ * @return A ProcessDefinition
+ * @throws IOException
+ */
+ public static ProcessDefinition getProcessDefinition(String filename) throws IOException
{
+ String processDefinition = FileUtils.readFileToString(new
File(MigrationUtils.class.getResource(filename).getPath()), "UTF-8");
+ return ProcessDefinition.parseXmlString(processDefinition);
+ }
+
+ /**
+ * Taking a base class name, this method will search the Classpath for all Migrations
that begin with that name. The migrations will be returned
+ * in an array. For example, given the base Class name 'com.foo.BarMigration',
this method will attempt to load classes named
+ * 'com.foo.BarMigration001', 'com.foo.BarMigration002',
'com.foo.BarMigration003', etc. It will stop loading when it catches a {@link
ClassNotFoundException}.
+ *
+ * Valid Migration classes must implement the {@link Migration} interface (but not be an
interface themselves), have a default constructor, and cannot be abstract.
+ *
+ * @param baseClassName
+ * @return
+ */
+ public static Migration[] lookupMigrationsFor(String baseClassName) {
+ int revision = 0;
+ List migrations = new ArrayList();
+ while (true) {
+ String migrationName = constructMigrationClassName(baseClassName, ++revision);
+ try {
+ Class migrationClass = Class.forName(migrationName);
+ if (isValidMigration(migrationClass)) {
+ migrations.add(migrationClass.newInstance());
+ }
+ } catch (ClassNotFoundException e) {
+ if(CollectionUtils.isEmpty(migrations)) {
+ logger.info("Could not locate any migrations for the base Class name [" +
baseClassName + "].");
+ }
+ break;
+ } catch (InstantiationException e) {
+ String errorMessage = "The " + migrationName + " migration could not
be instantiated. Please ensure it has a default constructor.";
+ logger.error(errorMessage, e);
+ throw new InvalidMigrationException(errorMessage, e);
+ } catch (IllegalAccessException e) {
+ String errorMessage = "The " + migrationName + " migration could not
be instantiated.";
+ logger.error(errorMessage, e);
+ throw new InvalidMigrationException(errorMessage, e);
+ }
+ }
+ return (Migration[]) migrations.toArray(new Migration[migrations.size()]);
+ }
+
+ /**
+ * The method joins a base Class name and a revision number. It will pad the revision
number if necessary.
+ * @param baseClassName
+ * @param revision
+ * @return
+ */
+ private static String constructMigrationClassName(String baseClassName, int revision) {
+ return baseClassName + StringUtils.leftPad(Integer.toString(revision), 3,
"0");
+ }
+
+ /**
+ *
+ * @param migrationClass
+ * @return true is this class is an assignable to {@link Migration}, is not an
interface, and is not abstract.
+ */
+ private static boolean isValidMigration(Class migrationClass) {
+ return Migration.class.isAssignableFrom(migrationClass) &&
!migrationClass.isInterface() &&
!Modifier.isAbstract(migrationClass.getModifiers());
+ }
+
+ /**
+ * Used to determine whether a ProcessInstance requires migration.
+ * @param processInstance
+ * @return true if the processInstance (or any of it's subProcessInstance's)
belongs to an outdated processDefinition.
+ */
+ public static boolean requiresMigration(ProcessInstance processInstance, JbpmContext
jbpmContext) {
+ ProcessDefinition latestProcessDefinition =
MigrationUtils.findLatestProcessDefinition(processInstance.getProcessDefinition().getName(),
jbpmContext);
+ //1. look at the given process definition
+ boolean processInstanceRequiresMigration =
processInstance.getProcessDefinition().getVersion() !=
latestProcessDefinition.getVersion();
+
+ //2. search for sub process definitions
+ List subProcesses = findSubProcesses(processInstance.getRootToken());
+ for (Iterator iter = subProcesses.iterator(); processInstanceRequiresMigration == false
&& iter.hasNext();) {
+ ProcessInstance subProcessInstance = (ProcessInstance) iter.next();
+ processInstanceRequiresMigration = requiresMigration(subProcessInstance,
jbpmContext);
+ }
+ logger.info("Checking whether process instance[@id='" +
processInstance.getId()+"'] requires migration? => " +
processInstanceRequiresMigration);
+ return processInstanceRequiresMigration ;
+ }
+
+ private static List findSubProcesses(Token token) {
+ ArrayList processInstances = new ArrayList();
+ ProcessInstance processInstance = token.getSubProcessInstance();
+ if(processInstance != null){
+ processInstances.add(processInstance);
+ processInstances.addAll(findSubProcesses(processInstance.getRootToken()));
+ }
+
+ Map children = token.getChildren();
+ if(children != null){
+ for (Iterator iter = children.values().iterator(); iter.hasNext();) {
+ Token childToken = (Token) iter.next();
+ processInstances.addAll(findSubProcesses(childToken));
+ }
+ }
+ return processInstances;
+ }
+
+ /**
+ * Used to find a {@link ProcessDefinition} by it's name.
+ *
+ * @param processName The name of the process definition.
+ * @param jbpmContext
+ * @return
+ */
+ public static ProcessDefinition findLatestProcessDefinition(String processName,
JbpmContext jbpmContext) {
+ return jbpmContext.getGraphSession().findLatestProcessDefinition(processName);
+ }
+}
Added:
projects/instance-migration/trunk/jbpm-instance-migrator/src/main/java/org/jbpm/instance/migration/Migrator.java
===================================================================
---
projects/instance-migration/trunk/jbpm-instance-migrator/src/main/java/org/jbpm/instance/migration/Migrator.java
(rev 0)
+++
projects/instance-migration/trunk/jbpm-instance-migrator/src/main/java/org/jbpm/instance/migration/Migrator.java 2009-08-22
15:03:41 UTC (rev 5506)
@@ -0,0 +1,286 @@
+package org.jbpm.instance.migration;
+
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.collections.MapUtils;
+import org.apache.commons.lang.ArrayUtils;
+import org.apache.log4j.Logger;
+import org.jbpm.JbpmContext;
+import org.jbpm.context.exe.ContextInstance;
+import org.jbpm.graph.def.Node;
+import org.jbpm.graph.def.ProcessDefinition;
+import org.jbpm.graph.def.SuperState;
+import org.jbpm.graph.exe.ProcessInstance;
+import org.jbpm.graph.exe.Token;
+import org.jbpm.graph.node.EndState;
+import org.jbpm.graph.node.Fork;
+import org.jbpm.graph.node.Join;
+import org.jbpm.graph.node.ProcessState;
+import org.jbpm.graph.node.StartState;
+import org.jbpm.graph.node.State;
+import org.jbpm.instance.migration.util.JbpmInstanceMigratorLogger;
+
+
+
+/**
+ * An instance of this class is responsible for migrating a process instance to te latest
version.
+ * @author Caleb Powell <caleb.powell(a)intelliware.ca>
+ * @author David Harcombe <david.harcombe(a)intelliware.ca>
+ */
+public class Migrator {
+
+ private static Logger logger = Logger.getLogger(JbpmInstanceMigratorLogger.class);
+ private static final String ROOT_TOKEN_NAME = "Root token";
+ private final SortedSet migrations = new TreeSet(new MigrationComparator());
+ private final Map subProcessMigrators = new HashMap();
+ private final JbpmContext jbpmContext;
+ private final String processDefinitionName;
+ private final StateNodeMap compositeNodeMap = new StateNodeMap();
+ public static Set SUPPORTED_WAIT_STATE_NODE_TYPES = new HashSet(){
+ private static final long serialVersionUID = 9100798202825510066L;
+ {
+ add(StartState.class);
+ add(EndState.class);
+ add(State.class);
+ add(Fork.class);
+ add(Join.class);
+ add(ProcessState.class);
+ add(SuperState.class);
+ }};
+
+ /**
+ *
+ * @param processDefinitionName The name of the ProcessDefinition that this migrator is
responsible for.
+ * @param jbpmContext A JBPMContext that the migrator can use to look up the latest
ProcessDefinition (among other things).
+ * @param migrations An arrray of migration instances.
+ * @param subProcessMigrators An array of migrator classes for any subprocesses that
this Migrator may encounter.
+ * @throws InvalidMigrationException
+ */
+ public Migrator(String processDefinitionName, JbpmContext jbpmContext, Migration[]
migrations, Migrator[] subProcessMigrators) throws InvalidMigrationException {
+ this.processDefinitionName = processDefinitionName;
+ this.jbpmContext = jbpmContext;
+
+ if(!ArrayUtils.isEmpty(migrations)) {
+ CollectionUtils.addAll(this.migrations, migrations);
+ }
+
+ for (int i = 0; subProcessMigrators != null && i <
subProcessMigrators.length; i++) {
+ this.subProcessMigrators.put(subProcessMigrators[i].getProcessDefinitionName(),
subProcessMigrators[i]);
+ }
+
+ populateCompositeNodeMap();
+ }
+
+ /**
+ *
+ * @param processDefinitionName The name of the ProcessDefinition that this migrator is
responsible for.
+ * @param jbpmContext A JBPMContext that the migrator can use to look up the latest
ProcessDefinition (among other things).
+ * @param baseClassName The base name for the migration classes. For example, if given
'ca.intelliware.foo.FooProcess' as the baseClassName, the migrator
+ * will attempt load 'ca.intelliware.foo.FooProcess001',
''ca.intelliware.foo.FooProcess002', etc.
+ * @param subProcessMigrators An array of migrator classes for any subprocesses that
this Migrator may encounter.
+ * @throws InvalidMigrationException
+ */
+ public Migrator(String processDefinitionName, JbpmContext jbpmContext, String
baseClassName, Migrator[] subProcessMigrators) throws InvalidMigrationException {
+ this(processDefinitionName, jbpmContext,
MigrationUtils.lookupMigrationsFor(baseClassName), subProcessMigrators);
+ }
+
+ /**
+ *
+ * @param processDefinitionName The name of the ProcessDefinition that this migrator is
responsible for.
+ * @param jbpmContext A JBPMContext that the migrator can use to look up the latest
ProcessDefinition (among other things).
+ * @param baseClassName The base name for the migration classes. For example, if given
'ca.intelliware.foo.FooProcess' as the baseClassName, the migrator
+ * will attempt load 'ca.intelliware.foo.FooProcess001',
''ca.intelliware.foo.FooProcess002', etc.
+ * @throws InvalidMigrationException
+ */
+ public Migrator(String processDefinitionName, JbpmContext jbpmContext, String
baseClassName) throws InvalidMigrationException {
+ this(processDefinitionName, jbpmContext,
MigrationUtils.lookupMigrationsFor(baseClassName), null);
+ }
+
+ /**
+ * Migrates the ProcessInstance instance to the latest version.
+ * @param processInstance The processInstance that you wish to migrate.
+ * @return A migrated processInstance based on the latest version of this Migrator's
ProcessDefinition.
+ * @throws InvalidMigrationException
+ */
+ public ProcessInstance migrate(ProcessInstance processInstance) {
+ if(!processInstance.getProcessDefinition().getName().equals(getProcessDefinitionName())){
+ String errorMessage = "The "+getProcessDefinitionName()+" migrator
cannot migrate a processInstance of the
"+processInstance.getProcessDefinition().getName()+" ProcessDefinition!";
+ logger.error(errorMessage);
+ throw new IllegalArgumentException(errorMessage);
+ }
+
+ if(processRequiresMigration(processInstance, jbpmContext)) {
+ logger.info(getProcessDefinitionName()+" Migrator attempting to migrate
processInstance[(a)id="+processInstance.getId()+"].");
+ processInstance = migrateOldProcessInstance(processInstance);
+ logger.info(getProcessDefinitionName()+" Migrator finished migration of
processInstance[(a)id="+processInstance.getId()+"].");
+ }
+ return processInstance;
+ }
+
+ /**
+ * This method iterates through 'migrations' list and populates the
compositeNodeMap with each Migration mappings.
+ * @throws InvalidMigrationException
+ */
+ private void populateCompositeNodeMap() {
+ for (Iterator iterator = this.migrations.iterator(); iterator.hasNext();) {
+ Migration currentMigration = (Migration) iterator.next();
+ logger.debug("Adding the " + currentMigration.getClass().getName()+"
migration node mappings to the composite node map.");
+ this.compositeNodeMap.addMigration(currentMigration);
+ }
+ }
+
+ private ProcessInstance migrateOldProcessInstance(ProcessInstance processInstance) {
+ ProcessInstance newProcessInstance =
MigrationUtils.findLatestProcessDefinition(processInstance.getProcessDefinition().getName(),
jbpmContext).createProcessInstance();
+ migrateContextInstance(processInstance, newProcessInstance);
+ mapAllTokens(null, processInstance.getRootToken(), newProcessInstance);
+ return newProcessInstance;
+ }
+
+ private boolean processRequiresMigration(ProcessInstance processInstance, JbpmContext
jbpmContext) {
+ return MigrationUtils.requiresMigration(processInstance, jbpmContext);
+ }
+
+ private void migrateContextInstance(ProcessInstance oldProcessInstance, ProcessInstance
newProcessInstance) {
+ ContextInstance oldContextInstance = oldProcessInstance.getContextInstance();
+ ContextInstance newContextInstance = newProcessInstance.getContextInstance();
+ migratePersistedVariables(oldContextInstance, newContextInstance);
+ migrateTransientVariables(oldContextInstance, newContextInstance);
+ addMigrationMemo(newContextInstance, oldProcessInstance, newProcessInstance);
+ }
+
+ private void addMigrationMemo(ContextInstance newContextInstance, ProcessInstance
oldProcessInstance,
+ ProcessInstance newProcessInstance) {
+ int oldVersion = oldProcessInstance.getProcessDefinition().getVersion();
+ int newVersion = newProcessInstance.getProcessDefinition().getVersion();
+ Date today = Calendar.getInstance().getTime();
+ newContextInstance.createVariable("migrationMemo",
createMigrationMemo(oldVersion, newVersion, today, oldProcessInstance.getId()));
+ }
+
+ private String createMigrationMemo(int oldVersion, int newVersion, Date today, long
predecessorProcessId) {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append("Process migrated from version [");
+ buffer.append(oldVersion);
+ buffer.append("] to [");
+ buffer.append(newVersion);
+ buffer.append("] on ");
+ buffer.append(today.toString());
+ buffer.append(". Predecessor process instance id => ");
+ buffer.append(predecessorProcessId);
+ return buffer.toString();
+ }
+
+ private void migrateTransientVariables(ContextInstance contextInstance, ContextInstance
newContextInstance) {
+ if (MapUtils.isNotEmpty(contextInstance.getTransientVariables())) {
+ logger.info(getProcessDefinitionName()+" Migrator is migrating the
TransientVariables map");
+ newContextInstance.setTransientVariables(contextInstance.getTransientVariables());
+ }
+ }
+
+ private void migratePersistedVariables(ContextInstance contextInstance, ContextInstance
newContextInstance) {
+ if (MapUtils.isNotEmpty(contextInstance.getVariables())) {
+ logger.info(getProcessDefinitionName()+" Migrator is migrating the
PersistedVariables map");
+ newContextInstance.setVariables(contextInstance.getVariables());
+ }
+ }
+
+ private void mapAllTokens(Token parentToken, Token oldProcessToken, ProcessInstance
newProcessInstance) {
+ mapProcessToken(parentToken, oldProcessToken, newProcessInstance);
+ mapChildTokens(oldProcessToken, newProcessInstance);
+ }
+
+ private void mapProcessToken(Token parentToken, Token oldToken, ProcessInstance
newInstance) {
+ Node toNode = findCurrentNode(oldToken);
+ Token newToken = createNewToken(parentToken, oldToken, newInstance, toNode);
+ if(oldToken.getSubProcessInstance() != null) {
+ mapSubProcess(oldToken, newToken);
+ }
+ }
+
+ private Token createNewToken(Token parentToken, Token oldToken, ProcessInstance
newInstance, Node toNode) {
+ Token newToken;
+ logger.info(getProcessDefinitionName()+" Migrator creating new Token named
'"+getTokenName(oldToken)+"'");
+ if (oldToken.isRoot()) {
+ newToken = newInstance.getRootToken();
+ } else {
+ newToken = new Token(parentToken, getTokenName(oldToken));
+ }
+ newToken.setNodeEnter(new Date());
+ newToken.setNode(toNode);
+ logger.info(getProcessDefinitionName()+" Migrator has converted node token
["+ getTokenName(oldToken) +"] from ["+
oldToken.getNode().getFullyQualifiedName()+"] to
["+toNode.getFullyQualifiedName()+"] for process
["+newInstance.getProcessDefinition().getName()+"]");
+ return newToken;
+ }
+
+ private String getTokenName(Token token) {
+ return token.getName() == null ? ROOT_TOKEN_NAME : token.getName();
+ }
+
+ private void mapSubProcess(Token oldSuperProcessToken, Token newSuperProcessToken) {
+ ProcessInstance oldSubProcess = oldSuperProcessToken.getSubProcessInstance();
+ logger.info(getProcessDefinitionName() + " migrator is attempting to migrate a
"+oldSubProcess.getProcessDefinition().getName()+ " sub-process
instance.");
+ ProcessDefinition newSubProcessDefinition =
this.jbpmContext.getGraphSession().findLatestProcessDefinition(oldSubProcess.getProcessDefinition().getName());
+
+ ProcessInstance newSubProcessInstance
= getSubProcessMigrator(newSubProcessDefinition.getName()).migrateOldProcessInstance(oldSubProcess);
+ newSubProcessInstance.setSuperProcessToken(newSuperProcessToken);
+ newSuperProcessToken.setSubProcessInstance(newSubProcessInstance);
+ }
+
+ private Migrator getSubProcessMigrator(String processDefinitionName) {
+ if(!this.subProcessMigrators.containsKey(processDefinitionName)){
+ //create a default migrator for the subprocess definition
+ Migrator subProcessMigrator = new Migrator(processDefinitionName, jbpmContext, new
Migration[]{}, new Migrator[]{});
+ subProcessMigrators.put(processDefinitionName, subProcessMigrator);
+ }
+ return (Migrator) this.subProcessMigrators.get(processDefinitionName);
+ }
+
+ private void mapChildTokens(Token oldProcessToken, ProcessInstance newProcessInstance)
{
+ if (oldProcessToken.getChildren() != null) {
+ Iterator childTokenIter = oldProcessToken.getChildren().values().iterator();
+ while (childTokenIter.hasNext()) {
+ Token childToken = (Token) childTokenIter.next();
+ mapAllTokens(newProcessInstance.getRootToken(), childToken, newProcessInstance);
+ }
+ }
+ }
+
+ private Node findCurrentNode(Token oldProcessToken) {
+ ProcessDefinition targetDefinition =
MigrationUtils.findLatestProcessDefinition(oldProcessToken.getProcessInstance().getProcessDefinition().getName(),
jbpmContext);
+ String nodeName = oldProcessToken.getNode().getFullyQualifiedName();
+ String currentNodeName = this.compositeNodeMap.containsDeprecatedNodeName(nodeName) ?
this.compositeNodeMap.getCurrentNodeName(nodeName) : nodeName;
+ logger.debug(getProcessDefinitionName()+" Migrator.findCurrentNode: mapping
'"+nodeName+"' => '"+currentNodeName+"'");
+ Node toNode = targetDefinition.findNode(currentNodeName);
+ return toNode;
+ }
+
+ private String getProcessDefinitionName() {
+ return this.processDefinitionName;
+ }
+
+ /**
+ *
+ * @param processDefinition
+ * @return true if the processDefinition parameter's name attribute is equal to the
+ * processDefinitionName attribute of this Migrator instance.
+ */
+ public boolean willMigrate(ProcessDefinition processDefinition){
+ return this.processDefinitionName.equals(processDefinition.getName());
+ }
+
+ /**
+ * Returns this Migrator's {@link StateNodeMap}, which is a composite of all the
+ * Migrations' {@link StateNodeMap}'s.
+ * @return
+ */
+ public StateNodeMap getStateNodeMap() {
+ return this.compositeNodeMap;
+ }
+}
Added:
projects/instance-migration/trunk/jbpm-instance-migrator/src/main/java/org/jbpm/instance/migration/StateNodeMap.java
===================================================================
---
projects/instance-migration/trunk/jbpm-instance-migrator/src/main/java/org/jbpm/instance/migration/StateNodeMap.java
(rev 0)
+++
projects/instance-migration/trunk/jbpm-instance-migrator/src/main/java/org/jbpm/instance/migration/StateNodeMap.java 2009-08-22
15:03:41 UTC (rev 5506)
@@ -0,0 +1,142 @@
+package org.jbpm.instance.migration;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.collections.MapUtils;
+import org.apache.commons.lang.StringUtils;
+
+/**
+ * This class is used to compile a list of node name mappings for one or more
Migrations.
+ * It is is backed by a synchronized {@link HashMap}
+ * @author Caleb Powell <caleb.powell(a)intelliware.ca>
+ * @author David Harcombe <david.harcombe(a)intelliware.ca>
+ */
+public class StateNodeMap {
+
+ private final Map backingMap = MapUtils.synchronizedMap(new HashMap());
+
+ public StateNodeMap() {
+ }
+
+ /**
+ * Take a String[][] containing the node conversion mappings to be performed and convert
them
+ * into a Map we can use elsewhere.
+ *
+ * @param nodeMap Array of conversion mappings
+ * @return Map of node conversion mappings
+ */
+ public StateNodeMap(String[][] nodeMap) {
+ for (int i = 0; i < nodeMap.length; i++) {
+ String from = nodeMap[i][0];
+ String to = nodeMap[i][1];
+ if(StringUtils.isBlank(from)) {
+ continue;
+ }
+ addNodeMapping(from, to);
+ }
+ }
+
+ /**
+ * Given a deprecated node name, this method will return the name of the node which has
superseded
+ * it (the <i>current</i> node).
+ * @param deprecatedNodeName The name of a deprecated node.
+ * @return The name of the node that supersedes the deprecated node.
+ */
+ public String getCurrentNodeName(String deprecatedNodeName){
+ return (String) backingMap.get(deprecatedNodeName);
+ }
+
+ /**
+ *
+ * @param nodeName
+ * @return true if this map contains the deprecated node.
+ */
+ public boolean containsDeprecatedNodeName(String nodeName){
+ return backingMap.containsKey(nodeName);
+ }
+
+ /**
+ *
+ * @param nodeName
+ * @return true if this map contains the current node.
+ */
+ public boolean containsCurrentNodeName(String currentNodeName) {
+ return backingMap.containsValue(currentNodeName);
+ }
+
+ /**
+ *
+ * @return a Set of deprecated node names.
+ */
+ public Set deprecatedNodeNames() {
+ return backingMap.keySet();
+ }
+
+ /**
+ *
+ * @return a {@link Collection} of current node names.
+ */
+ public Collection currentNodeNames() {
+ return backingMap.values();
+ }
+
+ /**
+ * Adds the deprecated and current nodes to this map.
+ * @param deprecatedNodeName
+ * @param currentNodeName
+ * @throws {@link InvalidMigrationException} if the currentNodeName was previously added
as a deprecated node.
+ */
+ public void addNodeMapping(String deprecatedNodeName, String currentNodeName) {
+ if(this.containsDeprecatedNodeName(currentNodeName)) {
+ throw new InvalidMigrationException("Invalid Node Mapping
['"+deprecatedNodeName+"' =>
'"+currentNodeName+"']! The '"+currentNodeName+"' node
was deprecated by a previous migration.");
+ }
+ updateCurrentNodeNames(deprecatedNodeName, currentNodeName);
+ backingMap.put(deprecatedNodeName, currentNodeName);
+ }
+
+ /**
+ * Searches the entries in the backingMap. If an Entry contains a value equal to the
+ * deprecatedNodeName, the value will be replaced with the currentNodeName.
+ * @param deprecatedNodeName The value that will be replaced
+ * @param currentNodeName The replacement value
+ */
+ private void updateCurrentNodeNames(String deprecatedNodeName, String currentNodeName)
{
+ Iterator allEntries = this.backingMap.entrySet().iterator();
+ while (allEntries.hasNext()) {
+ Map.Entry entry = (Map.Entry) allEntries.next();
+ if (entry.getValue().equals(deprecatedNodeName)) {
+ entry.setValue(currentNodeName);
+ }
+ }
+ }
+
+ /**
+ * Adds the {@link StateNodeMap} from the provided Migration to this map.
+ * @param migration
+ * @throws {@link InvalidMigrationException} if the migration paramater contains a
<i>current</i> node that is in this map's <i>deprecated</i>
node list.
+ */
+ public void addMigration(Migration migration) {
+ addStateNodeMap(migration.createNodeMap());
+ }
+
+ /**
+ * Adds each entry in the provided stateNodeMap to this nodeMap.
+ * @param stateNodeMap
+ * @throws {@link InvalidMigrationException} if the stateNodeMap paramater contains a
<i>current</i> node that is
+ * in this map's <i>deprecated</i> node list.
+ */
+ private void addStateNodeMap(StateNodeMap stateNodeMap) {
+ Iterator deprecatedNodes = stateNodeMap.deprecatedNodeNames().iterator();
+ while (deprecatedNodes.hasNext()) {
+ String deprecatedNodeName = (String) deprecatedNodes.next();
+ String currentNodeName = stateNodeMap.getCurrentNodeName(deprecatedNodeName);
+ addNodeMapping(deprecatedNodeName, currentNodeName);
+ }
+ }
+
+
+}
Added:
projects/instance-migration/trunk/jbpm-instance-migrator/src/main/java/org/jbpm/instance/migration/util/JbpmInstanceMigratorBaseTest.java
===================================================================
---
projects/instance-migration/trunk/jbpm-instance-migrator/src/main/java/org/jbpm/instance/migration/util/JbpmInstanceMigratorBaseTest.java
(rev 0)
+++
projects/instance-migration/trunk/jbpm-instance-migrator/src/main/java/org/jbpm/instance/migration/util/JbpmInstanceMigratorBaseTest.java 2009-08-22
15:03:41 UTC (rev 5506)
@@ -0,0 +1,60 @@
+package org.jbpm.instance.migration.util;
+
+import java.io.InputStream;
+
+import org.apache.commons.lang.StringUtils;
+import org.jbpm.graph.def.ProcessDefinition;
+import org.jbpm.instance.migration.Migrator;
+
+
+import junit.framework.TestCase;
+
+/**
+ *
+ * @author Caleb Powell <caleb.powell(a)intelliware.ca>
+ * @author David Harcombe <david.harcombe(a)intelliware.ca>
+ */
+public abstract class JbpmInstanceMigratorBaseTest extends TestCase {
+
+ public static void assertMigratorValidity(Migrator migrator, ProcessDefinition
processDefinition){
+ assertThatTheMigratorWillMigrateTheProvidedProcessDefinition(processDefinition,
migrator);
+ assertTheValidityOfTheMigratorsDeprecatedNodes(processDefinition, migrator);
+ assertThatCurrentNodesAreValidWaitStateNodes(processDefinition, migrator);
+ assertThatCurrentNodesExistInTheProcessDefinition(processDefinition, migrator);
+ }
+
+ protected ProcessDefinition createProcessDefinition(String processDefinitionFileName) {
+ InputStream processDefinitionStream =
getClass().getResourceAsStream(processDefinitionFileName);
+ ProcessDefinition processDefinition =
ProcessDefinition.parseXmlInputStream(processDefinitionStream);
+ return processDefinition;
+ }
+
+ private static void
assertThatTheMigratorWillMigrateTheProvidedProcessDefinition(ProcessDefinition
processDefinition, Migrator migrator) {
+ assertTrue("The provided migrator is not capable of migrating the
'"+processDefinition.getName()+"' ProcessDefinition!",
migrator.willMigrate(processDefinition));
+ }
+
+ private static void assertTheValidityOfTheMigratorsDeprecatedNodes(ProcessDefinition
processDefinition, Migrator migrator){
+ String[] deprecatedNodes =
MigratorValiditionUtil.findDeprecatedNodesInProcessDefinition(processDefinition,
migrator);
+ if(deprecatedNodes != null && deprecatedNodes.length > 0){
+ String errorMessage = "The '"+processDefinition.getName()+"'
ProcessDefinition contains the following nodes that were deprecated in the migrator
["+StringUtils.join(deprecatedNodes, ", ")+"]. You cannot re-introduce
a deprecated node to a ProcessDefinition!";
+ fail(errorMessage);
+ }
+ }
+
+ private static void assertThatCurrentNodesExistInTheProcessDefinition(ProcessDefinition
processDefinition, Migrator migrator) {
+ String[] missingCurrentNodes =
MigratorValiditionUtil.findMissingCurrentNodesInTheProcessDefinition(processDefinition,
migrator);
+ if(missingCurrentNodes != null && missingCurrentNodes.length > 0){
+ String errorMessage = "The '"+processDefinition.getName()+"'
ProcessDefinition is missing the following current nodes declared in the migrator
["+StringUtils.join(missingCurrentNodes, ", ")+"]. If these nodes were
removed, you must create a Migration that deprecates them!";
+ fail(errorMessage);
+ }
+ }
+
+ private static void assertThatCurrentNodesAreValidWaitStateNodes(ProcessDefinition
processDefinition, Migrator migrator) {
+ String[] invalidWaitStateNodes =
MigratorValiditionUtil.findCurrentNodesThatAreInvalidWaitStates(processDefinition,
migrator);
+ if(invalidWaitStateNodes != null && invalidWaitStateNodes.length > 0){
+ String errorMessage = "The '"+processDefinition.getName()+"'
Migrator contains current nodes that are not valid wait states
["+StringUtils.join(invalidWaitStateNodes, ", ")+"]";
+ fail(errorMessage);
+ }
+ }
+
+}
Added:
projects/instance-migration/trunk/jbpm-instance-migrator/src/main/java/org/jbpm/instance/migration/util/JbpmInstanceMigratorLogger.java
===================================================================
---
projects/instance-migration/trunk/jbpm-instance-migrator/src/main/java/org/jbpm/instance/migration/util/JbpmInstanceMigratorLogger.java
(rev 0)
+++
projects/instance-migration/trunk/jbpm-instance-migrator/src/main/java/org/jbpm/instance/migration/util/JbpmInstanceMigratorLogger.java 2009-08-22
15:03:41 UTC (rev 5506)
@@ -0,0 +1,10 @@
+package org.jbpm.instance.migration.util;
+
+/**
+ * Used for Logging purposes only. Projects that use the jbpm-migrator project can
configure it's log4j log output by referrin to this class.
+ * @author Caleb Powell <caleb.powell(a)intelliware.ca>
+ * @author David Harcombe <david.harcombe(a)intelliware.ca>
+ */
+public class JbpmInstanceMigratorLogger {
+
+}
Added:
projects/instance-migration/trunk/jbpm-instance-migrator/src/main/java/org/jbpm/instance/migration/util/MigratorValiditionUtil.java
===================================================================
---
projects/instance-migration/trunk/jbpm-instance-migrator/src/main/java/org/jbpm/instance/migration/util/MigratorValiditionUtil.java
(rev 0)
+++
projects/instance-migration/trunk/jbpm-instance-migrator/src/main/java/org/jbpm/instance/migration/util/MigratorValiditionUtil.java 2009-08-22
15:03:41 UTC (rev 5506)
@@ -0,0 +1,106 @@
+package org.jbpm.instance.migration.util;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import org.jbpm.graph.def.Node;
+import org.jbpm.graph.def.ProcessDefinition;
+import org.jbpm.instance.migration.Migrator;
+
+
+/**
+ * Contains utility methods used to validate a {@link Migrator}.
+ * @author Caleb Powell <caleb.powell(a)intelliware.ca>
+ * @author David Harcombe <david.harcombe(a)intelliware.ca>
+ */
+public class MigratorValiditionUtil {
+
+ /**
+ * Searches the processDefinition instance for any deprecated nodes specified in the
migrator.
+ *
+ * @param processDefinition
+ * @param migrator
+ * @return An array of deprecated nodes contained in the processDefinition. An empty
array if none are found.
+ */
+ public static String[] findDeprecatedNodesInProcessDefinition(ProcessDefinition
processDefinition, Migrator migrator) {
+ List deprecatedNodes = new ArrayList();
+ for (Iterator deprecatedNodeIterator =
deprecatedNodeIterator(migrator);deprecatedNodeIterator.hasNext();) {
+ String deprecatedNode = (String) deprecatedNodeIterator.next();
+ if(findNode(processDefinition, deprecatedNode) != null){
+ deprecatedNodes.add(deprecatedNode);
+ }
+ }
+
+ return (String[]) deprecatedNodes.toArray(new String[deprecatedNodes.size()]);
+ }
+
+ /**
+ * Searches the processDefinition instance for missing current nodes.
+ * @param processDefinition
+ * @param migrator
+ * @return An array of current nodes that are specified in the migrator and are missing
in the processDefinition.
+ * An empty array if no nodes are missing.
+ */
+ public static String[] findMissingCurrentNodesInTheProcessDefinition(ProcessDefinition
processDefinition, Migrator migrator) {
+ Set missingNodes = new HashSet();
+ for (Iterator currentNodeIterator =
currentNodeIterator(migrator);currentNodeIterator.hasNext();) {
+ String currentNode = (String) currentNodeIterator.next();
+ if(findNode(processDefinition, currentNode) == null){
+ missingNodes.add(currentNode);
+ }
+ }
+ return (String[]) missingNodes.toArray(new String[missingNodes.size()]);
+ }
+
+ /**
+ * Searches the processDefinition instance for a node by name.
+ * @param processDefinition
+ * @param nodeName
+ * @return the node, or null if no node of that name exists
+ */
+ public static Node findNode(ProcessDefinition processDefinition, String nodeName) {
+ try {
+ return processDefinition.findNode(nodeName);
+ } catch (NullPointerException e) {
+ // IW/PP: jbpm method throws an NPE if the superstate referenced in a node name
doesn't exist
+ return null;
+ }
+ }
+
+ /**
+ * Searches the processDefinition instance for current nodes (as specified in the
migrator) that are not supported wait states.
+ * See the {@link Migrator}'s SUPPORTED_WAIT_STATE_NODE_TYPES constant for the set
of supported wait state nodes.
+ * @param processDefinition
+ * @param migrator
+ * @return An array of current node names that are specified in the migrator as current
nodes, but are not supported by the migrator.
+ */
+ public static String[] findCurrentNodesThatAreInvalidWaitStates(ProcessDefinition
processDefinition, Migrator migrator) {
+ Set invalidNodes = new HashSet();
+ for (Iterator currentNodeIterator =
currentNodeIterator(migrator);currentNodeIterator.hasNext();) {
+ String currentNode = (String) currentNodeIterator.next();
+ Node node = findNode(processDefinition, currentNode);
+ if(node != null && nodeIsNotASupportedWaitState(node)){
+ invalidNodes.add(currentNode);
+ }
+ }
+
+ return (String[]) invalidNodes.toArray(new String[invalidNodes.size()]);
+ }
+
+ private static Iterator deprecatedNodeIterator(Migrator migrator) {
+ Iterator iterator = migrator.getStateNodeMap().deprecatedNodeNames().iterator();
+ return iterator;
+ }
+
+ private static Iterator currentNodeIterator(Migrator migrator) {
+ Iterator iterator = migrator.getStateNodeMap().currentNodeNames().iterator();
+ return iterator;
+ }
+
+ private static boolean nodeIsNotASupportedWaitState(Node node) {
+ return !Migrator.SUPPORTED_WAIT_STATE_NODE_TYPES.contains(node.getClass());
+ }
+}
Added: projects/instance-migration/trunk/jbpm-instance-migrator/src/site/apt/cookbook.apt
===================================================================
--- projects/instance-migration/trunk/jbpm-instance-migrator/src/site/apt/cookbook.apt
(rev 0)
+++
projects/instance-migration/trunk/jbpm-instance-migrator/src/site/apt/cookbook.apt 2009-08-22
15:03:41 UTC (rev 5506)
@@ -0,0 +1,147 @@
+Cookbook
+
+* Purpose
+
+ The purpose of this document is to help a developer create migrations for a JBPM
ProcessInstance.
+
+* Overview
+
+ The JBPM project allows for simultaneous versions of a ProcessDefinition. Each time a
modified ProcessDefinition is deployed,
+ JBPM will assign a version number to it. It does not delete the previous version/s.
Rather, it maintains all of the prior ProcessDefinition
+ records, and their related ProcessInstance records. This can be very useful for
short-lived processes and is the JBPM recommended strategy.
+
+ For projects that require long-lived processes, this option is not as appealing. For
example, new process definitions may contain graph changes
+ that resolve a bug, or new requirements. Alternatively, old process definitions may
reference deprecated or non-existent Actions. The risks
+ become more pronounced the older the process instance is. In light of these risks, the
ability to migrate older process instances is very
+ desirable. The jbpm-migrator project was created to address this.
+
+ Given an old process instance (that is, a process instance whose process definition is
not the current version), the jbpm-migrator is capable of
+ migrating the process instance to the latest process instance. A migration performs the
following actions:
+
+ [[1]] Checks to determine whether the ProcessInstance actual requires migration. If the
process instance refers to the current Process definition, it will not perform a migration
and will exit and return the current process instance (the one passed into the migrate
method).
+
+ [[2]] Creates a new ProcessInstance from the latest ProcessDefinition.
+
+ [[3]] Copies all of the Persisted Variables from the old process instance
ExecutionContext into the new process instance.
+
+ [[4]] Copies all of the Transient Variables from the old process instance Execution
Context into the new process instance.
+
+ [[5]] Adds a migration memo (a String in the persistent variables map) to the new
process instance which records info (current date, old version, new version) about the
migration.
+
+ [[6]] Copies all of the tokens from the old process instance into the new process
instance. The migrator uses mappings that a developer provides to determine where old
tokens get placed in the new object graph.
+
+ This process is performed recursively, so each sub-process is also migrated according
the above steps. The migrator is not responsible for persistence
+ of any kind. The caller assumes responsibility for the persistence of a ProcessInstance.
+
+* Mapping Token Nodes
+
+ One of the key challenges when migrating a process instance is the addition and removal
of wait state nodes. This is where migrations come into play.
+ Migrations contain maps that tell the Migrator how to how to get a token from a node in
one process to a node in another process. Consider the following
+ two versions of the Foo process:
+
+[fooprocessv1.gif] Foo Process Version 1\
+
+[fooprocessv2.gif] Foo Process Version 2\
+
+ This example shows two versions of a process instance. Version 1 contains three wait
state nodes (A, B, and C). In Version 2, nodes B and C are deprecated and
+ were replaced with the nodes E and F (we refer to these new nodes as current nodes). In
order for the migrator to work, it needs to be told where to place the token
+ on node B in Version 2. Does it place the token on node A, E, or F? A developer tells
the migrator where to place the node by defining a migration which provides a mapping.
+ We would express the mapping for this migration as:
+
+----------------
+{�B� => �E�, �C� => �F�}
+----------------
+
+* Defining a Migration
+
+ Migrations are written in Java classes. The class must implement the Migration
interface, it must not be abstract, and it must contain a default constructor. The
Migration
+ interface declares one method that must be implemented:
+
+----------------
+public StateNodeMap createNodeMap();
+----------------
+
+ Here is how you would express the migration for our example above:
+
+----------------
+public class FooProcessMigration001 implements Migration{
+ public StateNodeMap createNodeMap() {
+ return new StateNodeMap(new String[][]{{"B", "E"}, {"C",
"F"}});
+ }
+}
+----------------
+
+ Note that the map only needs to explain what to do with tokens on deprecated nodes. No
mapping is required for the A node because it is not deprecated. By default, if no mapping
exists for a wait state node (e.g. it is not deprecated), the migrator will attempt to
move the token to a node with the same name in the new version. The FooProcessMigration001
migration class is read by the migrator and tells it everything it needs to know:
+
+ * If the migrator encounters a token on node B, it should move it to node E in the new
process instance.
+ * If the migrator encounters a token on node C, it should move it to node F in the new
process instance.
+ * Node A is not deprecated, so if the migrator encounters a token on node A, it should
put it into node A on the new process instance.
+
+* Defining a Migrator
+
+ How do we create the migrator and use it to perform a migration? Like this:
+
+-----------------
+Migrator migrator = new Migrator(�FooProcess�,
jbpmContext, �com.foobar.FooProcessMigration�);
+ProcessInstance newProcess = migrator.migrate(oldProcess);
+-----------------
+
+ The parameters used to create the Migrator instance are:
+
+ [[1]] The name of the ProcessDefinition that it will be migrating.
+ [[2]] A JbpmContext instance. The migrator requires this to look up the latest
ProcessDefinition.
+ [[3]] The Migration base class name. The migrator works by convention, assuming that
your migrations use the pattern: package.ClassName[0-9]{3}. For the base Class name
�com.foobar.FooProcessMigration�, the migrator will attempt to load
�com.foobar.FooProcessMigration001�, �com.foobar.FooProcessMigration002�, etc, until it
can�t find any valid classes. Alternatively, the constructor is overloaded so that you can
provide an array of Migration classes. In most cases, following the convention and
providing a base class name will require less maintenance on behalf of the developer.
+
+ The migrator analyzes each and every Migration in order and compiles a composite map.
For example, consider the following individual migrations:
+
+-----------------
+{�B� => �E�, �C� => �F�} #Migration 001
+{�A� => �G� } #Migration 002
+{�E� => �X�, �F� => �Y�} #Migration 003
+-----------------
+
+ The Migrator would compile a composite map that looks like this: {�B� => �X�, �E�
=> �X�, �C� => �Y�, �F� => �Y�, �A� => �G�}
+
+ Using this composite map, the migrator can map any outdated process instance to the
current version. As a consequence, the migrator does not need to keep track of process
definition versions. As long as you have recorded deprecated nodes in a migration, the
migrator will be able to perform its job. There are some rules that the migrator
enforces:
+
+ [[1]] You cannot rename or remove a wait state node without providing a migration.
+ [[2]] You cannot re-introduce a deprecated node. Once a node has been deprecated, it�s
never to be used again in the ProcessDefinition. Ever!!!
+ [[3]] As mentioned earlier, you do not need to map non wait state nodes. For example, a
Node type of node (one that performs actions, but never contains a token) does not need to
be mapped. The migrator will never be required to migrate a token from this type of node.
+
+
+* Sub Process Migrations
+
+
+ Jbpm processes can contain sub processes. Obviously, if you are migrating a super
process, you will need to migrate any sub processes as well. This is easily accomplished
by providing the super process migrator class with a migrator for any sub processes that
it will encounter. For example, let�s assume that our Foo process contains a sub process
called Bar. You would start by creating a migrator for the Bar sub process:
+
+-----------------
+Migrator barMigrator = new Migrator(�Bar�, jbpmcontext,
�com.foobar.BarProcessMigration�);
+Migrator fooMigrator = new Migrator(�Foo�, jbpmcontext, �com.foobar.FooProcessMigration�,
new Migrator[]{barMigrator});
+
+ProcessInstance newFooProcess = fooMigrator.migrate(oldFooProcess);
+-----------------
+
+ In this case, you pass the foo super process instance to the fooMigrator. If the foo
super process contains a bar sub process (that is, if there is a token on the bar sub
process node), than the fooMigrator will pass the bar sub process to the bar migrator.
This is recursive, so you can nest as many migrators as you need.
+
+
+* Super State Migrations
+
+ Jbpm process definitions can contain Super States. Nodes are mapped hierarchically if
contained in a super state node. Assume a developer is creating a new version a process
definition, and decides that the wait state node bar should be wrapped by a super state
node named foo. This mapping would look like:
+
+-----------------
+{�bar� => �foo/bar�}
+-----------------
+
+ Likewise, if the foo super state was being removed, the mapping would be represented
as:
+
+-----------------
+{�foo/bar� => �bar�}
+-----------------
+
+ Finally, if the bar node name resides in the foo super state, and is to be renamed baz,
the mapping would be represented as:
+
+-----------------
+{�foo/bar� => �foo/baz�}
+-----------------
+
+ []
\ No newline at end of file
Added:
projects/instance-migration/trunk/jbpm-instance-migrator/src/site/apt/fooprocessv1.gif
===================================================================
(Binary files differ)
Property changes on:
projects/instance-migration/trunk/jbpm-instance-migrator/src/site/apt/fooprocessv1.gif
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added:
projects/instance-migration/trunk/jbpm-instance-migrator/src/site/apt/fooprocessv2.gif
===================================================================
(Binary files differ)
Property changes on:
projects/instance-migration/trunk/jbpm-instance-migrator/src/site/apt/fooprocessv2.gif
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: projects/instance-migration/trunk/jbpm-instance-migrator/src/site/apt/index.apt
===================================================================
--- projects/instance-migration/trunk/jbpm-instance-migrator/src/site/apt/index.apt
(rev 0)
+++
projects/instance-migration/trunk/jbpm-instance-migrator/src/site/apt/index.apt 2009-08-22
15:03:41 UTC (rev 5506)
@@ -0,0 +1,8 @@
+~~see
http://maven.apache.org/doxia/format.html for info on the APT format
+Jbpm-Migrator
+
+ The jbpm-migrator project is used to migrate jbpm process instances dynamically at
runtime.
+
+ * {{{cookbook.html}Cookbook}}
+
+ []
Added:
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/java/org/jbpm/instance/migration/BaseTestCase.java
===================================================================
---
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/java/org/jbpm/instance/migration/BaseTestCase.java
(rev 0)
+++
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/java/org/jbpm/instance/migration/BaseTestCase.java 2009-08-22
15:03:41 UTC (rev 5506)
@@ -0,0 +1,46 @@
+package org.jbpm.instance.migration;
+
+import org.hibernate.classic.Session;
+import org.jbpm.JbpmConfiguration;
+import org.jbpm.JbpmContext;
+import org.jbpm.graph.def.ProcessDefinition;
+import org.jmock.cglib.MockObjectTestCase;
+
+/**
+ * Abstract base class for the jbpm-migrator project. Performs Hibernate and Log4J
configurations.
+ * @see HibernateTestSupport
+ * @author Caleb Powell <caleb.powell(a)intelliware.ca>
+ * @author David Harcombe <david.harcombe(a)intelliware.ca>
+ */
+public abstract class BaseTestCase extends MockObjectTestCase {
+
+ private HibernateTestSupport hibernateSupport;
+
+ protected JbpmContext jbpmContext;
+
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ this.hibernateSupport = new HibernateTestSupport();
+ this.hibernateSupport.setUp();
+ this.jbpmContext = JbpmConfiguration.getInstance().createJbpmContext();
+ Session currentSession =
this.hibernateSupport.getSessionFactory().getCurrentSession();
+ currentSession.beginTransaction();
+ jbpmContext.setSession(currentSession);
+ }
+
+ /**
+ * Rollback to stop jBPM from keeping multiple version of processes we don't want.
+ * support.tearDown() to reinitialise between tests.
+ */
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ Session currentSession =
this.hibernateSupport.getSessionFactory().getCurrentSession();
+ currentSession.getTransaction().rollback();
+ this.hibernateSupport.tearDown();
+ }
+
+ protected ProcessDefinition findLatestProcessDefinition(String processName) {
+ return jbpmContext.getGraphSession().findLatestProcessDefinition(processName);
+ }
+}
Added:
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/java/org/jbpm/instance/migration/BasicMigrationTest.java
===================================================================
---
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/java/org/jbpm/instance/migration/BasicMigrationTest.java
(rev 0)
+++
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/java/org/jbpm/instance/migration/BasicMigrationTest.java 2009-08-22
15:03:41 UTC (rev 5506)
@@ -0,0 +1,179 @@
+package org.jbpm.instance.migration;
+
+import java.io.IOException;
+
+import org.jbpm.graph.def.ProcessDefinition;
+import org.jbpm.graph.exe.ProcessInstance;
+
+
+/**
+ *
+ * @author Caleb Powell <caleb.powell(a)intelliware.ca>
+ * @author David Harcombe <david.harcombe(a)intelliware.ca>
+ */
+public class BasicMigrationTest extends BaseTestCase {
+
+ protected void setUp() throws Exception {
+ super.setUp();
+ }
+
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ public void testTheProcessInstanceSignals() throws IOException,
InvalidMigrationException{
+ deployV1Definitions();
+
+ ProcessInstance processInstanceV1 =
findLatestProcessDefinition("simple").createProcessInstance();
+ processInstanceV1.signal();
+ assertEquals("A", processInstanceV1.getRootToken().getNode().getName());
+
+ processInstanceV1.signal();
+ assertEquals("Fork1", processInstanceV1.getRootToken().getNode().getName());
+ assertEquals("forkNode1",
processInstanceV1.getRootToken().getChild("to_forkNode1").getNode().getName());
+ assertEquals("forkNode2",
processInstanceV1.getRootToken().getChild("to_forkNode2").getNode().getName());
+ assertEquals("forkNode3",
processInstanceV1.getRootToken().getChild("to_forkNode3").getNode().getName());
+
+ processInstanceV1.getRootToken().getChild("to_forkNode1").signal();
+ processInstanceV1.getRootToken().getChild("to_forkNode2").signal();
+ processInstanceV1.getRootToken().getChild("to_forkNode3").signal();
+ assertEquals("B", processInstanceV1.getRootToken().getNode().getName());
+ }
+
+ public void testThatTheMigratorWillRejectInvalidProcessInstances() throws IOException {
+ try{
+ deployV1Definitions();
+ Migrator fooMigrator = new Migrator("foo", this.jbpmContext,
(Migration[])null, (Migrator[])null);
+ fooMigrator.migrate(findLatestProcessDefinition("simple").createProcessInstance());
+ fail();
+ }catch(IllegalArgumentException e){
+
+ } catch (InvalidMigrationException e) {
+ fail();
+ }
+ }
+
+ public void testThatTheMigratorCanMigrateAProcessInstance() throws IOException,
InvalidMigrationException{
+ deployV1Definitions();
+ ProcessInstance processInstanceV1 =
findLatestProcessDefinition("simple").createProcessInstance();
+
+ processInstanceV1.signal();
+ assertEquals("A", processInstanceV1.getRootToken().getNode().getName());
+
+ deployV2Definitions();
+ deployV3Definitions();
+
+ Migrator migrator = createSimpleProcessDefinitionMigrator();
+ ProcessDefinition processDefinitionV3 =
findLatestProcessDefinition("simple");
+ assertNotNull(processDefinitionV3);
+ assertEquals(3, processDefinitionV3.getVersion());
+ ProcessInstance processInstanceV3 = migrator.migrate(processInstanceV1);
+
+ assertEquals("third", processInstanceV3.getRootToken().getNode().getName());
+ }
+
+ public void testThatTheMigratorCanMigrateAMidProcessInstance() throws IOException,
InvalidMigrationException{
+ deployV1Definitions();
+ deployV2Definitions();
+ ProcessInstance instance1 =
findLatestProcessDefinition("simple").createProcessInstance();
+ instance1.signal();
+
+ deployV3Definitions();
+
+ Migrator migrator = createSimpleProcessDefinitionMigrator();
+ ProcessDefinition definition3 = findLatestProcessDefinition("simple");
+ assertNotNull(definition3);
+ assertEquals(3, definition3.getVersion());
+ ProcessInstance instance3 = migrator.migrate(instance1);
+
+ assertEquals("third", instance3.getRootToken().getNode().getName());
+ }
+
+ public void testThatTheMigratorCanMigrateAProcessInstanceWithAFork() throws IOException,
InvalidMigrationException{
+ deployV1Definitions();
+ ProcessInstance processInstanceV1 =
findLatestProcessDefinition("simple").createProcessInstance();
+ processInstanceV1.signal();
+ assertEquals("A", processInstanceV1.getRootToken().getNode().getName());
+
+ processInstanceV1.signal();
+ assertEquals("Fork1", processInstanceV1.getRootToken().getNode().getName());
+ assertEquals("forkNode1",
processInstanceV1.getRootToken().getChild("to_forkNode1").getNode().getName());
+ assertEquals("forkNode2",
processInstanceV1.getRootToken().getChild("to_forkNode2").getNode().getName());
+ assertEquals("forkNode3",
processInstanceV1.getRootToken().getChild("to_forkNode3").getNode().getName());
+
+ deployV2Definitions();
+ deployV3Definitions();
+
+ Migrator migrator = createSimpleProcessDefinitionMigrator();
+ ProcessInstance processInstanceV3 = migrator.migrate(processInstanceV1);
+ assertEquals("Fork1", processInstanceV3.getRootToken().getNode().getName());
+ assertEquals("forkNodeOne",
processInstanceV3.getRootToken().getChild("to_forkNode1").getNode().getName());
+ assertEquals("forkNodeTwo",
processInstanceV3.getRootToken().getChild("to_forkNode2").getNode().getName());
+ assertEquals("forkNodeThree",
processInstanceV3.getRootToken().getChild("to_forkNode3").getNode().getName());
+
+ processInstanceV3.getRootToken().getChild("to_forkNode1").signal();
+ processInstanceV3.getRootToken().getChild("to_forkNode2").signal();
+ processInstanceV3.getRootToken().getChild("to_forkNode3").signal();
+ assertEquals("second",
processInstanceV3.getRootToken().getNode().getName());
+ }
+
+ public void testThatTheContextInstanceIsTransferredToTheNewProcess() throws Exception{
+ deployV1Definitions();
+ ProcessInstance processInstanceV1 =
findLatestProcessDefinition("simple").createProcessInstance();
+ processInstanceV1.getContextInstance().setVariable("Foo", "Bar");
+
+ Migrator migrator = createSimpleProcessDefinitionMigrator();
+
+ deployV2Definitions();
+ deployV3Definitions();
+
+ ProcessInstance processInstanceV3 = migrator.migrate(processInstanceV1);
+ assertEquals("Bar",
processInstanceV3.getContextInstance().getVariable("Foo"));
+ assertNull(processInstanceV1.getContextInstance().getVariable("migrationMemo"));
+ assertNotNull(processInstanceV3.getContextInstance().getVariable("migrationMemo"));
+ System.out.println(processInstanceV3.getContextInstance().getVariable("migrationMemo"));
+ }
+
+ public void testNoMigrationOfCurrentInstance() throws Exception {
+ deployV1Definitions();
+ deployV2Definitions();
+ deployV3Definitions();
+
+ ProcessInstance processInstance1 =
findLatestProcessDefinition("simple").createProcessInstance();
+ Migrator migrator = createSimpleProcessDefinitionMigrator();
+ ProcessInstance processInstance2 = migrator.migrate(processInstance1);
+ assertEquals(processInstance1, processInstance2);
+ }
+
+ public void testNoMigrations() throws Exception {
+ new Migrator("", this.jbpmContext, (Migration[])null, (Migrator[])null);
+ }
+
+ private Migrator createSimpleProcessDefinitionMigrator() throws
InvalidMigrationException {
+ Migrator migrator = new Migrator("simple", this.jbpmContext, new
Migration[]{new SimpleProcessDefinitionMigration001(), new
SimpleProcessDefinitionMigration002()}, null);
+ return migrator;
+ }
+
+ private void deployV1Definitions() throws IOException {
+ jbpmContext.deployProcessDefinition(MigrationUtils.getProcessDefinition("simpleProcessDefinition_001.xml"));
+ }
+
+ private void deployV2Definitions() throws IOException {
+ jbpmContext.deployProcessDefinition(MigrationUtils.getProcessDefinition("simpleProcessDefinition_002.xml"));
+ }
+
+ private void deployV3Definitions() throws IOException {
+ jbpmContext.deployProcessDefinition(MigrationUtils.getProcessDefinition("simpleProcessDefinition_003.xml"));
+ }
+
+ private static class SimpleProcessDefinitionMigration001 implements Migration{
+ public StateNodeMap createNodeMap() {
+ return new StateNodeMap(new String[][] {{"A","first"},
{"B","second"}, });
+ }
+ }
+ private static class SimpleProcessDefinitionMigration002 implements Migration{
+ public StateNodeMap createNodeMap() {
+ return new StateNodeMap(new String[][] {{"first","third"},
{"forkNode1","forkNodeOne"},
{"forkNode2","forkNodeTwo"},
{"forkNode3","forkNodeThree"}, });
+ }
+ }
+}
Added:
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/java/org/jbpm/instance/migration/HibernateTestSupport.java
===================================================================
---
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/java/org/jbpm/instance/migration/HibernateTestSupport.java
(rev 0)
+++
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/java/org/jbpm/instance/migration/HibernateTestSupport.java 2009-08-22
15:03:41 UTC (rev 5506)
@@ -0,0 +1,52 @@
+package org.jbpm.instance.migration;
+
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+import org.hibernate.Transaction;
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.beans.factory.xml.XmlBeanFactory;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.orm.hibernate3.SessionHolder;
+import org.springframework.transaction.support.TransactionSynchronizationManager;
+
+/**
+ * A utility class to provide Hibernate support in unit tests.
+ * @author Caleb Powell <caleb.powell(a)intelliware.ca>
+ * @author David Harcombe <david.harcombe(a)intelliware.ca>
+ */
+public class HibernateTestSupport {
+ private static XmlBeanFactory factory;
+
+ private void setUpTransactionManager() {
+ Session session = getSessionFactory().openSession();
+ TransactionSynchronizationManager.bindResource(getSessionFactory(), new
SessionHolder(session));
+ }
+
+ public void setUp() {
+ if (factory == null) {
+ factory = new XmlBeanFactory(new
ClassPathResource("/org/jbpm/instance/migration/mock-hibernate-spring.xml"));
+ }
+ setUpTransactionManager();
+ }
+
+ public void tearDown() throws Exception {
+ SessionHolder holder = (SessionHolder)
TransactionSynchronizationManager.getResource(getSessionFactory());
+ Session session = holder.getSession();
+ TransactionSynchronizationManager.unbindResource(getSessionFactory());
+ session.close();
+ }
+
+ public SessionFactory getSessionFactory() {
+ return (SessionFactory) getFactory().getBean(SessionFactory.class.getName());
+ }
+
+ public BeanFactory getFactory() {
+ return factory;
+ }
+
+ public void runInTransaction(Runnable runnable) {
+ Transaction transaction = getSessionFactory().getCurrentSession().beginTransaction();
+ runnable.run();
+ transaction.commit();
+ }
+}
\ No newline at end of file
Added:
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/java/org/jbpm/instance/migration/MigrationComparatorTest.java
===================================================================
---
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/java/org/jbpm/instance/migration/MigrationComparatorTest.java
(rev 0)
+++
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/java/org/jbpm/instance/migration/MigrationComparatorTest.java 2009-08-22
15:03:41 UTC (rev 5506)
@@ -0,0 +1,26 @@
+package org.jbpm.instance.migration;
+
+import org.jbpm.instance.migration.Migration;
+import org.jbpm.instance.migration.MigrationComparator;
+import org.jmock.cglib.MockObjectTestCase;
+
+/**
+ *
+ * @author Caleb Powell <caleb.powell(a)intelliware.ca>
+ * @author David Harcombe <david.harcombe(a)intelliware.ca>
+ */
+public class MigrationComparatorTest extends MockObjectTestCase {
+
+ public void testCompare() {
+ Migration migration1 = new TestMigration001();
+ Migration migration2 = new TestMigration002();
+ Migration migration3 = new TestMigration003();
+
+ MigrationComparator migrationComparator = new MigrationComparator();
+ assertEquals(0, migrationComparator.compare(migration1, migration1));
+ assertTrue(migrationComparator.compare(migration1, migration2) < 0);
+ assertTrue(migrationComparator.compare(migration2, migration3) < 0);
+ assertTrue(migrationComparator.compare(migration3, migration1) > 0);
+ }
+
+}
Added:
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/java/org/jbpm/instance/migration/MigrationUtilsTest.java
===================================================================
---
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/java/org/jbpm/instance/migration/MigrationUtilsTest.java
(rev 0)
+++
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/java/org/jbpm/instance/migration/MigrationUtilsTest.java 2009-08-22
15:03:41 UTC (rev 5506)
@@ -0,0 +1,71 @@
+package org.jbpm.instance.migration;
+
+import java.io.IOException;
+
+import org.jbpm.graph.def.ProcessDefinition;
+import org.jbpm.graph.exe.ProcessInstance;
+import org.jbpm.instance.migration.MigrationUtils;
+
+
+/**
+ *
+ * @author Caleb Powell <caleb.powell(a)intelliware.ca>
+ * @author David Harcombe <david.harcombe(a)intelliware.ca>
+ */
+public class MigrationUtilsTest extends BaseTestCase {
+
+ protected void setUp() throws Exception {
+ super.setUp();
+ }
+
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ public void testThatASuperProcessWillRequireMigrationIfItsOutOfDate() throws
IOException{
+ deployV1Definitions();
+ ProcessDefinition definition =
findLatestProcessDefinition("simpleSuperProcess");
+ ProcessInstance processInstance = definition.createProcessInstance();
+
+ processInstance.signal();
+ deployV2Definitions();
+
+ assertTrue(MigrationUtils.requiresMigration(processInstance, jbpmContext));
+ }
+
+ public void testThatASuperProcessWillRequireMigrationIfANewSubProcessWasDeployed()
throws IOException{
+ deployV1Definitions();
+ ProcessDefinition definition =
findLatestProcessDefinition("simpleSuperProcess");
+ ProcessInstance processInstance = definition.createProcessInstance();
+
+ processInstance.signal();
+ processInstance.signal();
+ assertEquals("Fork1", processInstance.getRootToken().getNode().getName());
+ assertEquals("forkNode1",
processInstance.getRootToken().getChild("to_forkNode1").getNode().getName());
+ assertEquals("forkNode2",
processInstance.getRootToken().getChild("to_forkNode2").getNode().getName());
+ assertEquals("forkNode3",
processInstance.getRootToken().getChild("to_forkNode3").getNode().getName());
+ assertEquals("SubA",
processInstance.getRootToken().getChild("to_forkNode3").getSubProcessInstance().getRootToken().getNode().getName());
+ assertFalse(MigrationUtils.requiresMigration(processInstance, jbpmContext));
+
+ deploySubProcessV2Definition();
+
+ assertTrue(MigrationUtils.requiresMigration(processInstance, jbpmContext));
+ assertTrue(MigrationUtils.requiresMigration(processInstance.getRootToken().getChild("to_forkNode3").getSubProcessInstance(),
jbpmContext));
+
+ }
+
+ private void deployV1Definitions() throws IOException {
+ jbpmContext.deployProcessDefinition(MigrationUtils.getProcessDefinition("simpleSubProcessDefinition_001.xml"));
+ jbpmContext.deployProcessDefinition(MigrationUtils.getProcessDefinition("simpleSuperProcessDefinition_001.xml"));
+ }
+
+ private void deployV2Definitions() throws IOException {
+ jbpmContext.deployProcessDefinition(MigrationUtils.getProcessDefinition("simpleSubProcessDefinition_002.xml"));
+ jbpmContext.deployProcessDefinition(MigrationUtils.getProcessDefinition("simpleSuperProcessDefinition_002.xml"));
+ }
+
+ private void deploySubProcessV2Definition() throws IOException {
+ jbpmContext.deployProcessDefinition(MigrationUtils.getProcessDefinition("simpleSubProcessDefinition_002.xml"));
+ }
+
+}
Added:
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/java/org/jbpm/instance/migration/MigratorAggregationTest.java
===================================================================
---
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/java/org/jbpm/instance/migration/MigratorAggregationTest.java
(rev 0)
+++
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/java/org/jbpm/instance/migration/MigratorAggregationTest.java 2009-08-22
15:03:41 UTC (rev 5506)
@@ -0,0 +1,69 @@
+package org.jbpm.instance.migration;
+
+
+import org.jbpm.instance.migration.InvalidMigrationException;
+import org.jbpm.instance.migration.Migration;
+import org.jbpm.instance.migration.Migrator;
+import org.jbpm.instance.migration.StateNodeMap;
+
+
+/**
+ *
+ * @author Caleb Powell <caleb.powell(a)intelliware.ca>
+ * @author David Harcombe <david.harcombe(a)intelliware.ca>
+ */
+public class MigratorAggregationTest extends BaseTestCase {
+
+ public void testThatTheMigratorCanAggregateACollectionOfMigrations() throws Exception{
+ Migration migration1 = new MigratorTestMigration001();
+ Migration migration2 = new MigratorTestMigration002();
+ Migration migration3 = new MigratorTestMigration003();
+ Migrator migrator = new Migrator("", null, new Migration[]{migration1,
migration2, migration3}, null);
+
+ assertTrue(migrator.getStateNodeMap().containsDeprecatedNodeName("a"));
+ assertExistenseNodeMapping("a", "d", migrator.getStateNodeMap());
+ assertExistenseNodeMapping("x", "z", migrator.getStateNodeMap());
+ assertExistenseNodeMapping("b", "d", migrator.getStateNodeMap());
+ assertExistenseNodeMapping("c", "d", migrator.getStateNodeMap());
+ }
+
+ public void testIllegalMigrationThrowsException() throws Exception{
+ Migration migration1 = new MigratorTestMigration001();
+ Migration migration2 = new MigratorTestMigration002();
+ Migration migration3 = new MigratorTestMigration003();
+ Migration migration4 = new MigratorTestMigration004();
+ try {
+ new Migrator("", null, new Migration[]{migration1, migration2, migration3,
migration4}, null);
+ fail();
+ } catch (InvalidMigrationException e) {
+ System.out.println(e.getMessage());
+ }
+ }
+
+ private void assertExistenseNodeMapping(String deprecatedNodeName, String
currentNodeName, StateNodeMap mappings) {
+ assertTrue("Mapping does not include the key
'"+deprecatedNodeName+"'",
mappings.containsDeprecatedNodeName(deprecatedNodeName));
+ assertTrue("Mapping does not include the value
'"+currentNodeName+"'",
mappings.containsCurrentNodeName(currentNodeName));
+ assertEquals(deprecatedNodeName+"==>"+currentNodeName+" mapping does
not exist!", currentNodeName, mappings.getCurrentNodeName(deprecatedNodeName));
+ }
+
+ private static class MigratorTestMigration001 implements Migration{
+ public StateNodeMap createNodeMap() {
+ return new StateNodeMap(new String[][]{{"a", "b"}, {"x",
"y"}});
+ }
+ }
+ private static class MigratorTestMigration002 implements Migration{
+ public StateNodeMap createNodeMap() {
+ return new StateNodeMap(new String[][]{{"b", "c"}, {"y",
"z"}});
+ }
+ }
+ private static class MigratorTestMigration003 implements Migration{
+ public StateNodeMap createNodeMap() {
+ return new StateNodeMap(new String[][]{{"c", "d"}});
+ }
+ }
+ private static class MigratorTestMigration004 implements Migration{
+ public StateNodeMap createNodeMap() {
+ return new StateNodeMap(new String[][]{{"d", "a"}});
+ }
+ }
+}
Added:
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/java/org/jbpm/instance/migration/SubprocessMigratorTest.java
===================================================================
---
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/java/org/jbpm/instance/migration/SubprocessMigratorTest.java
(rev 0)
+++
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/java/org/jbpm/instance/migration/SubprocessMigratorTest.java 2009-08-22
15:03:41 UTC (rev 5506)
@@ -0,0 +1,148 @@
+package org.jbpm.instance.migration;
+
+import java.io.IOException;
+
+import org.jbpm.graph.def.ProcessDefinition;
+import org.jbpm.graph.exe.ProcessInstance;
+import org.jbpm.instance.migration.InvalidMigrationException;
+import org.jbpm.instance.migration.Migration;
+import org.jbpm.instance.migration.MigrationUtils;
+import org.jbpm.instance.migration.Migrator;
+import org.jbpm.instance.migration.StateNodeMap;
+
+/**
+ *
+ * @author Caleb Powell <caleb.powell(a)intelliware.ca>
+ * @author David Harcombe <david.harcombe(a)intelliware.ca>
+ */
+public class SubprocessMigratorTest extends BaseTestCase {
+
+ private static final String SUB_PROCESS_NAME = "simpleSubProcess";
+
+ private static final String SUPER_PROCESS_NAME = "simpleSuperProcess";
+
+ protected void setUp() throws Exception {
+ super.setUp();
+ }
+
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ public void testTheProcessInstanceSignals() throws IOException,
InvalidMigrationException {
+ deployV1Definitions();
+
+ ProcessDefinition processDefinitionV1 =
findLatestProcessDefinition(SUPER_PROCESS_NAME);
+ ProcessInstance processInstanceV1 = processDefinitionV1.createProcessInstance();
+
+ processInstanceV1.signal();
+ assertEquals("A", processInstanceV1.getRootToken().getNode().getName());
+
+ processInstanceV1.signal();
+ assertEquals("Fork1", processInstanceV1.getRootToken().getNode().getName());
+ assertEquals("forkNode1",
processInstanceV1.getRootToken().getChild("to_forkNode1").getNode().getName());
+ assertEquals("forkNode2",
processInstanceV1.getRootToken().getChild("to_forkNode2").getNode().getName());
+ assertEquals("forkNode3",
processInstanceV1.getRootToken().getChild("to_forkNode3").getNode().getName());
+ assertEquals("SubA",
processInstanceV1.getRootToken().getChild("to_forkNode3").getSubProcessInstance().getRootToken().getNode().getName());
+
+ processInstanceV1.getRootToken().getChild("to_forkNode1").signal();
+ processInstanceV1.getRootToken().getChild("to_forkNode2").signal();
+ processInstanceV1.getRootToken().getChild("to_forkNode3").getSubProcessInstance().signal();
+ assertEquals("SubB",
processInstanceV1.getRootToken().getChild("to_forkNode3").getSubProcessInstance().getRootToken().getNode().getName());
+ }
+
+ public void testForSubProcesses() throws Exception {
+ deployV1Definitions();
+
+ ProcessDefinition processDefinitionV1 =
findLatestProcessDefinition(SUPER_PROCESS_NAME);
+ ProcessInstance processInstanceV1 = processDefinitionV1.createProcessInstance();
+
+ processInstanceV1.signal();
+ processInstanceV1.signal();
+ assertNull(processInstanceV1.getRootToken().getChild("to_forkNode1").getSubProcessInstance());
+ assertNotNull(processInstanceV1.getRootToken().getChild("to_forkNode3").getSubProcessInstance());
+ }
+
+ public void testSubprocessCreationAcrossVersions() throws Exception {
+ deployV1Definitions();
+ ProcessDefinition processDefinitionV1 =
findLatestProcessDefinition(SUPER_PROCESS_NAME);
+ assertEquals(1, processDefinitionV1.getVersion());
+
+ ProcessInstance instanceV1 = processDefinitionV1.createProcessInstance();
+ instanceV1.signal();
+ instanceV1.signal();
+ assertEquals("Fork1", instanceV1.getRootToken().getNode().getName());
+ assertEquals("forkNode1",
instanceV1.getRootToken().getChild("to_forkNode1").getNode().getName());
+ assertEquals("forkNode2",
instanceV1.getRootToken().getChild("to_forkNode2").getNode().getName());
+ assertEquals("forkNode3",
instanceV1.getRootToken().getChild("to_forkNode3").getNode().getName());
+ assertEquals("SubA",
instanceV1.getRootToken().getChild("to_forkNode3").getSubProcessInstance().getRootToken().getNode().getName());
+
+ deployV2Definitions();
+ assertEquals(2, findLatestProcessDefinition(SUPER_PROCESS_NAME).getVersion());
+
+ Migrator subProcessMigrator = new Migrator(SUB_PROCESS_NAME, this.jbpmContext, new
Migration[] {new SimpleSubProcessDefinitionMigration001()}, null );
+ Migrator superProcessMigrator = new Migrator(SUPER_PROCESS_NAME, this.jbpmContext, new
Migration[] {}, new Migrator[]{subProcessMigrator});
+ ProcessInstance instanceV2 = superProcessMigrator.migrate(instanceV1);
+ assertNull(instanceV2.getRootToken().getChild("to_forkNode1").getSubProcessInstance());
+ assertNotNull(instanceV2.getRootToken().getChild("to_forkNode3").getSubProcessInstance());
+ assertEquals("Sub1",
instanceV2.getRootToken().getChild("to_forkNode3").getSubProcessInstance().getRootToken().getNode().getName());
+
+ instanceV2.getRootToken().getChild("to_forkNode3").getSubProcessInstance().signal();
+ assertEquals("SubB",
instanceV2.getRootToken().getChild("to_forkNode3").getSubProcessInstance().getRootToken().getNode().getName());
+
+ instanceV2.getRootToken().getChild("to_forkNode3").getSubProcessInstance().signal();
+ assertNull(instanceV2.getRootToken().getChild("to_forkNode3").getSubProcessInstance());
+ assertEquals("Join1",
instanceV2.getRootToken().getChild("to_forkNode3").getNode().getName());
+
+ instanceV2.getRootToken().getChild("to_forkNode1").signal();
+ instanceV2.getRootToken().getChild("to_forkNode2").signal();
+ assertEquals("B", instanceV2.getRootToken().getNode().getName());
+
+ instanceV2.signal();
+ assertEquals("end", instanceV2.getRootToken().getNode().getName());
+ }
+
+ public void testThatSubprocessIsMigratedWhenSuperprocessIsMigrated() throws Exception {
+ deployV1Definitions();
+ ProcessDefinition processDefinitionV1 =
findLatestProcessDefinition(SUPER_PROCESS_NAME);
+ assertEquals(1, processDefinitionV1.getVersion());
+
+ ProcessInstance instanceV1 = processDefinitionV1.createProcessInstance();
+ instanceV1.signal();
+ instanceV1.signal();
+ assertEquals("Fork1", instanceV1.getRootToken().getNode().getName());
+ assertEquals("forkNode1",
instanceV1.getRootToken().getChild("to_forkNode1").getNode().getName());
+ assertEquals("forkNode2",
instanceV1.getRootToken().getChild("to_forkNode2").getNode().getName());
+ assertEquals("forkNode3",
instanceV1.getRootToken().getChild("to_forkNode3").getNode().getName());
+ assertEquals("SubA",
instanceV1.getRootToken().getChild("to_forkNode3").getSubProcessInstance().getRootToken().getNode().getName());
+
+ deployV2SuperprocessOnly();
+ assertEquals(2, findLatestProcessDefinition(SUPER_PROCESS_NAME).getVersion());
+
+ Migrator subProcessMigrator = new Migrator(SUB_PROCESS_NAME, this.jbpmContext, new
Migration[] {}, null );
+ Migrator superProcessMigrator = new Migrator(SUPER_PROCESS_NAME, this.jbpmContext, new
Migration[] {}, new Migrator[]{subProcessMigrator});
+ ProcessInstance instanceV2 = superProcessMigrator.migrate(instanceV1);
+
+ assertNotSame(instanceV2.getRootToken().getChild("to_forkNode3").getSubProcessInstance(),
instanceV1.getRootToken().getChild("to_forkNode3").getSubProcessInstance());
+ }
+
+ private void deployV1Definitions() throws IOException {
+ jbpmContext.deployProcessDefinition(MigrationUtils.getProcessDefinition("simpleSubProcessDefinition_001.xml"));
+ jbpmContext.deployProcessDefinition(MigrationUtils.getProcessDefinition("simpleSuperProcessDefinition_001.xml"));
+ }
+
+ private void deployV2Definitions() throws IOException {
+ jbpmContext.deployProcessDefinition(MigrationUtils.getProcessDefinition("simpleSubProcessDefinition_002.xml"));
+ jbpmContext.deployProcessDefinition(MigrationUtils.getProcessDefinition("simpleSuperProcessDefinition_002.xml"));
+ }
+
+ private void deployV2SuperprocessOnly() throws IOException {
+ jbpmContext.deployProcessDefinition(MigrationUtils.getProcessDefinition("simpleSuperProcessDefinition_002.xml"));
+ }
+
+ private static class SimpleSubProcessDefinitionMigration001 implements Migration{
+ public StateNodeMap createNodeMap() {
+ return new StateNodeMap(new String[][] {{"SubA", "Sub1"}});
+ }
+ }
+}
Added:
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/java/org/jbpm/instance/migration/SuperstateMigratorTest.java
===================================================================
---
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/java/org/jbpm/instance/migration/SuperstateMigratorTest.java
(rev 0)
+++
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/java/org/jbpm/instance/migration/SuperstateMigratorTest.java 2009-08-22
15:03:41 UTC (rev 5506)
@@ -0,0 +1,147 @@
+package org.jbpm.instance.migration;
+
+import java.io.IOException;
+
+import org.jbpm.graph.def.ProcessDefinition;
+import org.jbpm.graph.exe.ProcessInstance;
+import org.jbpm.instance.migration.Migration;
+import org.jbpm.instance.migration.MigrationUtils;
+import org.jbpm.instance.migration.Migrator;
+import org.jbpm.instance.migration.StateNodeMap;
+
+
+/**
+ *
+ * @author Caleb Powell <caleb.powell(a)intelliware.ca>
+ * @author David Harcombe <david.harcombe(a)intelliware.ca>
+ */
+public class SuperstateMigratorTest extends BaseTestCase {
+
+ private static final String PROCESS_NAME =
"superStateMigratorTestProcessDefinition";
+
+ protected void setUp() throws Exception {
+ super.setUp();
+ }
+
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ public void testMigrationToAProcessDefinitionWithASuperState() throws Exception {
+ deployNonSuperStateDefinition();
+ ProcessDefinition noSuperStateProcessDefinition =
findLatestProcessDefinition(PROCESS_NAME);
+ assertEquals(1, noSuperStateProcessDefinition.getVersion());
+
+ ProcessInstance noSuperStateInstance =
noSuperStateProcessDefinition.createProcessInstance();
+ noSuperStateInstance.signal();
+ assertEquals("Saved",
noSuperStateInstance.getRootToken().getNode().getFullyQualifiedName());
+
+ deploySuperStateDefinition01();
+ assertEquals(2, findLatestProcessDefinition(PROCESS_NAME).getVersion());
+
+ Migrator superProcessMigrator = new Migrator(PROCESS_NAME, this.jbpmContext, new
Migration[] {new ToSuperStateProcessDefinitionMigration()}, null);
+ ProcessInstance superStateInstance =
superProcessMigrator.migrate(noSuperStateInstance);
+ assertEquals("superStateNode/Saved",
superStateInstance.getRootToken().getNode().getFullyQualifiedName());
+
+ superStateInstance.signal();
+ assertEquals("Deleted",
superStateInstance.getRootToken().getNode().getFullyQualifiedName());
+ }
+
+ public void testMigrationToAProcessDefinitionWithNoSuperState() throws Exception {
+ deploySuperStateDefinition01();
+ ProcessDefinition superStateProcessDefinition =
findLatestProcessDefinition(PROCESS_NAME);
+ assertEquals(1, superStateProcessDefinition.getVersion());
+
+ ProcessInstance superStateInstance =
superStateProcessDefinition.createProcessInstance();
+ superStateInstance.signal();
+ assertEquals("superStateNode/Saved",
superStateInstance.getRootToken().getNode().getFullyQualifiedName());
+
+ deployNonSuperStateDefinition();
+ assertEquals(2, findLatestProcessDefinition(PROCESS_NAME).getVersion());
+
+ Migrator migrator = new Migrator(PROCESS_NAME, this.jbpmContext, new Migration[] {new
FromSuperStateProcessDefinitionMigration()}, null);
+ ProcessInstance nonSuperStateInstance = migrator.migrate(superStateInstance);
+ assertEquals("Saved",
nonSuperStateInstance.getRootToken().getNode().getFullyQualifiedName());
+
+ nonSuperStateInstance.signal();
+ assertEquals("Deleted",
nonSuperStateInstance.getRootToken().getNode().getFullyQualifiedName());
+ }
+
+ public void testMigrationBetweenProcessDefinitionsWithSuperStates() throws Exception {
+ deploySuperStateDefinition01();
+ ProcessDefinition superStateProcessDefinition01 =
findLatestProcessDefinition(PROCESS_NAME);
+ assertEquals(1, superStateProcessDefinition01.getVersion());
+
+ ProcessInstance superStateInstance01 =
superStateProcessDefinition01.createProcessInstance();
+ superStateInstance01.signal();
+ assertEquals("superStateNode/Saved",
superStateInstance01.getRootToken().getNode().getFullyQualifiedName());
+
+ deploySuperStateDefinition02();
+ assertEquals(2, findLatestProcessDefinition(PROCESS_NAME).getVersion());
+
+ Migrator migrator = new Migrator(PROCESS_NAME, this.jbpmContext, new Migration[] {new
BetweenSuperStateProcessDefinitionMigration()}, null);
+ ProcessInstance superStateInstance02 = migrator.migrate(superStateInstance01);
+ assertEquals("superStateNode/Saved2",
superStateInstance02.getRootToken().getNode().getFullyQualifiedName());
+ superStateInstance02.signal();
+ assertEquals("Deleted",
superStateInstance02.getRootToken().getNode().getFullyQualifiedName());
+ }
+
+ public void testMigrationToProcessDefinitionsWithNestedSuperStates() throws Exception {
+ deploySuperStateDefinition02();
+ ProcessDefinition superStateProcessDefinition01 =
findLatestProcessDefinition(PROCESS_NAME);
+ assertEquals(1, superStateProcessDefinition01.getVersion());
+
+ ProcessInstance superStateInstance01 =
superStateProcessDefinition01.createProcessInstance();
+ superStateInstance01.signal();
+ assertEquals("superStateNode/Saved2",
superStateInstance01.getRootToken().getNode().getFullyQualifiedName());
+
+ deployNestedSuperStateDefinition();
+ assertEquals(2, findLatestProcessDefinition(PROCESS_NAME).getVersion());
+
+ Migrator migrator = new Migrator(PROCESS_NAME, this.jbpmContext, new Migration[] {new
NestedSuperStateProcessDefinitionMigration()}, null);
+ ProcessInstance superStateInstance02 = migrator.migrate(superStateInstance01);
+ assertEquals("superDuperStateNode/superStateNode/Saved2",
superStateInstance02.getRootToken().getNode().getFullyQualifiedName());
+ superStateInstance02.signal();
+ assertEquals("Deleted",
superStateInstance02.getRootToken().getNode().getFullyQualifiedName());
+ }
+
+ private void deployNonSuperStateDefinition() throws IOException {
+ jbpmContext.deployProcessDefinition(MigrationUtils.getProcessDefinition("superstateMigratorTest_001.xml"));
+ }
+
+ private void deploySuperStateDefinition01() throws IOException {
+ jbpmContext.deployProcessDefinition(MigrationUtils.getProcessDefinition("superstateMigratorTest_002.xml"));
+ }
+
+ private void deploySuperStateDefinition02() throws IOException {
+ jbpmContext.deployProcessDefinition(MigrationUtils.getProcessDefinition("superstateMigratorTest_003.xml"));
+ }
+
+ private void deployNestedSuperStateDefinition() throws IOException {
+ jbpmContext.deployProcessDefinition(MigrationUtils.getProcessDefinition("superstateMigratorTest_004.xml"));
+ }
+
+ private static class ToSuperStateProcessDefinitionMigration implements Migration{
+ public StateNodeMap createNodeMap() {
+ return new StateNodeMap(new String[][] {{"Saved",
"superStateNode/Saved"}});
+ }
+ }
+
+ private static class FromSuperStateProcessDefinitionMigration implements Migration{
+ public StateNodeMap createNodeMap() {
+ return new StateNodeMap(new String[][] {{"superStateNode/Saved",
"Saved"}});
+ }
+ }
+
+ private static class BetweenSuperStateProcessDefinitionMigration implements Migration{
+ public StateNodeMap createNodeMap() {
+ return new StateNodeMap(new String[][] {{"superStateNode/Saved",
"superStateNode/Saved2"}});
+ }
+ }
+
+ private static class NestedSuperStateProcessDefinitionMigration implements Migration{
+ public StateNodeMap createNodeMap() {
+ return new StateNodeMap(new String[][] {{"superStateNode/Saved2",
"superDuperStateNode/superStateNode/Saved2"}});
+ }
+ }
+}
Added:
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/java/org/jbpm/instance/migration/TestMigration001.java
===================================================================
---
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/java/org/jbpm/instance/migration/TestMigration001.java
(rev 0)
+++
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/java/org/jbpm/instance/migration/TestMigration001.java 2009-08-22
15:03:41 UTC (rev 5506)
@@ -0,0 +1,17 @@
+package org.jbpm.instance.migration;
+
+import org.jbpm.instance.migration.Migration;
+import org.jbpm.instance.migration.StateNodeMap;
+
+/**
+ *
+ * @author Caleb Powell <caleb.powell(a)intelliware.ca>
+ * @author David Harcombe <david.harcombe(a)intelliware.ca>
+ */
+public class TestMigration001 implements Migration {
+
+ public StateNodeMap createNodeMap() {
+ return null;
+ }
+
+}
Added:
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/java/org/jbpm/instance/migration/TestMigration002.java
===================================================================
---
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/java/org/jbpm/instance/migration/TestMigration002.java
(rev 0)
+++
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/java/org/jbpm/instance/migration/TestMigration002.java 2009-08-22
15:03:41 UTC (rev 5506)
@@ -0,0 +1,17 @@
+package org.jbpm.instance.migration;
+
+import org.jbpm.instance.migration.Migration;
+import org.jbpm.instance.migration.StateNodeMap;
+
+/**
+ *
+ * @author Caleb Powell <caleb.powell(a)intelliware.ca>
+ * @author David Harcombe <david.harcombe(a)intelliware.ca>
+ */
+public class TestMigration002 implements Migration {
+
+ public StateNodeMap createNodeMap() {
+ return null;
+ }
+
+}
Added:
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/java/org/jbpm/instance/migration/TestMigration003.java
===================================================================
---
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/java/org/jbpm/instance/migration/TestMigration003.java
(rev 0)
+++
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/java/org/jbpm/instance/migration/TestMigration003.java 2009-08-22
15:03:41 UTC (rev 5506)
@@ -0,0 +1,16 @@
+package org.jbpm.instance.migration;
+
+import org.jbpm.instance.migration.Migration;
+import org.jbpm.instance.migration.StateNodeMap;
+
+/**
+ *
+ * @author Caleb Powell <caleb.powell(a)intelliware.ca>
+ * @author David Harcombe <david.harcombe(a)intelliware.ca>
+ */
+public class TestMigration003 implements Migration {
+
+ public StateNodeMap createNodeMap() {
+ return null;
+ }
+}
Added:
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/java/org/jbpm/instance/migration/util/MigratorValidityUtilTest.java
===================================================================
---
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/java/org/jbpm/instance/migration/util/MigratorValidityUtilTest.java
(rev 0)
+++
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/java/org/jbpm/instance/migration/util/MigratorValidityUtilTest.java 2009-08-22
15:03:41 UTC (rev 5506)
@@ -0,0 +1,82 @@
+package org.jbpm.instance.migration.util;
+
+import java.io.IOException;
+
+import junit.framework.TestCase;
+
+import org.apache.commons.lang.ArrayUtils;
+import org.jbpm.graph.def.ProcessDefinition;
+import org.jbpm.instance.migration.Migration;
+import org.jbpm.instance.migration.MigrationUtils;
+import org.jbpm.instance.migration.Migrator;
+import org.jbpm.instance.migration.StateNodeMap;
+
+/**
+ *
+ * @author Caleb Powell <caleb.powell(a)intelliware.ca>
+ * @author David Harcombe <david.harcombe(a)intelliware.ca>
+ */
+public class MigratorValidityUtilTest extends TestCase {
+
+ private static final String PROCESS_DEF_FILE_NAME =
"/org/jbpm/instance/migration/util/migratorValidityTestProcessDefinition_001.xml";
+ private static final String PROCESS_DEF_NAME =
"migratorValidityTestProcessDefinition_001";
+
+ public void testFindDeprecatedNodesInProcessDefinition() throws IOException {
+ String[] deprecatedNodes =
MigratorValiditionUtil.findDeprecatedNodesInProcessDefinition(createProcessDefinition(),
createMigrator(migrations));
+
+ assertEquals(2, deprecatedNodes.length);
+ assertTrue(ArrayUtils.contains(deprecatedNodes,
"firstSuperStateNode/first"));
+ assertTrue(ArrayUtils.contains(deprecatedNodes, "forkNodeThree"));
+ }
+
+ public void testFindMissingCurrentNodesInTheProcessDefinition() throws IOException {
+ String[] missingCurrentNodes =
MigratorValiditionUtil.findMissingCurrentNodesInTheProcessDefinition(createProcessDefinition(),
createMigrator(migrations));
+
+ assertEquals(2, missingCurrentNodes.length);
+ assertTrue(ArrayUtils.contains(missingCurrentNodes, "missingCurrentNode1"));
+ assertTrue(ArrayUtils.contains(missingCurrentNodes, "missingCurrentNode2"));
+ }
+
+ public void testFindCurrentNodesThatAreInvalidWaitStates() throws IOException {
+ String[] invalidNodes =
MigratorValiditionUtil.findCurrentNodesThatAreInvalidWaitStates(createProcessDefinition(),
createMigrator(migrations));
+
+ assertEquals(1, invalidNodes.length);
+ assertTrue(ArrayUtils.contains(invalidNodes,
"nonWaitSuperStateNode/nonWaitStateNode"));
+ }
+
+ public void testFindNode() throws Exception {
+ MigratorValiditionUtil.findNode(createProcessDefinition(),
"nonexistent-superstate/anything");
+ }
+
+ private static class TestMigration001 implements Migration{
+ public StateNodeMap createNodeMap() {
+ return new StateNodeMap(new String[][] {{"firstSuperStateNode/first",
"missingCurrentNode1"}});
+ }
+ }
+ private static class TestMigration002 implements Migration{
+ public StateNodeMap createNodeMap() {
+ return new StateNodeMap(new String[][]
{{"forkNodeThree","missingCurrentNode2"}});
+ }
+ }
+ private static class TestMigration003 implements Migration{
+ public StateNodeMap createNodeMap() {
+ return new StateNodeMap(new String[][]
{{"validDeprecatedNode","validSuperStateNode/validCurrentNode1"}});
+ }
+ }
+ private static class TestMigration004 implements Migration{
+ public StateNodeMap createNodeMap() {
+ return new StateNodeMap(new String[][]
{{"deprecatedNonWaitStateNode","nonWaitSuperStateNode/nonWaitStateNode"}});
+ }
+ }
+ private Migration[] migrations = new Migration[]{new TestMigration001(), new
TestMigration002(), new TestMigration003(), new TestMigration004()};
+
+ private Migrator createMigrator(Migration[] migrations) {
+ Migrator migrator = new Migrator(PROCESS_DEF_NAME, null, migrations, null);
+ return migrator;
+ }
+
+ private ProcessDefinition createProcessDefinition() throws IOException {
+ ProcessDefinition processDefinition =
MigrationUtils.getProcessDefinition(PROCESS_DEF_FILE_NAME);
+ return processDefinition;
+ }
+}
Added:
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/resources/hibernate.cfg.xml
===================================================================
---
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/resources/hibernate.cfg.xml
(rev 0)
+++
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/resources/hibernate.cfg.xml 2009-08-22
15:03:41 UTC (rev 5506)
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!DOCTYPE hibernate-configuration PUBLIC
+ "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
+ "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
+
+<hibernate-configuration>
+ <session-factory>
+ <mapping resource="org/jbpm/graph/action/Script.hbm.xml"/>
+ <mapping
resource="org/jbpm/context/exe/variableinstance/JcrNodeInstance.hbm.xml"/>
+ <mapping resource="org/jbpm/db/hibernate.queries.hbm.xml"/>
+ <mapping resource="org/jbpm/graph/action/MailAction.hbm.xml"/>
+ <mapping
resource="org/jbpm/graph/def/ProcessDefinition.hbm.xml"/>
+ <mapping resource="org/jbpm/graph/def/Node.hbm.xml"/>
+ <mapping resource="org/jbpm/graph/def/Transition.hbm.xml"/>
+ <mapping resource="org/jbpm/graph/def/Event.hbm.xml"/>
+ <mapping resource="org/jbpm/graph/def/Action.hbm.xml"/>
+ <mapping resource="org/jbpm/graph/def/SuperState.hbm.xml"/>
+ <mapping
resource="org/jbpm/graph/def/ExceptionHandler.hbm.xml"/>
+ <mapping resource="org/jbpm/instantiation/Delegation.hbm.xml"/>
+ <mapping resource="org/jbpm/graph/node/StartState.hbm.xml"/>
+ <mapping resource="org/jbpm/graph/node/EndState.hbm.xml"/>
+ <mapping resource="org/jbpm/graph/node/ProcessState.hbm.xml"/>
+ <mapping resource="org/jbpm/graph/node/Decision.hbm.xml"/>
+ <mapping resource="org/jbpm/graph/node/Fork.hbm.xml"/>
+ <mapping resource="org/jbpm/graph/node/Join.hbm.xml"/>
+ <mapping resource="org/jbpm/graph/node/MailNode.hbm.xml"/>
+ <mapping resource="org/jbpm/graph/node/State.hbm.xml"/>
+ <mapping resource="org/jbpm/graph/node/TaskNode.hbm.xml"/>
+ <mapping
resource="org/jbpm/context/def/ContextDefinition.hbm.xml"/>
+ <mapping
resource="org/jbpm/context/def/VariableAccess.hbm.xml"/>
+ <mapping
resource="org/jbpm/taskmgmt/def/TaskMgmtDefinition.hbm.xml"/>
+ <mapping resource="org/jbpm/taskmgmt/def/Swimlane.hbm.xml"/>
+ <mapping resource="org/jbpm/taskmgmt/def/Task.hbm.xml"/>
+ <mapping
resource="org/jbpm/taskmgmt/def/TaskController.hbm.xml"/>
+ <mapping
resource="org/jbpm/module/def/ModuleDefinition.hbm.xml"/>
+ <mapping resource="org/jbpm/bytes/ByteArray.hbm.xml"/>
+ <mapping resource="org/jbpm/file/def/FileDefinition.hbm.xml"/>
+ <mapping
resource="org/jbpm/scheduler/def/CreateTimerAction.hbm.xml"/>
+ <mapping
resource="org/jbpm/scheduler/def/CancelTimerAction.hbm.xml"/>
+ <mapping resource="org/jbpm/graph/exe/Comment.hbm.xml"/>
+ <mapping resource="org/jbpm/graph/exe/ProcessInstance.hbm.xml"/>
+ <mapping resource="org/jbpm/graph/exe/Token.hbm.xml"/>
+ <mapping resource="org/jbpm/graph/exe/RuntimeAction.hbm.xml"/>
+ <mapping resource="org/jbpm/module/exe/ModuleInstance.hbm.xml"/>
+ <mapping
resource="org/jbpm/context/exe/ContextInstance.hbm.xml"/>
+ <mapping
resource="org/jbpm/context/exe/TokenVariableMap.hbm.xml"/>
+ <mapping
resource="org/jbpm/context/exe/VariableInstance.hbm.xml"/>
+ <mapping
resource="org/jbpm/context/exe/variableinstance/ByteArrayInstance.hbm.xml"/>
+ <mapping
resource="org/jbpm/context/exe/variableinstance/DateInstance.hbm.xml"/>
+ <mapping
resource="org/jbpm/context/exe/variableinstance/DoubleInstance.hbm.xml"/>
+ <mapping
resource="org/jbpm/context/exe/variableinstance/HibernateLongInstance.hbm.xml"/>
+ <mapping
resource="org/jbpm/context/exe/variableinstance/HibernateStringInstance.hbm.xml"/>
+ <mapping
resource="org/jbpm/context/exe/variableinstance/LongInstance.hbm.xml"/>
+ <mapping
resource="org/jbpm/context/exe/variableinstance/NullInstance.hbm.xml"/>
+ <mapping
resource="org/jbpm/context/exe/variableinstance/StringInstance.hbm.xml"/>
+ <mapping resource="org/jbpm/job/Job.hbm.xml"/>
+ <mapping resource="org/jbpm/job/Timer.hbm.xml"/>
+ <mapping resource="org/jbpm/job/ExecuteNodeJob.hbm.xml"/>
+ <mapping resource="org/jbpm/job/ExecuteActionJob.hbm.xml"/>
+ <mapping
resource="org/jbpm/taskmgmt/exe/TaskMgmtInstance.hbm.xml"/>
+ <mapping resource="org/jbpm/taskmgmt/exe/TaskInstance.hbm.xml"/>
+ <mapping resource="org/jbpm/taskmgmt/exe/PooledActor.hbm.xml"/>
+ <mapping
resource="org/jbpm/taskmgmt/exe/SwimlaneInstance.hbm.xml"/>
+ <mapping resource="org/jbpm/logging/log/ProcessLog.hbm.xml"/>
+ <mapping resource="org/jbpm/logging/log/MessageLog.hbm.xml"/>
+ <mapping resource="org/jbpm/logging/log/CompositeLog.hbm.xml"/>
+ <mapping resource="org/jbpm/graph/log/ActionLog.hbm.xml"/>
+ <mapping resource="org/jbpm/graph/log/NodeLog.hbm.xml"/>
+ <mapping
resource="org/jbpm/graph/log/ProcessInstanceCreateLog.hbm.xml"/>
+ <mapping
resource="org/jbpm/graph/log/ProcessInstanceEndLog.hbm.xml"/>
+ <mapping resource="org/jbpm/graph/log/ProcessStateLog.hbm.xml"/>
+ <mapping resource="org/jbpm/graph/log/SignalLog.hbm.xml"/>
+ <mapping resource="org/jbpm/graph/log/TokenCreateLog.hbm.xml"/>
+ <mapping resource="org/jbpm/graph/log/TokenEndLog.hbm.xml"/>
+ <mapping resource="org/jbpm/graph/log/TransitionLog.hbm.xml"/>
+ <mapping resource="org/jbpm/context/log/VariableLog.hbm.xml"/>
+ <mapping
resource="org/jbpm/context/log/VariableCreateLog.hbm.xml"/>
+ <mapping
resource="org/jbpm/context/log/VariableDeleteLog.hbm.xml"/>
+ <mapping
resource="org/jbpm/context/log/VariableUpdateLog.hbm.xml"/>
+ <mapping
resource="org/jbpm/context/log/variableinstance/ByteArrayUpdateLog.hbm.xml"/>
+ <mapping
resource="org/jbpm/context/log/variableinstance/DateUpdateLog.hbm.xml"/>
+ <mapping
resource="org/jbpm/context/log/variableinstance/DoubleUpdateLog.hbm.xml"/>
+ <mapping
resource="org/jbpm/context/log/variableinstance/HibernateLongUpdateLog.hbm.xml"/>
+ <mapping
resource="org/jbpm/context/log/variableinstance/HibernateStringUpdateLog.hbm.xml"/>
+ <mapping
resource="org/jbpm/context/log/variableinstance/LongUpdateLog.hbm.xml"/>
+ <mapping
resource="org/jbpm/context/log/variableinstance/StringUpdateLog.hbm.xml"/>
+ <mapping resource="org/jbpm/taskmgmt/log/TaskLog.hbm.xml"/>
+ <mapping
resource="org/jbpm/taskmgmt/log/TaskCreateLog.hbm.xml"/>
+ <mapping
resource="org/jbpm/taskmgmt/log/TaskAssignLog.hbm.xml"/>
+ <mapping resource="org/jbpm/taskmgmt/log/TaskEndLog.hbm.xml"/>
+ <mapping resource="org/jbpm/taskmgmt/log/SwimlaneLog.hbm.xml"/>
+ <mapping
resource="org/jbpm/taskmgmt/log/SwimlaneCreateLog.hbm.xml"/>
+ <mapping
resource="org/jbpm/taskmgmt/log/SwimlaneAssignLog.hbm.xml"/>
+ </session-factory>
+</hibernate-configuration>
\ No newline at end of file
Added:
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/resources/log4j.properties
===================================================================
---
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/resources/log4j.properties
(rev 0)
+++
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/resources/log4j.properties 2009-08-22
15:03:41 UTC (rev 5506)
@@ -0,0 +1,15 @@
+# Set root logger level to INFO and its only appender to A1.
+log4j.rootLogger=WARN, A1
+log4j.logger.org.jbpm.instance.migration.util.JbpmInstanceMigratorLogger=DEBUG,
JbpmInstanceMigratorLogger
+
+# A1 is set to be a ConsoleAppender.
+log4j.appender.A1=org.apache.log4j.ConsoleAppender
+log4j.appender.JbpmInstanceMigratorLogger=org.apache.log4j.ConsoleAppender
+
+# A1 uses PatternLayout.
+log4j.appender.A1.layout=org.apache.log4j.PatternLayout
+log4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n
+
+# Migrator uses PatternLayout.
+log4j.appender.JbpmInstanceMigratorLogger.layout=org.apache.log4j.PatternLayout
+log4j.appender.JbpmInstanceMigratorLogger.layout.ConversionPattern=%-4r [%t] %-5p %c %x -
%m%n
Added:
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/resources/org/jbpm/instance/migration/mock-hibernate-spring.xml
===================================================================
---
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/resources/org/jbpm/instance/migration/mock-hibernate-spring.xml
(rev 0)
+++
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/resources/org/jbpm/instance/migration/mock-hibernate-spring.xml 2009-08-22
15:03:41 UTC (rev 5506)
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
+
+<beans>
+
+ <bean id="org.hibernate.SessionFactory"
+ class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
+ <property name="dataSource" ref="javax.sql.DataSource" />
+ <property name="configLocations">
+ <list>
+ <value>classpath:hibernate.cfg.xml</value>
+ </list>
+ </property>
+ <property name="hibernateProperties">
+ <props>
+ <!-- Echo all executed SQL to stdout -->
+ <prop key="hibernate.show_sql">false</prop>
+ <prop key="hibernate.format_sql">false</prop>
+ <!-- Since we're using Hyper Sonic for test only, we have to specify another
sessionfactory bean with HSQLDialect -->
+ <prop
key="hibernate.dialect">org.hibernate.dialect.HSQLDialect</prop>
+ <prop key="hibernate.hbm2ddl.auto">update</prop>
+ <prop
key="hibernate.cache.use_second_level_cache">false</prop>
+ <prop key="hibernate.cache.use_query_cache">false</prop>
+ <prop
key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop>
+ </props>
+ </property>
+ </bean>
+
+ <bean id="javax.sql.DataSource"
class="org.hsqldb.jdbc.jdbcDataSource">
+ <property name="database" value="jdbc:hsqldb:mem:temp" />
+ <property name="user" value="sa" />
+ <property name="password" value="" />
+ </bean>
+
+</beans>
\ No newline at end of file
Added:
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/resources/org/jbpm/instance/migration/simpleProcessDefinition_001.xml
===================================================================
---
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/resources/org/jbpm/instance/migration/simpleProcessDefinition_001.xml
(rev 0)
+++
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/resources/org/jbpm/instance/migration/simpleProcessDefinition_001.xml 2009-08-22
15:03:41 UTC (rev 5506)
@@ -0,0 +1,35 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<process-definition xmlns='urn:jbpm.org:jpdl-3.2' name='simple'>
+ <start-state name='start'>
+ <transition name='to_A' to='A'>
+ </transition>
+ </start-state>
+ <state name='A'>
+ <transition name='to_Fork1' to='Fork1'/>
+ </state>
+
+ <fork name="Fork1">
+ <transition name="to_forkNode1"
to="forkNode1"></transition>
+ <transition name="to_forkNode2"
to="forkNode2"></transition>
+ <transition name="to_forkNode3"
to="forkNode3"></transition>
+ </fork>
+ <state name='forkNode1'>
+ <transition name='to_Join1' to='Join1' />
+ </state>
+ <state name='forkNode2'>
+ <transition name='to_Join1' to='Join1' />
+ </state>
+ <state name='forkNode3'>
+ <transition name='to_Join1' to='Join1' />
+ </state>
+ <join name="Join1">
+ <transition to="B"></transition>
+ </join>
+
+ <state name='B'>
+ <transition name='to_end' to='end' />
+ </state>
+
+ <end-state name='end'></end-state>
+</process-definition>
+
\ No newline at end of file
Added:
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/resources/org/jbpm/instance/migration/simpleProcessDefinition_002.xml
===================================================================
---
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/resources/org/jbpm/instance/migration/simpleProcessDefinition_002.xml
(rev 0)
+++
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/resources/org/jbpm/instance/migration/simpleProcessDefinition_002.xml 2009-08-22
15:03:41 UTC (rev 5506)
@@ -0,0 +1,35 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<process-definition xmlns='urn:jbpm.org:jpdl-3.2' name='simple'>
+ <start-state name='start'>
+ <transition name='to_first' to='first'>
+ </transition>
+ </start-state>
+
+ <state name='first'>
+ <transition name='to_Fork1' to='Fork1'/>
+ </state>
+
+ <fork name="Fork1">
+ <transition name="to_forkNode1"
to="forkNode1"></transition>
+ <transition name="to_forkNode2"
to="forkNode2"></transition>
+ <transition name="to_forkNode3"
to="forkNode3"></transition>
+ </fork>
+ <state name='forkNode1'>
+ <transition name='to_Join1' to='Join1' />
+ </state>
+ <state name='forkNode2'>
+ <transition name='to_Join1' to='Join1' />
+ </state>
+ <state name='forkNode3'>
+ <transition name='to_Join1' to='Join1' />
+ </state>
+ <join name="Join1">
+ <transition to="second"></transition>
+ </join>
+
+ <state name='second'>
+ <transition name='to_end' to='end' />
+ </state>
+ <end-state name='end'></end-state>
+</process-definition>
+
\ No newline at end of file
Added:
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/resources/org/jbpm/instance/migration/simpleProcessDefinition_003.xml
===================================================================
---
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/resources/org/jbpm/instance/migration/simpleProcessDefinition_003.xml
(rev 0)
+++
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/resources/org/jbpm/instance/migration/simpleProcessDefinition_003.xml 2009-08-22
15:03:41 UTC (rev 5506)
@@ -0,0 +1,39 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<process-definition xmlns='urn:jbpm.org:jpdl-3.2' name='simple'>
+ <start-state name='start'>
+ <transition name='to_first' to='first'>
+ </transition>
+ </start-state>
+
+ <state name='first'>
+ <transition name='to_Fork1' to='Fork1'/>
+ </state>
+
+ <fork name="Fork1">
+ <transition name="to_forkNode1"
to="forkNodeOne"></transition>
+ <transition name="to_forkNode2"
to="forkNodeTwo"></transition>
+ <transition name="to_forkNode3"
to="forkNodeThree"></transition>
+ </fork>
+ <state name='forkNodeOne'>
+ <transition name='to_Join1' to='Join1' />
+ </state>
+ <state name='forkNodeTwo'>
+ <transition name='to_Join1' to='Join1' />
+ </state>
+ <state name='forkNodeThree'>
+ <transition name='to_Join1' to='Join1' />
+ </state>
+ <join name="Join1">
+ <transition to="second"></transition>
+ </join>
+
+ <state name='second'>
+ <transition name='to_third' to='third' />
+ </state>
+ <state name='third'>
+ <transition name='to_end' to='end' />
+ </state>
+
+ <end-state name='end'></end-state>
+</process-definition>
+
\ No newline at end of file
Added:
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/resources/org/jbpm/instance/migration/simpleSubProcessDefinition_001.xml
===================================================================
---
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/resources/org/jbpm/instance/migration/simpleSubProcessDefinition_001.xml
(rev 0)
+++
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/resources/org/jbpm/instance/migration/simpleSubProcessDefinition_001.xml 2009-08-22
15:03:41 UTC (rev 5506)
@@ -0,0 +1,17 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<process-definition xmlns='urn:jbpm.org:jpdl-3.2'
name='simpleSubProcess'>
+ <start-state name='start'>
+ <transition name='to_SubA' to='SubA' />
+ </start-state>
+
+ <state name='SubA'>
+ <transition name='to_SubB' to='SubB'/>
+ </state>
+
+ <state name='SubB'>
+ <transition name='to_end' to='end' />
+ </state>
+
+ <end-state name='end' />
+</process-definition>
+
\ No newline at end of file
Added:
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/resources/org/jbpm/instance/migration/simpleSubProcessDefinition_002.xml
===================================================================
---
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/resources/org/jbpm/instance/migration/simpleSubProcessDefinition_002.xml
(rev 0)
+++
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/resources/org/jbpm/instance/migration/simpleSubProcessDefinition_002.xml 2009-08-22
15:03:41 UTC (rev 5506)
@@ -0,0 +1,17 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<process-definition xmlns='urn:jbpm.org:jpdl-3.2'
name='simpleSubProcess'>
+ <start-state name='start'>
+ <transition name='to_Sub1' to='Sub1' />
+ </start-state>
+
+ <state name='Sub1'>
+ <transition name='to_SubB' to='SubB'/>
+ </state>
+
+ <state name='SubB'>
+ <transition name='to_end' to='end' />
+ </state>
+
+ <end-state name='end' />
+</process-definition>
+
\ No newline at end of file
Added:
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/resources/org/jbpm/instance/migration/simpleSuperProcessDefinition_001.xml
===================================================================
---
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/resources/org/jbpm/instance/migration/simpleSuperProcessDefinition_001.xml
(rev 0)
+++
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/resources/org/jbpm/instance/migration/simpleSuperProcessDefinition_001.xml 2009-08-22
15:03:41 UTC (rev 5506)
@@ -0,0 +1,39 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<process-definition xmlns='urn:jbpm.org:jpdl-3.2'
name='simpleSuperProcess'>
+ <start-state name='start'>
+ <transition name='to_A' to='A' />
+ </start-state>
+ <state name='A'>
+ <transition name='to_Fork1' to='Fork1'/>
+ </state>
+
+ <fork name="Fork1">
+ <transition name="to_forkNode1"
to="forkNode1"></transition>
+ <transition name="to_forkNode2"
to="forkNode2"></transition>
+ <transition name="to_forkNode3"
to="forkNode3"></transition>
+ </fork>
+
+ <state name='forkNode1'>
+ <transition name='to_Join1' to='Join1' />
+ </state>
+
+ <state name='forkNode2'>
+ <transition name='to_Join1' to='Join1' />
+ </state>
+
+ <process-state name='forkNode3'>
+ <sub-process name="simpleSubProcess"></sub-process>
+ <transition name='to_Join1' to='Join1' />
+ </process-state>
+
+ <join name="Join1">
+ <transition to="B"></transition>
+ </join>
+
+ <state name='B'>
+ <transition name='to_end' to='end' />
+ </state>
+
+ <end-state name='end'></end-state>
+</process-definition>
+
\ No newline at end of file
Added:
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/resources/org/jbpm/instance/migration/simpleSuperProcessDefinition_002.xml
===================================================================
---
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/resources/org/jbpm/instance/migration/simpleSuperProcessDefinition_002.xml
(rev 0)
+++
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/resources/org/jbpm/instance/migration/simpleSuperProcessDefinition_002.xml 2009-08-22
15:03:41 UTC (rev 5506)
@@ -0,0 +1,39 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<process-definition xmlns='urn:jbpm.org:jpdl-3.2'
name='simpleSuperProcess'>
+ <start-state name='start'>
+ <transition name='to_A' to='A' />
+ </start-state>
+ <state name='A'>
+ <transition name='to_Fork1' to='Fork1'/>
+ </state>
+
+ <fork name="Fork1">
+ <transition name="to_forkNode1"
to="forkNode1"></transition>
+ <transition name="to_forkNode2"
to="forkNode2"></transition>
+ <transition name="to_forkNode3"
to="forkNode3"></transition>
+ </fork>
+
+ <state name='forkNode1'>
+ <transition name='to_Join1' to='Join1' />
+ </state>
+
+ <state name='forkNode2'>
+ <transition name='to_Join1' to='Join1' />
+ </state>
+
+ <process-state name='forkNode3'>
+ <sub-process name="simpleSubProcess"></sub-process>
+ <transition name='to_Join1' to='Join1' />
+ </process-state>
+
+ <join name="Join1">
+ <transition to="B"></transition>
+ </join>
+
+ <state name='B'>
+ <transition name='to_end' to='end' />
+ </state>
+
+ <end-state name='end'></end-state>
+</process-definition>
+
\ No newline at end of file
Added:
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/resources/org/jbpm/instance/migration/superstateMigratorTest_001.xml
===================================================================
---
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/resources/org/jbpm/instance/migration/superstateMigratorTest_001.xml
(rev 0)
+++
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/resources/org/jbpm/instance/migration/superstateMigratorTest_001.xml 2009-08-22
15:03:41 UTC (rev 5506)
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<process-definition xmlns='urn:jbpm.org:jpdl-3.2'
name="superStateMigratorTestProcessDefinition">
+
+
+ <start-state name="Start">
+ <transition to="Saving" name="save"></transition>
+ </start-state>
+
+ <node name="Saving">
+ <event type="node-enter">
+ </event>
+ <transition name="" to="Saved"></transition>
+ </node>
+
+ <state name="Saved">
+ <transition to="Deleted" name="cancel">
+ </transition>
+ </state>
+
+
+ <end-state name="Deleted"></end-state>
+
+
+</process-definition>
\ No newline at end of file
Added:
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/resources/org/jbpm/instance/migration/superstateMigratorTest_002.xml
===================================================================
---
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/resources/org/jbpm/instance/migration/superstateMigratorTest_002.xml
(rev 0)
+++
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/resources/org/jbpm/instance/migration/superstateMigratorTest_002.xml 2009-08-22
15:03:41 UTC (rev 5506)
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<process-definition xmlns='urn:jbpm.org:jpdl-3.2'
name="superStateMigratorTestProcessDefinition">
+
+
+ <start-state name="Start">
+ <transition to="superStateNode/Saving"
name="save"></transition>
+ </start-state>
+
+ <super-state name="superStateNode">
+ <node name="Saving">
+ <event type="node-enter">
+ </event>
+ <transition name="" to="Saved"></transition>
+ </node>
+
+ <state name="Saved">
+ <transition to="../Deleted" name="cancel">
+ </transition>
+ </state>
+
+ </super-state>
+
+ <end-state name="Deleted"></end-state>
+
+
+</process-definition>
\ No newline at end of file
Added:
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/resources/org/jbpm/instance/migration/superstateMigratorTest_003.xml
===================================================================
---
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/resources/org/jbpm/instance/migration/superstateMigratorTest_003.xml
(rev 0)
+++
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/resources/org/jbpm/instance/migration/superstateMigratorTest_003.xml 2009-08-22
15:03:41 UTC (rev 5506)
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<process-definition xmlns='urn:jbpm.org:jpdl-3.2'
name="superStateMigratorTestProcessDefinition">
+
+
+ <start-state name="Start">
+ <transition to="superStateNode/Saving"
name="save"></transition>
+ </start-state>
+
+ <super-state name="superStateNode">
+ <node name="Saving">
+ <event type="node-enter">
+ </event>
+ <transition name="" to="Saved2"></transition>
+ </node>
+
+ <state name="Saved2">
+ <transition to="../Deleted" name="cancel">
+ </transition>
+ </state>
+ </super-state>
+
+ <end-state name="Deleted"></end-state>
+
+
+</process-definition>
\ No newline at end of file
Added:
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/resources/org/jbpm/instance/migration/superstateMigratorTest_004.xml
===================================================================
---
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/resources/org/jbpm/instance/migration/superstateMigratorTest_004.xml
(rev 0)
+++
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/resources/org/jbpm/instance/migration/superstateMigratorTest_004.xml 2009-08-22
15:03:41 UTC (rev 5506)
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<process-definition xmlns='urn:jbpm.org:jpdl-3.2'
name="superStateMigratorTestProcessDefinition">
+
+
+ <start-state name="Start">
+ <transition to="superDuperStateNode/superStateNode/Saving"
name="save"></transition>
+ </start-state>
+
+ <super-state name="superDuperStateNode">
+ <super-state name="superStateNode">
+ <node name="Saving">
+ <event type="node-enter">
+ </event>
+ <transition name="" to="Saved2"></transition>
+ </node>
+
+ <state name="Saved2">
+ <transition to="../../Deleted" name="cancel">
+ </transition>
+ </state>
+ </super-state>
+ </super-state>
+
+ <end-state name="Deleted"></end-state>
+
+
+</process-definition>
\ No newline at end of file
Added:
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/resources/org/jbpm/instance/migration/util/migratorValidityTestProcessDefinition_001.xml
===================================================================
---
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/resources/org/jbpm/instance/migration/util/migratorValidityTestProcessDefinition_001.xml
(rev 0)
+++
projects/instance-migration/trunk/jbpm-instance-migrator/src/test/resources/org/jbpm/instance/migration/util/migratorValidityTestProcessDefinition_001.xml 2009-08-22
15:03:41 UTC (rev 5506)
@@ -0,0 +1,48 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<process-definition xmlns='urn:jbpm.org:jpdl-3.2'
name='migratorValidityTestProcessDefinition_001'>
+ <start-state name='start'>
+ <transition name='firstSuperStateNode/to_first' to='first'>
+ </transition>
+ </start-state>
+
+ <super-state name="firstSuperStateNode">
+ <state name='first'>
+ <transition name='../to_Fork1' to='Fork1'/>
+ </state>
+ </super-state>
+
+ <fork name="Fork1">
+ <transition name="to_forkNode1"
to="forkNodeOne"></transition>
+ <transition name="to_forkNode2"
to="nonWaitStateNode"></transition>
+ <transition name="to_forkNode3"
to="forkNodeThree"></transition>
+ </fork>
+ <state name='forkNodeOne'>
+ <transition name='to_Join1' to='Join1' />
+ </state>
+
+ <super-state name="nonWaitSuperStateNode">
+ <node name='nonWaitStateNode'>
+ <transition name='to_Join1' to='Join1' />
+ </node>
+ </super-state>
+ <state name='forkNodeThree'>
+ <transition name='to_Join1' to='Join1' />
+ </state>
+ <join name="Join1">
+ <transition to="second"></transition>
+ </join>
+
+
+ <super-state name="validSuperStateNode">
+ <state name='validCurrentNode1'>
+ <transition name='to_third' to='third' />
+ </state>
+ </super-state>
+
+ <state name='third'>
+ <transition name='to_end' to='end' />
+ </state>
+
+ <end-state name='end'></end-state>
+</process-definition>
+