[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