[jbpm-commits] JBoss JBPM SVN: r5049 - in jbpm4/trunk/modules/test-concurrent: src and 13 other directories.

do-not-reply at jboss.org do-not-reply at jboss.org
Wed Jun 17 04:57:16 EDT 2009


Author: jbarrez
Date: 2009-06-17 04:57:15 -0400 (Wed, 17 Jun 2009)
New Revision: 5049

Added:
   jbpm4/trunk/modules/test-concurrent/.classpath
   jbpm4/trunk/modules/test-concurrent/.project
   jbpm4/trunk/modules/test-concurrent/pom.xml
   jbpm4/trunk/modules/test-concurrent/src/
   jbpm4/trunk/modules/test-concurrent/src/main/
   jbpm4/trunk/modules/test-concurrent/src/main/java/
   jbpm4/trunk/modules/test-concurrent/src/main/java/org/
   jbpm4/trunk/modules/test-concurrent/src/main/java/org/jbpm/
   jbpm4/trunk/modules/test-concurrent/src/main/java/org/jbpm/test/
   jbpm4/trunk/modules/test-concurrent/src/main/java/org/jbpm/test/concurrent/
   jbpm4/trunk/modules/test-concurrent/src/main/java/org/jbpm/test/concurrent/ConcurrentJbpmTestCase.java
   jbpm4/trunk/modules/test-concurrent/src/main/java/org/jbpm/test/concurrent/JobExecutorEmulator.java
   jbpm4/trunk/modules/test-concurrent/src/main/java/org/jbpm/test/concurrent/JobExecutorEmulatorPool.java
   jbpm4/trunk/modules/test-concurrent/src/main/java/org/jbpm/test/concurrent/JobExecutorEmulatorSynchronization.java
   jbpm4/trunk/modules/test-concurrent/src/main/resources/
   jbpm4/trunk/modules/test-concurrent/src/test/
   jbpm4/trunk/modules/test-concurrent/src/test/java/
   jbpm4/trunk/modules/test-concurrent/src/test/java/org/
   jbpm4/trunk/modules/test-concurrent/src/test/java/org/jbpm/
   jbpm4/trunk/modules/test-concurrent/src/test/java/org/jbpm/test/
   jbpm4/trunk/modules/test-concurrent/src/test/java/org/jbpm/test/concurrent/
   jbpm4/trunk/modules/test-concurrent/src/test/java/org/jbpm/test/concurrent/OptimisticLockTestGround.java
   jbpm4/trunk/modules/test-concurrent/src/test/java/org/jbpm/test/concurrent/PassThroughActivity.java
   jbpm4/trunk/modules/test-concurrent/src/test/java/org/jbpm/test/concurrent/TimerVsSignalConcurrencyTest.java
   jbpm4/trunk/modules/test-concurrent/src/test/resources/
   jbpm4/trunk/modules/test-concurrent/src/test/resources/jbpm.cfg.xml
   jbpm4/trunk/modules/test-concurrent/src/test/resources/jbpm.hibernate.cfg.xml
   jbpm4/trunk/modules/test-concurrent/src/test/resources/logging.properties
Log:
Initial import for concurrency tests (JBPM-1987)

Added: jbpm4/trunk/modules/test-concurrent/.classpath
===================================================================
--- jbpm4/trunk/modules/test-concurrent/.classpath	                        (rev 0)
+++ jbpm4/trunk/modules/test-concurrent/.classpath	2009-06-17 08:57:15 UTC (rev 5049)
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="src" output="target/classes" path="src/main/java"/>
+	<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources"/>
+	<classpathentry kind="src" output="target/test-classes" path="src/test/java"/>
+	<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+	<classpathentry kind="con" path="org.maven.ide.eclipse.MAVEN2_CLASSPATH_CONTAINER"/>
+	<classpathentry kind="output" path="target/classes"/>
+</classpath>

Added: jbpm4/trunk/modules/test-concurrent/.project
===================================================================
--- jbpm4/trunk/modules/test-concurrent/.project	                        (rev 0)
+++ jbpm4/trunk/modules/test-concurrent/.project	2009-06-17 08:57:15 UTC (rev 5049)
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>test-concurrent</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.maven.ide.eclipse.maven2Builder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+		<nature>org.maven.ide.eclipse.maven2Nature</nature>
+	</natures>
+</projectDescription>

Added: jbpm4/trunk/modules/test-concurrent/pom.xml
===================================================================
--- jbpm4/trunk/modules/test-concurrent/pom.xml	                        (rev 0)
+++ jbpm4/trunk/modules/test-concurrent/pom.xml	2009-06-17 08:57:15 UTC (rev 5049)
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- ====================================================================== -->
+<!--                                                                        -->
+<!--  JBoss, the OpenSource J2EE webOS                                      -->
+<!--                                                                        -->
+<!--  Distributable under LGPL license.                                     -->
+<!--  See terms of license at http://www.gnu.org.                           -->
+<!--                                                                        -->
+<!-- ====================================================================== -->
+
+<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>
+  <name>jBPM 4 - Test DB</name>
+  <groupId>org.jbpm.jbpm4</groupId>
+  <artifactId>jbpm-test-concurrent</artifactId>
+  <packaging>jar</packaging>
+
+  <!-- Parent -->
+  <parent>
+    <groupId>org.jbpm.jbpm4</groupId>
+    <artifactId>jbpm</artifactId>
+    <version>4.0-SNAPSHOT</version>
+    <relativePath>../../pom.xml</relativePath>
+  </parent>
+
+  <!-- Dependencies -->
+  <dependencies>
+
+    <dependency>
+      <groupId>org.jbpm.jbpm4</groupId>
+      <artifactId>jbpm-api</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.jbpm.jbpm4</groupId>
+      <artifactId>jbpm-jpdl</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.jbpm.jbpm4</groupId>
+      <artifactId>jbpm-pvm</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.jbpm.jbpm4</groupId>
+      <artifactId>jbpm-test-base</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+	<!-- DB drivers -->
+	
+	<dependency>
+		<groupId>com.h2database</groupId>
+		<artifactId>h2</artifactId>
+		<version>1.1.114</version>
+	</dependency>
+	<dependency>
+		<groupId>postgresql</groupId>
+		<artifactId>postgresql</artifactId>
+		<version>8.3-603.jdbc4</version>
+	</dependency>
+
+  </dependencies>
+
+</project>
\ No newline at end of file

Added: jbpm4/trunk/modules/test-concurrent/src/main/java/org/jbpm/test/concurrent/ConcurrentJbpmTestCase.java
===================================================================
--- jbpm4/trunk/modules/test-concurrent/src/main/java/org/jbpm/test/concurrent/ConcurrentJbpmTestCase.java	                        (rev 0)
+++ jbpm4/trunk/modules/test-concurrent/src/main/java/org/jbpm/test/concurrent/ConcurrentJbpmTestCase.java	2009-06-17 08:57:15 UTC (rev 5049)
@@ -0,0 +1,75 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+/**
+ * 
+ */
+package org.jbpm.test.concurrent;
+
+import org.jbpm.api.env.EnvironmentFactory;
+import org.jbpm.test.JbpmTestCase;
+
+
+/**
+ * Base class for unit tests involving testing concurrency.
+ * 
+ * @author Joram Barrez
+ */
+public abstract class ConcurrentJbpmTestCase extends JbpmTestCase {
+  
+  protected EnvironmentFactory environmentFactory;
+
+  protected void setUp() throws Exception {
+    super.setUp();
+    this.environmentFactory = (EnvironmentFactory) processEngine; // Is there a better way to do this?
+  }
+  
+  protected class OffloadThread extends Thread {
+    
+    private ThreadCallback threadCallback;
+    
+    private Exception exception;
+    
+    public OffloadThread(ThreadCallback threadCallback) {
+      this.threadCallback = threadCallback;
+    }
+
+    public void run() {
+      try {
+       threadCallback.executeInThread(); 
+      } catch (Exception e) {
+        this.exception = e;
+      }
+    }
+
+    public Exception getException() {
+      return exception;
+    }
+    
+  }
+  
+  protected interface ThreadCallback {
+    
+    void executeInThread();
+    
+  }
+
+}

Added: jbpm4/trunk/modules/test-concurrent/src/main/java/org/jbpm/test/concurrent/JobExecutorEmulator.java
===================================================================
--- jbpm4/trunk/modules/test-concurrent/src/main/java/org/jbpm/test/concurrent/JobExecutorEmulator.java	                        (rev 0)
+++ jbpm4/trunk/modules/test-concurrent/src/main/java/org/jbpm/test/concurrent/JobExecutorEmulator.java	2009-06-17 08:57:15 UTC (rev 5049)
@@ -0,0 +1,302 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+/**
+ * 
+ */
+package org.jbpm.test.concurrent;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.BrokenBarrierException;
+import java.util.concurrent.CyclicBarrier;
+
+import org.jbpm.api.env.Environment;
+import org.jbpm.api.env.EnvironmentFactory;
+import org.jbpm.api.job.Job;
+import org.jbpm.pvm.internal.cmd.ExecuteJobCmd;
+import org.jbpm.pvm.internal.tx.StandardTransaction;
+
+/**
+ * Emulates the JobExecutorThread by executing the ExecuteJobCmd in 
+ * a dedicated thread. 
+ * 
+ * Has several sync points available (see {@link JobExecutorEmulatorSynchronization}):
+ * - before/after transaction is started
+ * - before/after job execution
+ * - before/after transaction is done (ie commit)
+ * 
+ * TODO: implement transaction sync, now only sync on job execution is done - waiting until use case passes by
+ * 
+ * @author Joram Barrez
+ */
+public class JobExecutorEmulator extends Thread {
+    
+    /** Used to create environment blocks */
+    private EnvironmentFactory environmentFactory;
+  
+    /** The database id of the job that is executed by this JobExecutorEmulator */
+    private Long jobId;
+    
+    /** 
+     * If an exception occurs in a thread that is not the JUnit thread, then
+     * the JUnit thread will never notice this. The solution is to catch the
+     * exception and store it in this field, so the JUnit thread can check
+     * if there were any exceptions when executing the job.
+     */
+    private Exception exception;
+    
+    /** Indicates if the thread must be blocked (ie this.wait() must be called) */
+    private boolean threadBlocked;
+    
+    /**
+     * List of synchronizations that will be called on specific point in the
+     * execution of this thread.
+     */
+    private List<JobExecutorEmulatorSynchronization> synchronizations;
+    
+    /* SYNC PRIMITIVES */
+    
+    /** Sync point when the job is executed */
+    private CyclicBarrier afterJobExecutionBarrier;
+    
+    private List<String> afterJobExecutionSyncThreads;
+    
+    /** Sync point before the job is executed */
+    private CyclicBarrier beforeJobExecutionBarrier;
+    
+    private List<String> beforeJobExecutionSyncThreads;
+    
+    /**
+     * Constructor.
+     * 
+     * @param job The job that must be executred by this emulator.
+     */
+    public JobExecutorEmulator(EnvironmentFactory environmentFactory, Job job) {
+      this.environmentFactory = environmentFactory;
+      this.jobId = job.getDbid();
+      this.threadBlocked = false;
+      
+      this.synchronizations = new ArrayList<JobExecutorEmulatorSynchronization>();
+      synchronizations.add(new DefaultSynchronization());
+    }
+    
+    public void run() {
+      
+      Environment environment = environmentFactory.openEnvironment();
+      StandardTransaction standardTransaction = environment.get(StandardTransaction.class);
+      standardTransaction.begin();
+
+      try {
+        
+        handleBeforeJobExecutionSynchronizations();
+        ExecuteJobCmd executeJobCmd = new ExecuteJobCmd(jobId);
+        executeJobCmd.execute(environment);
+        handleAfterJobExecutionSynchronizations(); // Sync point: after job execution
+        
+      } catch (Exception e) {
+        
+        standardTransaction.setRollbackOnly();
+        this.exception = e;
+        
+      } finally {
+                
+        if (standardTransaction.isRollbackOnly()) {
+          exception = new Exception("Transaction was rollbacked due to an exception");
+        }
+        
+        try {
+          standardTransaction.complete();
+        } catch (Exception e) {
+          
+        }
+        
+      }
+      environment.close();
+    }
+    
+    /**
+     * Executes all synchronizations that must be executed before the job is executed
+     */
+    private void handleBeforeJobExecutionSynchronizations() {
+      for (JobExecutorEmulatorSynchronization synchronization : synchronizations) {
+        synchronization.beforeJobExecution();
+      }
+    }
+    
+    /**
+     * Executes all synchronizations that must be executed when the job is executed
+     */
+    private void handleAfterJobExecutionSynchronizations() {
+      for (JobExecutorEmulatorSynchronization synchronization : synchronizations) {
+        synchronization.afterJobExecution();
+      }
+    }
+    
+    /**
+     * Unit tests that use this class can use this method to synchronize
+     * when the job just has been executed.
+     * 
+     * @param blockJobExecutor If true, the jobExecutor will be halted
+     * when leaving the synchronisation point
+     */
+    public void waitUntilJobExecuted(boolean blockJobExecutor) {
+      if (afterJobExecutionBarrier != null) {
+        try {
+          threadBlocked = blockJobExecutor;
+          afterJobExecutionBarrier.await();
+        } catch (InterruptedException e) {
+          e.printStackTrace();
+        } catch (BrokenBarrierException e) {
+          e.printStackTrace();
+        }
+      }
+    }
+    
+    public JobExecutorEmulator synchroniseAfterJobExecution(String threadName) {
+      if (isAlive()) {
+        throw new RuntimeException("Cannot set synchronization point once the JobExecutorEmulator has been started");
+      }
+      
+      if (afterJobExecutionSyncThreads == null) {
+        afterJobExecutionSyncThreads = new ArrayList<String>();
+      }
+      
+      if (afterJobExecutionBarrier == null ) {
+        afterJobExecutionBarrier = new CyclicBarrier(2);
+      } else {
+        afterJobExecutionBarrier = new CyclicBarrier(afterJobExecutionBarrier.getParties() + 1);
+      }
+      
+      return this;
+    }
+    
+    public JobExecutorEmulator synchroniseBeforeJobExecution(String threadName) {
+      if (isAlive()) {
+        throw new RuntimeException("Cannot set synchronization point once the JobExecutorEmulator has been started");
+      }
+      
+      if (beforeJobExecutionBarrier == null) {
+        beforeJobExecutionSyncThreads = new ArrayList<String>();
+      }
+      
+      if (beforeJobExecutionBarrier == null ) {
+        beforeJobExecutionBarrier = new CyclicBarrier(2);
+      } else {
+        beforeJobExecutionBarrier = new CyclicBarrier(beforeJobExecutionBarrier.getParties() + 1);
+      }
+      
+      return this;
+    }
+    
+    /**
+     * Helper method: check if the flag 'threadBlocked' has been raised.
+     * If so, this thread will block until it is notified again.
+     */
+    private void blockIfNeeded() {
+      if (threadBlocked) {
+        synchronized (this) {
+          try {
+            threadBlocked = false;
+            wait();
+          } catch (InterruptedException e) {
+            e.printStackTrace();
+          }
+        }
+      }
+    }
+    
+    /**
+     * Unit tests can use this method to proceed a halted JobExecutorEmulator.
+     * (ie this means that the wait() was called on this thread in the past).
+     */
+    public void goOn() {
+      synchronized (this) {
+          notify();
+      };
+    }
+    
+    /**
+     * Adds a custom synchronization to the JobExecutorEmulator.
+     */
+    public void addSynchronization(JobExecutorEmulatorSynchronization synchronization) {
+      synchronizations.add(synchronization);
+    }
+    
+    /* GETTERS AND SETTERS */
+    
+    public Exception getException() {
+      return exception;
+    }
+    
+    public boolean isBlockThread() {
+      return threadBlocked;
+    }
+
+    public void setBlockThread(boolean blockThread) {
+      this.threadBlocked = blockThread;
+    }
+
+    public void setAfterJobExecutionBarrier(CyclicBarrier afterJobExecutionBarrier) {
+      this.afterJobExecutionBarrier = afterJobExecutionBarrier;
+    }
+
+    public void setBeforeJobExecutionBarrier(CyclicBarrier beforeJobExecutionBarrier) {
+      this.beforeJobExecutionBarrier = beforeJobExecutionBarrier;
+    }
+
+    /**
+     * Default synchronization, executed by all JobExecutorEmulators.
+     * The default logic will synchronize at every sync point (ie barrier) 
+     * which is not null and will check if any external caller has raised
+     * the 'threadBlocked' flag.
+     */
+    private class DefaultSynchronization extends JobExecutorEmulatorSynchronization {
+      
+      public void afterJobExecution() {;
+        if (afterJobExecutionBarrier != null) {
+          try {
+            afterJobExecutionBarrier.await();
+            blockIfNeeded();
+          } catch (InterruptedException e) {
+            e.printStackTrace();
+          } catch (BrokenBarrierException e) {
+            e.printStackTrace();
+          }
+        }
+      }
+      
+      public void beforeJobExecution() {;
+      if (beforeJobExecutionBarrier != null) {
+        try {
+          beforeJobExecutionBarrier.await();
+          blockIfNeeded();
+        } catch (InterruptedException e) {
+          e.printStackTrace();
+        } catch (BrokenBarrierException e) {
+          e.printStackTrace();
+        }
+      }
+    }
+      
+    }
+
+}

Added: jbpm4/trunk/modules/test-concurrent/src/main/java/org/jbpm/test/concurrent/JobExecutorEmulatorPool.java
===================================================================
--- jbpm4/trunk/modules/test-concurrent/src/main/java/org/jbpm/test/concurrent/JobExecutorEmulatorPool.java	                        (rev 0)
+++ jbpm4/trunk/modules/test-concurrent/src/main/java/org/jbpm/test/concurrent/JobExecutorEmulatorPool.java	2009-06-17 08:57:15 UTC (rev 5049)
@@ -0,0 +1,53 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+/**
+ * 
+ */
+package org.jbpm.test.concurrent;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.jbpm.api.env.EnvironmentFactory;
+import org.jbpm.api.job.Job;
+
+
+/**
+ * @author Joram Barrez
+ */
+public class JobExecutorEmulatorPool {
+  
+  private EnvironmentFactory environmentFactory;
+  
+  private List<JobExecutorEmulator> jobExecutorEmulators;
+  
+  public JobExecutorEmulatorPool(EnvironmentFactory environmentFactory) {
+    this.environmentFactory = environmentFactory;
+    this.jobExecutorEmulators = new ArrayList<JobExecutorEmulator>();
+  }
+  
+  public void emulateJobExecution(Collection<Job> jobs) {
+    
+  }
+
+}

Added: jbpm4/trunk/modules/test-concurrent/src/main/java/org/jbpm/test/concurrent/JobExecutorEmulatorSynchronization.java
===================================================================
--- jbpm4/trunk/modules/test-concurrent/src/main/java/org/jbpm/test/concurrent/JobExecutorEmulatorSynchronization.java	                        (rev 0)
+++ jbpm4/trunk/modules/test-concurrent/src/main/java/org/jbpm/test/concurrent/JobExecutorEmulatorSynchronization.java	2009-06-17 08:57:15 UTC (rev 5049)
@@ -0,0 +1,47 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+/**
+ * 
+ */
+package org.jbpm.test.concurrent;
+
+/**
+ * Implementations can extend this class to add logic to sync points of the
+ * {@link JobExecutorEmulator}.
+ * 
+ * @author Joram Barrez
+ */
+public abstract class JobExecutorEmulatorSynchronization {
+  
+  public void beforeTransactionStarts() { }
+  
+  public void afterTransactionStarted() { }
+  
+  public void beforeJobExecution() { }
+  
+  public void afterJobExecution() { }
+  
+  public void beforeTransactionDone() { }
+  
+  public void afterTransactionDone() { }
+
+}

Added: jbpm4/trunk/modules/test-concurrent/src/test/java/org/jbpm/test/concurrent/OptimisticLockTestGround.java
===================================================================
--- jbpm4/trunk/modules/test-concurrent/src/test/java/org/jbpm/test/concurrent/OptimisticLockTestGround.java	                        (rev 0)
+++ jbpm4/trunk/modules/test-concurrent/src/test/java/org/jbpm/test/concurrent/OptimisticLockTestGround.java	2009-06-17 08:57:15 UTC (rev 5049)
@@ -0,0 +1,256 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+/**
+ * 
+ */
+package org.jbpm.test.concurrent;
+
+import java.util.List;
+import java.util.concurrent.Semaphore;
+
+import org.jbpm.api.Execution;
+import org.jbpm.api.ProcessInstance;
+import org.jbpm.api.env.Environment;
+import org.jbpm.api.env.EnvironmentFactory;
+import org.jbpm.api.job.Job;
+import org.jbpm.pvm.internal.cmd.ExecuteJobCmd;
+import org.jbpm.pvm.internal.tx.StandardTransaction;
+import org.jbpm.test.JbpmTestCase;
+
+
+/**
+ * Class to test different approaches to the concurrency problem.
+ * 
+ * Doesnt work anymore, but dont delete yet, I need some stuff in here for later!
+ * 
+ * @author Joram Barrez
+ */
+public class OptimisticLockTestGround extends JbpmTestCase {
+
+  private EnvironmentFactory environmentFactory;
+
+  protected void setUp() throws Exception {
+    super.setUp();
+    this.environmentFactory = (EnvironmentFactory) processEngine; // Better way to do this?
+  }
+  
+
+  public void testMe() throws Exception {
+    deployJpdlXmlString(
+            "<process name='asyncFork'>" +
+            "  <start>" +
+            "    <transition to='theFork' />" +
+            "  </start>" +
+            "  <fork name='theFork'>" +
+            "    <on event='end' continue='async' />" +
+            "    <transition to='pathA' />" +
+            "    <transition to='pathB' />" +
+            "  </fork>" +
+            "  <custom name='pathA' class='org.jbpm.test.concurrent.PassThroughActivity' >" +
+            "    <transition to='theJoin' />" +
+            "  </custom>" + 
+            "  <custom name='pathB' class='org.jbpm.test.concurrent.PassThroughActivity' >" +
+            "    <transition to='theJoin' />" +
+            "  </custom>" + 
+            "  <join name='theJoin' lockmode='none'>" +
+            "    <transition to='end' />" +
+            "  </join>" + 
+            "  <end name='end' />" +
+            "</process>"
+          );
+    
+    ProcessInstance processInstance = executionService.startProcessInstanceByKey("asyncFork");
+    final List<Job> jobs = managementService.createJobQuery().processInstanceId(processInstance.getId()).list();
+    assertEquals(2, jobs.size()); 
+    
+    JobExecutorEmulator jobExecutorEmulator1 = new JobExecutorEmulator(jobs.get(0));
+    jobExecutorEmulator1.start();
+    
+    JobExecutorEmulator jobExecutorEmulator2 = new JobExecutorEmulator(jobs.get(1));
+    jobExecutorEmulator2.start();
+    
+    // TODO check if transitions are marked for rollback -> exception happened
+    
+    jobExecutorEmulator1.join();
+    if (jobExecutorEmulator1.getException() != null) {
+      fail("Error while executing job: " + jobExecutorEmulator1.getException().getMessage());
+    }
+    
+    jobExecutorEmulator2.join();
+    if (jobExecutorEmulator2.getException() != null) {
+      fail("Error while executing job: " + jobExecutorEmulator2.getException().getMessage());
+    }
+    
+  }
+  
+  public void testMeToo() throws Exception {
+    
+    semaphore = new Semaphore(0);
+    
+    deployJpdlXmlString(
+            "<process name='timer_vs_signal'>" +
+            "  <start>" +
+            "    <transition to='wait' />" +
+            "  </start>" +
+            "  <state name='wait'>" +
+            "    <transition name='timeout' to='end'>" +
+            "      <timer duedate='1 second' />" +
+            "    </transition>" +
+            "    <transition to='end' name='go on' />" +
+            "  </state>" +
+            "  <end name='end' />" +
+            "</process>"
+          );
+    
+    ProcessInstance processInstance = executionService.startProcessInstanceByKey("timer_vs_signal");
+    final List<Job> jobs = managementService.createJobQuery().processInstanceId(processInstance.getId()).list();
+    assertEquals(1, jobs.size()); 
+    
+    JobExecutorEmulator jobExecutorEmulator1 = new JobExecutorEmulator(jobs.get(0));
+    jobExecutorEmulator1.start();
+   
+    while (!semaphore.hasQueuedThreads()) {
+      synchronized (this) {
+        System.out.println("------------------> waiting ...");
+        wait(20L);
+      }
+    }
+    
+    // cause conflict
+    System.out.println("---------------------------> Causing MayHem");
+    
+    Execution executionAtState = processInstance.findActiveExecutionIn("wait");
+    assertNotNull(executionAtState);
+    executionService.signalExecutionById(executionAtState.getId(), "go on");
+    semaphore.release();
+    System.out.println("----------------------------> Released semaphore");
+    
+    // TODO check if transitions are marked for rollback -> exception happened
+    
+    jobExecutorEmulator1.join();
+    if (jobExecutorEmulator1.getException() != null) {
+      fail("Error while executing job: " + jobExecutorEmulator1.getException().getMessage());
+    }
+    
+  }
+  
+  // Todo refactor
+  private static Semaphore semaphore = new Semaphore(1); // binary semaphore
+  
+  
+  private class JobExecutorEmulator extends Thread {
+    
+    private Long jobId;
+    
+    private Exception exception;
+    
+    public JobExecutorEmulator(Job job) {
+      this.jobId = job.getDbid();
+    }
+    
+    public void run() {
+      
+      Environment environment = environmentFactory.openEnvironment();
+      StandardTransaction standardTransaction = environment.get(StandardTransaction.class);
+      standardTransaction.begin();
+
+      try {
+        
+        System.out.println(Thread.currentThread().getName() + "----------------------------------------> executing job " + jobId);
+        ExecuteJobCmd executeJobCmd = new ExecuteJobCmd(jobId);
+        executeJobCmd.execute(environment);
+        
+        System.out.println(Thread.currentThread().getName() +"-------------------------------------------------------> DONE EXECUTING JOB " + jobId);
+        
+      } catch (Exception e) {
+        standardTransaction.setRollbackOnly();
+        this.exception = e;
+        
+        System.out.println(Thread.currentThread().getName() +" -----------------------------------------------------> IM A FAILURE");
+      } finally {
+        
+        
+        // error: both threads entering at the same time!
+        /*
+        boolean acquired = false;
+        System.out.println(Thread.currentThread().getName() + "-------------------------------------------------> BEFORE SYNC BLOCK");
+        synchronized (semaphore) {
+          acquired = semaphore.tryAcquire();
+        }
+        System.out.println(Thread.currentThread().getName() + "-------------------------------------------------> AFTER SYNC BLOCK");
+        if (acquired) {
+          
+          try {
+            System.out.println(Thread.currentThread().getName() + "-------------------------------------------------> ACQUIRING");
+            synchronized (semaphore) {
+              semaphore.wait();
+            }
+            System.out.println(Thread.currentThread().getName() + "-------------------------------------------------> FREED FROM ACQUIRED");
+          } catch (InterruptedException e) {
+            e.printStackTrace();
+          }
+        }
+        */
+        
+        
+        if (!semaphore.hasQueuedThreads()) {
+          try {
+            System.out.println(Thread.currentThread().getName() + "-------------------------------------------------> ACQUIRING");
+            semaphore.acquire();
+            System.out.println(Thread.currentThread().getName() + "-------------------------------------------------> FREED FROM ACQUIRED");
+          } catch (InterruptedException e) {
+            e.printStackTrace();
+          }
+        }
+        
+        
+        
+        if (standardTransaction.isRollbackOnly()) {
+          exception = new Exception("Transaction was rollbacked");
+        }
+        
+        System.out.println(Thread.currentThread().getName() + "-------------------------------------------------> COMPLETING ");
+        standardTransaction.complete();
+        
+        System.out.println(Thread.currentThread().getName() + "------------------------------------------------------> RELEASING");
+        
+        /*if (!acquired) {
+          semaphore.release();
+          synchronized (semaphore) {
+            semaphore.notify();
+          }
+        }*/
+        
+      }
+      environment.close();
+      System.out.println(Thread.currentThread().getName() + " has finished");
+    }
+
+    
+    public Exception getException() {
+      return exception;
+    }
+
+
+  }
+  
+}

Added: jbpm4/trunk/modules/test-concurrent/src/test/java/org/jbpm/test/concurrent/PassThroughActivity.java
===================================================================
--- jbpm4/trunk/modules/test-concurrent/src/test/java/org/jbpm/test/concurrent/PassThroughActivity.java	                        (rev 0)
+++ jbpm4/trunk/modules/test-concurrent/src/test/java/org/jbpm/test/concurrent/PassThroughActivity.java	2009-06-17 08:57:15 UTC (rev 5049)
@@ -0,0 +1,49 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+/**
+ * 
+ */
+package org.jbpm.test.concurrent;
+
+import java.util.Map;
+
+import org.jbpm.api.activity.ActivityExecution;
+import org.jbpm.api.activity.ExternalActivityBehaviour;
+
+
+/**
+ * @author Joram Barrez
+ */
+public class PassThroughActivity implements ExternalActivityBehaviour {
+
+  private static final long serialVersionUID = 1L;
+
+  public void signal(ActivityExecution execution, String signalName, Map<String, ? > parameters) throws Exception {
+    execution.take(signalName);
+  }
+
+  public void execute(ActivityExecution execution) throws Exception {
+    execution.takeDefaultTransition();
+  }
+  
+
+}

Added: jbpm4/trunk/modules/test-concurrent/src/test/java/org/jbpm/test/concurrent/TimerVsSignalConcurrencyTest.java
===================================================================
--- jbpm4/trunk/modules/test-concurrent/src/test/java/org/jbpm/test/concurrent/TimerVsSignalConcurrencyTest.java	                        (rev 0)
+++ jbpm4/trunk/modules/test-concurrent/src/test/java/org/jbpm/test/concurrent/TimerVsSignalConcurrencyTest.java	2009-06-17 08:57:15 UTC (rev 5049)
@@ -0,0 +1,117 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+/**
+ * 
+ */
+package org.jbpm.test.concurrent;
+
+import java.util.List;
+import java.util.concurrent.CyclicBarrier;
+
+import org.jbpm.api.Execution;
+import org.jbpm.api.ProcessInstance;
+import org.jbpm.api.env.EnvironmentFactory;
+import org.jbpm.api.job.Job;
+import org.jbpm.test.JbpmTestCase;
+
+
+/**
+ * @author Joram Barrez
+ */
+public class TimerVsSignalConcurrencyTest extends ConcurrentJbpmTestCase {
+  
+  public void testStaleObjectExceptionThrown() throws Exception {
+    
+    deployJpdlXmlString(
+            "<process name='timer_vs_signal'>" +
+            "  <start>" +
+            "    <transition to='wait' />" +
+            "  </start>" +
+            "  <state name='wait'>" +
+            "    <transition name='timeout' to='end'>" +
+            "      <timer duedate='1 second' />" +
+            "    </transition>" +
+            "    <transition to='end' name='go on' />" +
+            "  </state>" +
+            "  <end name='end' />" +
+            "</process>"
+          );
+    
+    ProcessInstance processInstance = executionService.startProcessInstanceByKey("timer_vs_signal");
+    final List<Job> jobs = managementService.createJobQuery().processInstanceId(processInstance.getId()).list();
+    assertEquals(1, jobs.size());
+
+    JobExecutorEmulator jobExecutorEmulator = new JobExecutorEmulator(environmentFactory, jobs.get(0));
+    jobExecutorEmulator.synchroniseAfterJobExecution(Thread.currentThread().getName());
+    jobExecutorEmulator.start();
+
+    jobExecutorEmulator.waitUntilJobExecuted(true); // transaction will be stalled
+    
+    // Cause conflicting transaction
+    final Execution executionAtState = processInstance.findActiveExecutionIn("wait");
+    assertNotNull(executionAtState);
+    OffloadThread signalThread = new OffloadThread(new ThreadCallback() {
+      public void executeInThread() {
+        executionService.signalExecutionById(executionAtState.getId(), "go on");
+      }
+    });
+    signalThread.start();
+    
+    /*
+    // Checking current stacktrace of thread
+    int i = 1;
+    while (i == 1) {
+      System.out.println("-----------> STATE = " + temp.getState());
+      StackTraceElement[] stack = temp.getStackTrace();
+      for (StackTraceElement e : stack) {
+        System.out.println("-----------> " + e);
+      }
+      
+      synchronized (this) {
+        try {
+          wait(1000L);
+        } catch (InterruptedException e) {
+          // TODO Auto-generated catch block
+          e.printStackTrace();
+        }
+      }
+    }
+    */
+    
+    // Best effort: wait 1 sec and see if the staleObjectException has been caused
+    synchronized (this) {
+      wait(1000L);
+    }
+    
+    jobExecutorEmulator.goOn();
+    jobExecutorEmulator.join();
+
+    
+    if (jobExecutorEmulator.getException() != null) {
+      fail("Error while executing job: " + jobExecutorEmulator.getException().getMessage());
+    } if (signalThread.getException() != null) {
+      fail("Error while executing signal " + signalThread.getException().getMessage());
+    }
+    
+  }
+
+}

Added: jbpm4/trunk/modules/test-concurrent/src/test/resources/jbpm.cfg.xml
===================================================================
--- jbpm4/trunk/modules/test-concurrent/src/test/resources/jbpm.cfg.xml	                        (rev 0)
+++ jbpm4/trunk/modules/test-concurrent/src/test/resources/jbpm.cfg.xml	2009-06-17 08:57:15 UTC (rev 5049)
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<jbpm-configuration>
+
+  <import resource="jbpm.default.cfg.xml" />
+  <import resource="jbpm.jpdl.cfg.xml" />
+  <import resource="jbpm.tx.hibernate.cfg.xml" />
+
+	<!--
+		In the concurrency tests, we'll emulate the job executor to have full
+		control on when syncing occurs 
+		
+		<import resource="jbpm.jobexecutor.cfg.xml" />
+	-->
+
+</jbpm-configuration>

Added: jbpm4/trunk/modules/test-concurrent/src/test/resources/jbpm.hibernate.cfg.xml
===================================================================
--- jbpm4/trunk/modules/test-concurrent/src/test/resources/jbpm.hibernate.cfg.xml	                        (rev 0)
+++ jbpm4/trunk/modules/test-concurrent/src/test/resources/jbpm.hibernate.cfg.xml	2009-06-17 08:57:15 UTC (rev 5049)
@@ -0,0 +1,46 @@
+<?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>
+
+	<!--
+		<property name="hibernate.dialect">org.hibernate.dialect.HSQLDialect</property>
+		<property name="hibernate.connection.driver_class">org.hsqldb.jdbcDriver</property>
+		<property name="hibernate.connection.url">jdbc:hsqldb:mem:.</property>
+		<property name="hibernate.connection.username">sa</property> <property
+		name="hibernate.connection.password"></property>
+	-->
+
+	<!-- H2 config -->
+	<property name="hibernate.connection.driver_class">org.h2.Driver</property>
+	<property name="hibernate.connection.url">jdbc:h2:mem:.;MVCC=TRUE</property>
+	<property name="hibernate.connection.username">sa</property>
+	<property name="hibernate.connection.password">sa</property>
+	<property name="hibernate.default_schema">PUBLIC</property>
+	<property name="hibernate.dialect">org.hibernate.dialect.H2Dialect</property>
+
+	
+	<!-- POSTGRES config 
+	<property name="hibernate.connection.driver_class">org.h2.Driver</property>
+	<property name="hibernate.connection.url">jdbc:postgresql://localhost:5432/jbpm</property>
+	<property name="hibernate.connection.username">postgres</property>
+	<property name="hibernate.connection.password">postgres</property>
+	<property name="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</property> 
+	-->                                          
+     
+    <property name="hibernate.hbm2ddl.auto">create-drop</property>
+	<property name="hibernate.format_sql">true</property>
+
+	<mapping resource="jbpm.repository.hbm.xml" />
+	<mapping resource="jbpm.execution.hbm.xml" />
+	<mapping resource="jbpm.history.hbm.xml" />
+	<mapping resource="jbpm.task.hbm.xml" />
+	<mapping resource="jbpm.jpdl.hbm.xml" />
+	<mapping resource="jbpm.identity.hbm.xml" />
+     
+  </session-factory>
+</hibernate-configuration>

Added: jbpm4/trunk/modules/test-concurrent/src/test/resources/logging.properties
===================================================================
--- jbpm4/trunk/modules/test-concurrent/src/test/resources/logging.properties	                        (rev 0)
+++ jbpm4/trunk/modules/test-concurrent/src/test/resources/logging.properties	2009-06-17 08:57:15 UTC (rev 5049)
@@ -0,0 +1,18 @@
+handlers= java.util.logging.ConsoleHandler
+redirect.commons.logging = enabled
+
+java.util.logging.ConsoleHandler.level = FINEST
+java.util.logging.ConsoleHandler.formatter = org.jbpm.internal.log.LogFormatter
+
+org.jbpm.level=FINE
+# org.jbpm.pvm.internal.tx.level=FINE
+# org.jbpm.pvm.internal.wire.level=FINE
+# org.jbpm.pvm.internal.util.level=FINE
+
+org.hibernate.level=INFO
+org.hibernate.cfg.SettingsFactory.level=SEVERE
+org.hibernate.cfg.HbmBinder.level=SEVERE
+#org.hibernate.SQL.level=FINEST
+#org.hibernate.type.level=FINEST
+#org.hibernate.tool.hbm2ddl.SchemaExport.level=FINEST
+org.hibernate.transaction.level=FINEST
\ No newline at end of file




More information about the jbpm-commits mailing list