JBoss JBPM SVN: r5223 - in jbpm3/branches/jbpm-3.2-soa/modules/core/src: main/java/org/jbpm/job/executor and 1 other directories.
by do-not-reply@jboss.org
Author: alex.guizar(a)jboss.com
Date: 2009-07-04 09:41:56 -0400 (Sat, 04 Jul 2009)
New Revision: 5223
Modified:
jbpm3/branches/jbpm-3.2-soa/modules/core/src/main/java/org/jbpm/db/JobSession.java
jbpm3/branches/jbpm-3.2-soa/modules/core/src/main/java/org/jbpm/job/executor/JobExecutorThread.java
jbpm3/branches/jbpm-3.2-soa/modules/core/src/main/java/org/jbpm/job/executor/LockMonitorThread.java
jbpm3/branches/jbpm-3.2-soa/modules/core/src/test/java/org/jbpm/jbpm2375/JBPM2375Test.java
Log:
[JBPM-2375] prevent job executor threads from committing after an Error is thrown
Modified: jbpm3/branches/jbpm-3.2-soa/modules/core/src/main/java/org/jbpm/db/JobSession.java
===================================================================
--- jbpm3/branches/jbpm-3.2-soa/modules/core/src/main/java/org/jbpm/db/JobSession.java 2009-07-04 11:53:02 UTC (rev 5222)
+++ jbpm3/branches/jbpm-3.2-soa/modules/core/src/main/java/org/jbpm/db/JobSession.java 2009-07-04 13:41:56 UTC (rev 5223)
@@ -26,8 +26,6 @@
import java.util.Iterator;
import java.util.List;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.Query;
@@ -119,7 +117,6 @@
public void deleteJob(Job job) {
try {
session.delete(job);
- log.debug("deleted " + job);
}
catch (HibernateException e) {
throw new JbpmPersistenceException("could not delete " + job, e);
@@ -189,19 +186,16 @@
public void deleteTimersByName(String name, Token token) {
try {
// delete unowned timers
- int entityCount =
- session.getNamedQuery("JobSession.deleteTimersByName")
- .setString("name", name)
- .setParameter("token", token)
- .executeUpdate();
- log.debug("deleted " + entityCount + " timers by name '" + name + "' for " + token);
+ session.getNamedQuery("JobSession.deleteTimersByName")
+ .setString("name", name)
+ .setParameter("token", token)
+ .executeUpdate();
// prevent further repetitions
- List timers =
- session.getNamedQuery("JobSession.findRepeatingTimersByName")
- .setString("name", name)
- .setParameter("token", token)
- .list();
+ List timers = session.getNamedQuery("JobSession.findRepeatingTimersByName")
+ .setString("name", name)
+ .setParameter("token", token)
+ .list();
preventFurtherRepetitions(timers);
}
catch (HibernateException e) {
@@ -213,27 +207,23 @@
}
public int countDeletableJobsForProcessInstance(ProcessInstance processInstance) {
- Number jobCount =
- (Number) session.getNamedQuery("JobSession.countDeletableJobsForProcessInstance")
- .setParameter("processInstance", processInstance)
- .uniqueResult();
+ Number jobCount = (Number) session.getNamedQuery("JobSession.countDeletableJobsForProcessInstance")
+ .setParameter("processInstance", processInstance)
+ .uniqueResult();
return jobCount.intValue();
}
public void deleteJobsForProcessInstance(ProcessInstance processInstance) {
try {
// delete unowned node-execute-jobs and timers
- int entityCount =
- session.getNamedQuery("JobSession.deleteJobsForProcessInstance")
- .setParameter("processInstance", processInstance)
- .executeUpdate();
- log.debug("deleted " + entityCount + " jobs for " + processInstance);
+ session.getNamedQuery("JobSession.deleteJobsForProcessInstance")
+ .setParameter("processInstance", processInstance)
+ .executeUpdate();
// prevent further repetitions
- List timers =
- session.getNamedQuery("JobSession.findRepeatingTimersForProcessInstance")
- .setParameter("processInstance", processInstance)
- .list();
+ List timers = session.getNamedQuery("JobSession.findRepeatingTimersForProcessInstance")
+ .setParameter("processInstance", processInstance)
+ .list();
preventFurtherRepetitions(timers);
}
catch (HibernateException e) {
@@ -247,7 +237,6 @@
Timer timer = (Timer) i.next();
timer.setRepeat(null);
}
- log.debug("prevented further repetitions of " + timers);
}
}
@@ -262,5 +251,4 @@
}
}
- private static Log log = LogFactory.getLog(JobSession.class);
}
Modified: jbpm3/branches/jbpm-3.2-soa/modules/core/src/main/java/org/jbpm/job/executor/JobExecutorThread.java
===================================================================
--- jbpm3/branches/jbpm-3.2-soa/modules/core/src/main/java/org/jbpm/job/executor/JobExecutorThread.java 2009-07-04 11:53:02 UTC (rev 5222)
+++ jbpm3/branches/jbpm-3.2-soa/modules/core/src/main/java/org/jbpm/job/executor/JobExecutorThread.java 2009-07-04 13:41:56 UTC (rev 5223)
@@ -27,7 +27,6 @@
final int maxIdleInterval;
final long maxLockTime;
- int currentIdleInterval;
volatile boolean isActive = true;
public JobExecutorThread(String name, JobExecutor jobExecutor) {
@@ -55,18 +54,16 @@
}
public void run() {
- currentIdleInterval = idleInterval;
+ int currentIdleInterval = idleInterval;
while (isActive) {
try {
Collection acquiredJobs = acquireJobs();
- if (!acquiredJobs.isEmpty()) {
- for (Iterator i = acquiredJobs.iterator(); i.hasNext() && isActive;) {
- Job job = (Job) i.next();
- executeJob(job);
- }
+ for (Iterator i = acquiredJobs.iterator(); i.hasNext() && isActive;) {
+ Job job = (Job) i.next();
+ executeJob(job);
}
if (isActive) {
- long waitPeriod = getWaitPeriod();
+ long waitPeriod = getWaitPeriod(currentIdleInterval);
if (waitPeriod > 0) {
synchronized (jobExecutor) {
jobExecutor.wait(waitPeriod);
@@ -77,26 +74,26 @@
currentIdleInterval = idleInterval;
}
catch (RuntimeException e) {
- log.error("exception in job executor thread. waiting " +
- currentIdleInterval +
- " milliseconds", e);
- try {
- synchronized (jobExecutor) {
- jobExecutor.wait(currentIdleInterval);
+ if (isActive) {
+ log.error("exception in " + getName() + ", waiting " + currentIdleInterval + " ms", e);
+ try {
+ synchronized (jobExecutor) {
+ jobExecutor.wait(currentIdleInterval);
+ }
}
+ catch (InterruptedException ie) {
+ log.debug("delay after exception got interrupted", ie);
+ }
+ // after an exception, the current idle interval is doubled to prevent
+ // continuous exception generation when e.g. the db is unreachable
+ currentIdleInterval <<= 1;
+ if (currentIdleInterval > maxIdleInterval || currentIdleInterval < 0) {
+ currentIdleInterval = maxIdleInterval;
+ }
}
- catch (InterruptedException ie) {
- log.debug("delay after exception got interrupted", ie);
- }
- // after an exception, the current idle interval is doubled to prevent
- // continuous exception generation when e.g. the db is unreachable
- currentIdleInterval <<= 1;
- if (currentIdleInterval > maxIdleInterval || currentIdleInterval < 0) {
- currentIdleInterval = maxIdleInterval;
- }
}
catch (InterruptedException e) {
- log.info("job executor thread '" + getName() + "' got interrupted");
+ log.info(getName() + " got interrupted");
}
}
log.info(getName() + " leaves cyberspace");
@@ -104,28 +101,25 @@
protected Collection acquireJobs() {
Collection acquiredJobs;
+
synchronized (jobExecutor) {
- log.debug("acquiring jobs for execution...");
List jobsToLock = Collections.EMPTY_LIST;
+
JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
try {
JobSession jobSession = jbpmContext.getJobSession();
+
String lockOwner = getName();
- log.debug("querying for acquirable job...");
Job job = jobSession.getFirstAcquirableJob(lockOwner);
if (job != null) {
if (job.isExclusive()) {
- log.debug("obtained exclusive " + job);
ProcessInstance processInstance = job.getProcessInstance();
- log.debug("finding other exclusive jobs for " + processInstance);
+ log.debug("finding exclusive jobs for " + processInstance);
jobsToLock = jobSession.findExclusiveJobs(lockOwner, processInstance);
- log.debug("trying to obtain exclusive locks on " +
- jobsToLock +
- " for " +
- processInstance);
+ log.debug("acquiring " + jobsToLock + " for " + processInstance);
}
else {
- log.debug("trying to obtain lock on " + job);
+ log.debug("acquiring " + job);
jobsToLock = Collections.singletonList(job);
}
@@ -136,14 +130,15 @@
job.setLockTime(lockTime);
}
}
- else {
- log.debug("no acquirable jobs in job table");
- }
}
catch (RuntimeException e) {
jbpmContext.setRollbackOnly();
throw e;
}
+ catch (Error e) {
+ jbpmContext.setRollbackOnly();
+ throw e;
+ }
finally {
try {
jbpmContext.close();
@@ -153,8 +148,8 @@
catch (RuntimeException e) {
if (!DbPersistenceService.isLockingException(e)) throw e;
// if this is a locking exception, keep it quiet
- StaleObjectLogConfigurer.getStaleObjectExceptionsLog().error(
- "failed to acquire lock on jobs " + jobsToLock);
+ StaleObjectLogConfigurer.getStaleObjectExceptionsLog()
+ .error("failed to acquire lock on jobs " + jobsToLock);
acquiredJobs = Collections.EMPTY_LIST;
}
}
@@ -191,6 +186,10 @@
jbpmContext.setRollbackOnly();
}
}
+ catch (Error e) {
+ jbpmContext.setRollbackOnly();
+ throw e;
+ }
// if this job is locked too long
long totalLockTimeInMillis = System.currentTimeMillis() - job.getLockTime().getTime();
@@ -205,29 +204,49 @@
catch (RuntimeException e) {
if (!DbPersistenceService.isLockingException(e)) throw e;
// if this is a locking exception, keep it quiet
- StaleObjectLogConfigurer.getStaleObjectExceptionsLog().error(
- "failed to complete job " + job);
+ StaleObjectLogConfigurer.getStaleObjectExceptionsLog().error("failed to complete job " +
+ job);
}
}
}
+ protected long getWaitPeriod(int currentIdleInterval) {
+ long waitPeriod = currentIdleInterval;
+
+ Date nextDueDate = getNextDueDate();
+ if (nextDueDate != null) {
+ long nextDueTime = nextDueDate.getTime();
+ long currentTime = System.currentTimeMillis();
+
+ if (nextDueTime < currentTime + currentIdleInterval) {
+ waitPeriod = nextDueTime - currentTime;
+ if (waitPeriod < 0) waitPeriod = 0;
+ }
+ }
+ return waitPeriod;
+ }
+
protected Date getNextDueDate() {
Date nextDueDate = null;
- String threadName = getName();
+ String lockOwner = getName();
JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
try {
JobSession jobSession = jbpmContext.getJobSession();
Collection jobIdsToIgnore = jobExecutor.getMonitoredJobIds();
- Job job = jobSession.getFirstDueJob(threadName, jobIdsToIgnore);
+ Job job = jobSession.getFirstDueJob(lockOwner, jobIdsToIgnore);
if (job != null) {
nextDueDate = job.getDueDate();
- jobExecutor.addMonitoredJobId(threadName, job.getId());
+ jobExecutor.addMonitoredJobId(lockOwner, job.getId());
}
}
catch (RuntimeException e) {
jbpmContext.setRollbackOnly();
throw e;
}
+ catch (Error e) {
+ jbpmContext.setRollbackOnly();
+ throw e;
+ }
finally {
try {
jbpmContext.close();
@@ -235,30 +254,14 @@
catch (RuntimeException e) {
if (!DbPersistenceService.isLockingException(e)) throw e;
// if this is a locking exception, keep it quiet
- StaleObjectLogConfigurer.getStaleObjectExceptionsLog().error(
- "failed to determine next due date for job executor thread " + threadName);
+ StaleObjectLogConfigurer.getStaleObjectExceptionsLog()
+ .error("failed to determine next due date for job executor thread " + lockOwner);
nextDueDate = null;
}
}
return nextDueDate;
}
- protected long getWaitPeriod() {
- long interval = currentIdleInterval;
- Date nextDueDate = getNextDueDate();
- if (nextDueDate != null) {
- long currentTime = System.currentTimeMillis();
- long nextDueTime = nextDueDate.getTime();
- if (nextDueTime < currentTime + currentIdleInterval) {
- interval = nextDueTime - currentTime;
- }
- }
- if (interval < 0) {
- interval = 0;
- }
- return interval;
- }
-
/**
* @deprecated As of jBPM 3.2.3, replaced by {@link #deactivate()}
*/
Modified: jbpm3/branches/jbpm-3.2-soa/modules/core/src/main/java/org/jbpm/job/executor/LockMonitorThread.java
===================================================================
--- jbpm3/branches/jbpm-3.2-soa/modules/core/src/main/java/org/jbpm/job/executor/LockMonitorThread.java 2009-07-04 11:53:02 UTC (rev 5222)
+++ jbpm3/branches/jbpm-3.2-soa/modules/core/src/main/java/org/jbpm/job/executor/LockMonitorThread.java 2009-07-04 13:41:56 UTC (rev 5223)
@@ -9,7 +9,6 @@
import org.jbpm.JbpmConfiguration;
import org.jbpm.JbpmContext;
-import org.jbpm.db.JobSession;
import org.jbpm.job.Job;
import org.jbpm.persistence.db.DbPersistenceService;
import org.jbpm.persistence.db.StaleObjectLogConfigurer;
@@ -18,14 +17,13 @@
public static final String DEFAULT_NAME = "LockMonitorThread";
- JbpmConfiguration jbpmConfiguration;
- int lockMonitorInterval;
- int maxLockTime;
- int lockBufferTime;
+ final JbpmConfiguration jbpmConfiguration;
+ final int lockMonitorInterval;
+ final int maxLockTime;
+ final int lockBufferTime;
- int currentLockMonitorInterval;
volatile boolean isActive = true;
-
+
public LockMonitorThread(JobExecutor jobExecutor) {
this(DEFAULT_NAME, jobExecutor);
}
@@ -36,7 +34,7 @@
lockMonitorInterval = jobExecutor.getLockMonitorInterval();
maxLockTime = jobExecutor.getMaxLockTime();
lockBufferTime = jobExecutor.getLockBufferTime();
- }
+ }
/** @deprecated As of jBPM 3.2.6, replaced by {@link #LockMonitorThread(JobExecutor)} */
public LockMonitorThread(JbpmConfiguration jbpmConfiguration, int lockMonitorInterval,
@@ -48,52 +46,36 @@
}
public void run() {
- try {
- while (isActive) {
+ while (isActive) {
+ try {
+ unlockOverdueJobs();
+ jbpmConfiguration.getJobExecutor().ensureThreadsAreActive();
+ }
+ catch (RuntimeException e) {
+ log.error("exception in " + getName(), e);
+ }
+ if (isActive) {
try {
- unlockOverdueJobs();
- jbpmConfiguration.getJobExecutor().ensureThreadsAreActive();
- if (isActive && lockMonitorInterval > 0) {
- sleep(lockMonitorInterval);
- }
+ sleep(lockMonitorInterval);
}
catch (InterruptedException e) {
- log.info("lock monitor thread '" + getName() + "' got interrupted");
+ log.info(getName() + " got interrupted");
}
- catch (Exception e) {
- log.error("exception in lock monitor thread. waiting "
- + lockMonitorInterval
- + " milliseconds", e);
- try {
- sleep(lockMonitorInterval);
- }
- catch (InterruptedException e2) {
- log.debug("delay after exception got interrupted", e2);
- }
- }
}
}
- catch (Exception e) {
- log.error("exception in lock monitor thread", e);
- }
- finally {
- log.info(getName() + " leaves cyberspace");
- }
+ log.info(getName() + " leaves cyberspace");
}
protected void unlockOverdueJobs() {
- List overdueJobs = null;
JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
try {
Date threshold = new Date(System.currentTimeMillis() - maxLockTime - lockBufferTime);
- JobSession jobSession = jbpmContext.getJobSession();
- overdueJobs = jobSession.findJobsWithOverdueLockTime(threshold);
+ List overdueJobs = jbpmContext.getJobSession().findJobsWithOverdueLockTime(threshold);
for (Iterator i = overdueJobs.iterator(); i.hasNext();) {
Job job = (Job) i.next();
- if(log.isDebugEnabled())
- {
- log.debug("unlocking " + job + " owned by thread " + job.getLockOwner());
- }
+ if (log.isDebugEnabled()) {
+ log.debug("unlocking " + job + " owned by " + job.getLockOwner());
+ }
job.setLockOwner(null);
job.setLockTime(null);
}
@@ -102,6 +84,10 @@
jbpmContext.setRollbackOnly();
throw e;
}
+ catch (Error e) {
+ jbpmContext.setRollbackOnly();
+ throw e;
+ }
finally {
try {
jbpmContext.close();
@@ -109,8 +95,8 @@
catch (RuntimeException e) {
if (!DbPersistenceService.isLockingException(e)) throw e;
// if this is a locking exception, keep it quiet
- StaleObjectLogConfigurer.getStaleObjectExceptionsLog().error(
- "could not unlock overdue jobs: " + overdueJobs);
+ StaleObjectLogConfigurer.getStaleObjectExceptionsLog()
+ .error("could not unlock overdue jobs");
}
}
}
Modified: jbpm3/branches/jbpm-3.2-soa/modules/core/src/test/java/org/jbpm/jbpm2375/JBPM2375Test.java
===================================================================
--- jbpm3/branches/jbpm-3.2-soa/modules/core/src/test/java/org/jbpm/jbpm2375/JBPM2375Test.java 2009-07-04 11:53:02 UTC (rev 5222)
+++ jbpm3/branches/jbpm-3.2-soa/modules/core/src/test/java/org/jbpm/jbpm2375/JBPM2375Test.java 2009-07-04 13:41:56 UTC (rev 5223)
@@ -1,14 +1,10 @@
package org.jbpm.jbpm2375;
-import org.jbpm.JbpmConfiguration;
import org.jbpm.db.AbstractDbTestCase;
import org.jbpm.graph.def.ActionHandler;
-import org.jbpm.graph.def.Event;
-import org.jbpm.graph.def.EventCallback;
import org.jbpm.graph.def.ProcessDefinition;
import org.jbpm.graph.exe.ExecutionContext;
import org.jbpm.graph.exe.ProcessInstance;
-import org.jbpm.job.executor.JobExecutor;
/**
* Test if the JobExecutorThread recovers from an Error
@@ -20,102 +16,83 @@
public class JBPM2375Test extends AbstractDbTestCase {
private static final int TEST_TIMEOUT = 10 * 1000;
+ private static boolean throwError;
- private JobExecutor jobExecutor = new JobExecutor();
- private long processDefinitionId;
-
+ private ProcessDefinition processDefinition;
+
// a process definition with two timers moving the token forward
// the second state has an action associated with the node-enter event,
// which can simulate an Error condition by throwing a NoClassDefFoundError
- private static final String PROCESS_DEFINITION = "<process-definition name='jbpm2375-timer-error-test'>"
- + " <event type='process-end'>"
- + " <action expression='#{eventCallback.processEnd}' />"
- + " </event>"
- + " <start-state name='start'>"
- + " <transition to='state1' name='to_state1'/>"
- + " </start-state>"
- + " <state name='state1'>"
- + " <timer name='moveToDefaultEndAfter1second' duedate='1 second' transition='to_state2'/>"
- + " <transition to='state2' name='to_state2'/>"
- + " </state>"
- + " <state name='state2'>"
- + " <timer name='moveToEndAfter1second' duedate='1 second' transition='to_end'/>"
- + " <event type='node-enter'>"
- + " <action name='exceptionTest' class='"
- + TimerExceptionAction.class.getName()
- + "'>"
- + " </action>"
- + " </event>"
- + " <transition to='end' name='to_end'/>"
- + " </state>"
- + " <end-state name='end' />"
- + "</process-definition>";
-
-
+ private static final String PROCESS_DEFINITION = "<process-definition name='jbpm2375-test'>" +
+ " <start-state name='start'>" +
+ " <transition to='state1' name='to_state1'/>" +
+ " </start-state>" +
+ " <state name='state1'>" +
+ " <timer name='moveToDefaultEndAfter1second' duedate='1 second' transition='to_state2'/>" +
+ " <transition to='state2' name='to_state2'/>" +
+ " </state>" +
+ " <state name='state2'>" +
+ " <timer name='moveToEndAfter1second' duedate='1 second' transition='to_end'/>" +
+ " <event type='node-enter'>" +
+ " <action name='exceptionTest' class='" +
+ TimerExceptionAction.class.getName() +
+ "'>" +
+ " </action>" +
+ " </event>" +
+ " <transition to='end' name='to_end'/>" +
+ " </state>" +
+ " <end-state name='end' />" +
+ "</process-definition>";
+
protected void setUp() throws Exception {
super.setUp();
+ jbpmConfiguration.getJobExecutor().setLockMonitorInterval(TEST_TIMEOUT / 2);
- ProcessDefinition processDefinition = ProcessDefinition.parseXmlString(PROCESS_DEFINITION);
+ processDefinition = ProcessDefinition.parseXmlString(PROCESS_DEFINITION);
jbpmContext.deployProcessDefinition(processDefinition);
- newTransaction();
- processDefinitionId = processDefinition.getId();
- getJbpmConfiguration().getJobExecutor().setLockMonitorInterval(TEST_TIMEOUT/2);
- startJobExecutor();
-
-
+ newTransaction();
}
protected void tearDown() throws Exception {
- stopJobExecutor();
+ graphSession.deleteProcessDefinition(processDefinition.getId());
- graphSession.deleteProcessDefinition(processDefinitionId);
-
- EventCallback.clear();
+ jbpmConfiguration.getJobExecutor().setLockMonitorInterval(60000);
super.tearDown();
- }
+ }
// check if the process ends correctly if no Error is thrown
public void testTimerWithoutErrorAction() {
- runTimerErrorAction(Boolean.FALSE);
+ throwError = false;
+ runTimerErrorAction();
}
// check if the process ends correctly if an Error is thrown in the ActionHandler
public void testTimerWithErrorAction() {
- runTimerErrorAction(Boolean.TRUE);
+ throwError = true;
+ runTimerErrorAction();
}
- private void runTimerErrorAction(Boolean withError) {
-
+ private void runTimerErrorAction() {
// kick off process instance
- ProcessDefinition processDefinition = graphSession.loadProcessDefinition(processDefinitionId);
ProcessInstance processInstance = new ProcessInstance(processDefinition);
- processInstance.getContextInstance().setVariable("eventCallback", new EventCallback());
- processInstance.getContextInstance().setVariable("throwError", withError);
processInstance.signal();
jbpmContext.save(processInstance);
- commitAndCloseSession();
- try {
- EventCallback.waitForEvent(Event.EVENTTYPE_PROCESS_END, TEST_TIMEOUT);
+ processJobs(TEST_TIMEOUT);
- waitForJobs(TEST_TIMEOUT);
-
- } finally {
- beginSessionTransaction();
- }
+ processInstance = jbpmContext.loadProcessInstance(processInstance.getId());
+ assert processInstance.hasEnded() : processInstance;
+ }
- }
-
-
public static class TimerExceptionAction implements ActionHandler {
-
private static final long serialVersionUID = 1L;
public void execute(ExecutionContext executionContext) throws Exception {
- Boolean throwError = (Boolean)executionContext.getVariable("throwError");
- if (throwError.booleanValue())
- throw new NoClassDefFoundError("org.jbpm.no.class.Class");
+ if (throwError) {
+ throwError = false;
+ throw new NoClassDefFoundError("org.jbpm.no.such.Class");
+ }
}
}
}
16 years, 10 months
JBoss JBPM SVN: r5222 - in jbpm4/trunk/modules: api/src/main/java/org/jbpm/api/task and 5 other directories.
by do-not-reply@jboss.org
Author: tom.baeyens(a)jboss.com
Date: 2009-07-04 07:53:02 -0400 (Sat, 04 Jul 2009)
New Revision: 5222
Added:
jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/cmd/DeleteTaskCmd.java
jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/history/events/TaskDelete.java
jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/task/OpenTask.java
Removed:
jbpm4/trunk/modules/api/src/main/java/org/jbpm/api/task/OpenTask.java
jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/cmd/CancelTaskCmd.java
jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/history/events/TaskCancel.java
Modified:
jbpm4/trunk/modules/api/src/main/java/org/jbpm/api/TaskService.java
jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/svc/TaskServiceImpl.java
jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/task/TaskHandler.java
jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/task/TaskImpl.java
jbpm4/trunk/modules/test-db/src/test/java/org/jbpm/test/task/TaskHandlerTest.java
Log:
JBPM-2336 fix task delete mismatch
Modified: jbpm4/trunk/modules/api/src/main/java/org/jbpm/api/TaskService.java
===================================================================
--- jbpm4/trunk/modules/api/src/main/java/org/jbpm/api/TaskService.java 2009-07-04 09:39:57 UTC (rev 5221)
+++ jbpm4/trunk/modules/api/src/main/java/org/jbpm/api/TaskService.java 2009-07-04 11:53:02 UTC (rev 5222)
@@ -21,6 +21,7 @@
*/
package org.jbpm.api;
+import org.jbpm.api.history.HistoryActivityInstance;
import org.jbpm.api.model.Comment;
import org.jbpm.api.task.Participation;
import org.jbpm.api.task.Task;
@@ -85,22 +86,17 @@
void completeTask(String taskId, String outcome);
/** Deletes the task without completing it.
- * If this task was created in the context of a process execution, one
- * of three things might happen depending on configurations of the task
- * in the process definition:
- * a) process executions resumes
- * b) whole process execution is cancelled as well.
- * c) exception is thrown */
+ * If this task was created in the context of a process execution,
+ * the execution remains active and the {@link ExecutionService#signalExecutionById(String)}
+ * is to be given explicitly. */
void deleteTask(String taskId);
/** Deletes the task without completing indicating the reason. Example reasons
- * could be: "failed", "error", "exited", "obsolete" or "deleted".
- * If this task was created in the context of a process execution, one
- * of three things might happen depending on configurations of the task
- * in the process definition:
- * a) process executions resumes
- * b) whole process execution is cancelled as well.
- * c) exception is thrown */
+ * could be: "failed", "error", "exited", "obsolete" or "deleted".
+ * The reason ends up as the state in the {@link HistoryActivityInstance}.
+ * If this task was created in the context of a process execution,
+ * the execution remains active and the {@link ExecutionService#signalExecutionById(String)}
+ * is to be given explicitly. */
void deleteTask(String taskId, String reason);
/** add a role to a given task.
Deleted: jbpm4/trunk/modules/api/src/main/java/org/jbpm/api/task/OpenTask.java
===================================================================
--- jbpm4/trunk/modules/api/src/main/java/org/jbpm/api/task/OpenTask.java 2009-07-04 09:39:57 UTC (rev 5221)
+++ jbpm4/trunk/modules/api/src/main/java/org/jbpm/api/task/OpenTask.java 2009-07-04 11:53:02 UTC (rev 5222)
@@ -1,53 +0,0 @@
-/*
- * 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.api.task;
-
-import org.jbpm.api.model.OpenExecution;
-
-
-/**
- * @author Tom Baeyens
- */
-public interface OpenTask extends Task, Assignable {
-
- OpenExecution getExecution();
-
- OpenTask createSubTask();
- OpenTask createSubTask(String name);
-
- /** fires a history event that marks the start of this task. */
- void historyTaskStart();
-
- /** fires a history event that marks the assignment of this task. */
- void historyTaskAssign(String userId);
-
- /** fires a history event that marks the completion of this task. */
- void historyTaskComplete(String outcome);
-
- /** fires a history event that marks the cancellation of this task. */
- void historyTaskCancel(String reason);
-
- boolean isSignalling();
- void setSignalling(boolean isSignalling);
-
- void cancel(String reason);
-}
Deleted: jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/cmd/CancelTaskCmd.java
===================================================================
--- jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/cmd/CancelTaskCmd.java 2009-07-04 09:39:57 UTC (rev 5221)
+++ jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/cmd/CancelTaskCmd.java 2009-07-04 11:53:02 UTC (rev 5222)
@@ -1,59 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source
- * Copyright 2005, JBoss Inc., and individual contributors as indicated
- * by the @authors tag. See the copyright.txt in the distribution for a
- * full listing of individual contributors.
- *
- * This is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- */
-package org.jbpm.pvm.internal.cmd;
-
-import org.jbpm.api.JbpmException;
-import org.jbpm.pvm.internal.env.Environment;
-import org.jbpm.pvm.internal.session.DbSession;
-import org.jbpm.pvm.internal.task.TaskImpl;
-
-/**
- * @author Alejandro Guizar
- */
-public class CancelTaskCmd extends AbstractCommand<Void> {
-
- private static final long serialVersionUID = 1L;
-
- protected String taskId;
- protected String reason;
-
- public CancelTaskCmd(String taskId) {
- this.taskId = taskId;
- }
-
- public CancelTaskCmd(String taskId, String reason) {
- this.taskId = taskId;
- this.reason = reason;
- }
-
- public Void execute(Environment environment) throws Exception {
- DbSession dbSession = environment.get(DbSession.class);
- TaskImpl task = (TaskImpl) dbSession.get(TaskImpl.class, Long.parseLong(taskId));
- if (task!=null) {
- task.cancel(reason);
- dbSession.delete(task);
- } else {
- throw new JbpmException("task "+taskId+" doesn't exist");
- }
- return null;
- }
-}
Copied: jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/cmd/DeleteTaskCmd.java (from rev 5219, jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/cmd/CancelTaskCmd.java)
===================================================================
--- jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/cmd/DeleteTaskCmd.java (rev 0)
+++ jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/cmd/DeleteTaskCmd.java 2009-07-04 11:53:02 UTC (rev 5222)
@@ -0,0 +1,59 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jbpm.pvm.internal.cmd;
+
+import org.jbpm.api.JbpmException;
+import org.jbpm.pvm.internal.env.Environment;
+import org.jbpm.pvm.internal.session.DbSession;
+import org.jbpm.pvm.internal.task.TaskImpl;
+
+/**
+ * @author Alejandro Guizar
+ */
+public class DeleteTaskCmd extends AbstractCommand<Void> {
+
+ private static final long serialVersionUID = 1L;
+
+ protected String taskId;
+ protected String reason;
+
+ public DeleteTaskCmd(String taskId) {
+ this.taskId = taskId;
+ }
+
+ public DeleteTaskCmd(String taskId, String reason) {
+ this.taskId = taskId;
+ this.reason = reason;
+ }
+
+ public Void execute(Environment environment) throws Exception {
+ DbSession dbSession = environment.get(DbSession.class);
+ TaskImpl task = (TaskImpl) dbSession.get(TaskImpl.class, Long.parseLong(taskId));
+ if (task!=null) {
+ task.delete(reason);
+ dbSession.delete(task);
+ } else {
+ throw new JbpmException("task "+taskId+" doesn't exist");
+ }
+ return null;
+ }
+}
Property changes on: jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/cmd/DeleteTaskCmd.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Deleted: jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/history/events/TaskCancel.java
===================================================================
--- jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/history/events/TaskCancel.java 2009-07-04 09:39:57 UTC (rev 5221)
+++ jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/history/events/TaskCancel.java 2009-07-04 11:53:02 UTC (rev 5222)
@@ -1,51 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source
- * Copyright 2005, JBoss Inc., and individual contributors as indicated
- * by the @authors tag. See the copyright.txt in the distribution for a
- * full listing of individual contributors.
- *
- * This is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- */
-package org.jbpm.pvm.internal.history.events;
-
-import org.jbpm.pvm.internal.history.model.HistoryActivityInstanceImpl;
-import org.jbpm.pvm.internal.history.model.HistoryTaskInstanceImpl;
-
-
-/**
- * @author Tom Baeyens
- */
-public class TaskCancel extends ActivityEnd {
-
- private static final long serialVersionUID = 1L;
-
- protected String reason;
-
- public TaskCancel(String reason) {
- this.reason = reason;
- }
-
- protected void updateHistoryActivityInstance(HistoryActivityInstanceImpl historyActivityInstance) {
- super.updateHistoryActivityInstance(historyActivityInstance);
-
- HistoryTaskInstanceImpl historyTaskInstance = (HistoryTaskInstanceImpl) historyActivityInstance;
- historyTaskInstance.setState(reason);
- }
-
- protected Class<? extends HistoryActivityInstanceImpl> getHistoryActivityInstanceClass() {
- return HistoryTaskInstanceImpl.class;
- }
-}
Copied: jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/history/events/TaskDelete.java (from rev 5219, jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/history/events/TaskCancel.java)
===================================================================
--- jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/history/events/TaskDelete.java (rev 0)
+++ jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/history/events/TaskDelete.java 2009-07-04 11:53:02 UTC (rev 5222)
@@ -0,0 +1,51 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jbpm.pvm.internal.history.events;
+
+import org.jbpm.pvm.internal.history.model.HistoryActivityInstanceImpl;
+import org.jbpm.pvm.internal.history.model.HistoryTaskInstanceImpl;
+
+
+/**
+ * @author Tom Baeyens
+ */
+public class TaskDelete extends ActivityEnd {
+
+ private static final long serialVersionUID = 1L;
+
+ protected String reason;
+
+ public TaskDelete(String reason) {
+ this.reason = reason;
+ }
+
+ protected void updateHistoryActivityInstance(HistoryActivityInstanceImpl historyActivityInstance) {
+ super.updateHistoryActivityInstance(historyActivityInstance);
+
+ HistoryTaskInstanceImpl historyTaskInstance = (HistoryTaskInstanceImpl) historyActivityInstance;
+ historyTaskInstance.setState(reason);
+ }
+
+ protected Class<? extends HistoryActivityInstanceImpl> getHistoryActivityInstanceClass() {
+ return HistoryTaskInstanceImpl.class;
+ }
+}
Property changes on: jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/history/events/TaskDelete.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Modified: jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/svc/TaskServiceImpl.java
===================================================================
--- jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/svc/TaskServiceImpl.java 2009-07-04 09:39:57 UTC (rev 5221)
+++ jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/svc/TaskServiceImpl.java 2009-07-04 11:53:02 UTC (rev 5222)
@@ -35,7 +35,7 @@
import org.jbpm.pvm.internal.cmd.AddReplyCommentCmd;
import org.jbpm.pvm.internal.cmd.AddTaskCommentCmd;
import org.jbpm.pvm.internal.cmd.AssignTaskCmd;
-import org.jbpm.pvm.internal.cmd.CancelTaskCmd;
+import org.jbpm.pvm.internal.cmd.DeleteTaskCmd;
import org.jbpm.pvm.internal.cmd.CompleteTaskCmd;
import org.jbpm.pvm.internal.cmd.CreateTaskQueryCmd;
import org.jbpm.pvm.internal.cmd.DeleteCommentCmd;
@@ -72,11 +72,11 @@
}
public void deleteTask(String taskId) {
- commandService.execute(new CancelTaskCmd(taskId));
+ commandService.execute(new DeleteTaskCmd(taskId));
}
public void deleteTask(String taskId, String reason) {
- commandService.execute(new CancelTaskCmd(taskId, reason));
+ commandService.execute(new DeleteTaskCmd(taskId, reason));
}
public void completeTask(String taskId) {
Copied: jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/task/OpenTask.java (from rev 5219, jbpm4/trunk/modules/api/src/main/java/org/jbpm/api/task/OpenTask.java)
===================================================================
--- jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/task/OpenTask.java (rev 0)
+++ jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/task/OpenTask.java 2009-07-04 11:53:02 UTC (rev 5222)
@@ -0,0 +1,43 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jbpm.pvm.internal.task;
+
+import org.jbpm.api.model.OpenExecution;
+import org.jbpm.api.task.Assignable;
+import org.jbpm.api.task.Task;
+
+
+/**
+ * @author Tom Baeyens
+ */
+public interface OpenTask extends Task, Assignable {
+
+ OpenExecution getExecution();
+
+ OpenTask createSubTask();
+ OpenTask createSubTask(String name);
+
+ boolean isSignalling();
+ void setSignalling(boolean isSignalling);
+
+ void delete(String reason);
+}
Property changes on: jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/task/OpenTask.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Modified: jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/task/TaskHandler.java
===================================================================
--- jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/task/TaskHandler.java 2009-07-04 09:39:57 UTC (rev 5221)
+++ jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/task/TaskHandler.java 2009-07-04 11:53:02 UTC (rev 5222)
@@ -23,7 +23,6 @@
import java.io.Serializable;
-import org.jbpm.api.task.OpenTask;
import org.jbpm.pvm.internal.client.ClientExecution;
/** for advanced task customization.
@@ -40,7 +39,7 @@
* to the task definition. This method allows to
* create subtasks.
* @return indicates if the process execution should wait. */
- public boolean executionCreateTask(OpenTask task) {
+ public boolean executionCreateTask(TaskImpl task) {
task.historyTaskStart();
return true;
}
@@ -48,24 +47,30 @@
/** called when the related execution gets a
* signal. this method must either
* {@link OpenTask#setSignalling(boolean) remove signalling} from this task
- * or {@link OpenTask#cancel(String) cancel} it. */
- public void executionSignal(OpenTask task) {
+ * or {@link OpenTask#delete(String) cancel} it. */
+ public void executionSignal(TaskImpl task) {
task.setSignalling(false);
}
/** called when the given task is assigned to an actor. */
- public void taskAssign(OpenTask task, String userId) {
+ public void taskAssign(TaskImpl task, String userId) {
task.historyTaskAssign(userId);
}
/** called when the given task is cancelled. */
- public void taskCancel(OpenTask task, String reason) {
- task.historyTaskCancel(reason);
+ public void taskDelete(TaskImpl task, String reason) {
+ task.historyTaskDelete(reason);
+// TODO if task is deleted, the related execution should be
+// suspended. But in the API and console, there is no
+// way yet to resume individual instances.
+// if (task.getExecution()!=null) {
+// task.getExecution().suspend();
+// }
}
/** called when the given task completes. The default behaviour
* will send a signal to the execution if this task is still signalling. */
- public void taskComplete(OpenTask task, String outcome) {
+ public void taskComplete(TaskImpl task, String outcome) {
task.historyTaskComplete(outcome);
if (task.isSignalling()) {
@@ -76,11 +81,11 @@
/** is called when a subtask completes. this can be used to
* prematurely signal the execution. e.g. for "5 out of 7" scenarios.*/
- public void taskSubTaskComplete(OpenTask task, OpenTask subTask, String outcome) {
+ public void taskSubTaskComplete(TaskImpl task, OpenTask subTask, String outcome) {
}
/** is called when a variable is updated. This can be used to
* propagate the execution based on availability of variables. */
- public void taskVariableUpdate(OpenTask task, String key, Object value) {
+ public void taskVariableUpdate(TaskImpl task, String key, Object value) {
}
}
Modified: jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/task/TaskImpl.java
===================================================================
--- jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/task/TaskImpl.java 2009-07-04 09:39:57 UTC (rev 5221)
+++ jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/task/TaskImpl.java 2009-07-04 11:53:02 UTC (rev 5222)
@@ -34,13 +34,12 @@
import org.jbpm.api.model.Comment;
import org.jbpm.api.model.Event;
import org.jbpm.api.task.Assignable;
-import org.jbpm.api.task.OpenTask;
import org.jbpm.api.task.Participation;
import org.jbpm.api.task.Swimlane;
import org.jbpm.api.task.Task;
import org.jbpm.pvm.internal.env.Environment;
import org.jbpm.pvm.internal.history.events.TaskAssign;
-import org.jbpm.pvm.internal.history.events.TaskCancel;
+import org.jbpm.pvm.internal.history.events.TaskDelete;
import org.jbpm.pvm.internal.history.events.TaskComplete;
import org.jbpm.pvm.internal.history.events.TaskStart;
import org.jbpm.pvm.internal.model.CommentImpl;
@@ -202,8 +201,8 @@
getTaskHandler().taskSubTaskComplete(this, subTask, outcome);
}
- public void cancel(String reason) {
- getTaskHandler().taskCancel(this, reason);
+ public void delete(String reason) {
+ getTaskHandler().taskDelete(this, reason);
}
// state ////////////////////////////////////////////////////////////////////
@@ -334,9 +333,9 @@
}
}
- public void historyTaskCancel(String reason) {
+ public void historyTaskDelete(String reason) {
if (execution != null) {
- execution.fireHistoryEvent(new TaskCancel(reason));
+ execution.fireHistoryEvent(new TaskDelete(reason));
}
}
Modified: jbpm4/trunk/modules/test-db/src/test/java/org/jbpm/test/task/TaskHandlerTest.java
===================================================================
--- jbpm4/trunk/modules/test-db/src/test/java/org/jbpm/test/task/TaskHandlerTest.java 2009-07-04 09:39:57 UTC (rev 5221)
+++ jbpm4/trunk/modules/test-db/src/test/java/org/jbpm/test/task/TaskHandlerTest.java 2009-07-04 11:53:02 UTC (rev 5222)
@@ -22,9 +22,10 @@
package org.jbpm.test.task;
import org.jbpm.api.Execution;
-import org.jbpm.api.task.OpenTask;
import org.jbpm.api.task.Task;
+import org.jbpm.pvm.internal.task.OpenTask;
import org.jbpm.pvm.internal.task.TaskHandler;
+import org.jbpm.pvm.internal.task.TaskImpl;
import org.jbpm.test.JbpmTestCase;
@@ -35,32 +36,32 @@
public static class ReviewHandler extends TaskHandler {
private static final long serialVersionUID = 1L;
- public boolean executionCreateTask(OpenTask task) {
+ public boolean executionCreateTask(TaskImpl task) {
task.getExecution().setVariable("isExecutionCreateTaskCalled", "true");
return super.executionCreateTask(task);
}
- public void executionSignal(OpenTask task) {
+ public void executionSignal(TaskImpl task) {
task.getExecution().setVariable("isExecutionSignalledCalled", "true");
super.executionSignal(task);
}
- public void taskCancel(OpenTask task, String reason) {
+ public void taskDelete(TaskImpl task, String reason) {
task.getExecution().setVariable("isTaskCancelCalled", "true");
- super.taskCancel(task, reason);
+ super.taskDelete(task, reason);
}
- public void taskComplete(OpenTask task, String outcome) {
+ public void taskComplete(TaskImpl task, String outcome) {
task.getExecution().setVariable("isTaskCompleteCalled", "true");
super.taskComplete(task, outcome);
}
- public void taskSubTaskComplete(OpenTask task, OpenTask subTask, String outcome) {
+ public void taskSubTaskComplete(TaskImpl task, OpenTask subTask, String outcome) {
task.getExecution().setVariable("isSubTaskCompleteCalled", "true");
super.taskSubTaskComplete(task, subTask, outcome);
}
- public void taskVariableUpdate(OpenTask task, String key, Object value) {
+ public void taskVariableUpdate(TaskImpl task, String key, Object value) {
task.getExecution().setVariable("isTaskVariableUpdateCalled", "true");
super.taskVariableUpdate(task, key, value);
}
16 years, 10 months
JBoss JBPM SVN: r5221 - in jbpm4/trunk/modules/test-db: src/test/java and 2 other directories.
by do-not-reply@jboss.org
Author: tom.baeyens(a)jboss.com
Date: 2009-07-04 05:39:57 -0400 (Sat, 04 Jul 2009)
New Revision: 5221
Added:
jbpm4/trunk/modules/test-db/src/test/java/org/jbpm/test/reporting/
jbpm4/trunk/modules/test-db/src/test/java/org/jbpm/test/reporting/DOMUtils.java
jbpm4/trunk/modules/test-db/src/test/java/org/jbpm/test/reporting/SQLStmtTest.java
Removed:
jbpm4/trunk/modules/test-db/src/test/java/reporting/
Modified:
jbpm4/trunk/modules/test-db/pom.xml
Log:
JBPM-2354 moved reporting to proper package name and excluded it from the integration test run
Modified: jbpm4/trunk/modules/test-db/pom.xml
===================================================================
--- jbpm4/trunk/modules/test-db/pom.xml 2009-07-04 08:19:36 UTC (rev 5220)
+++ jbpm4/trunk/modules/test-db/pom.xml 2009-07-04 09:39:57 UTC (rev 5221)
@@ -136,8 +136,8 @@
<failIfNoTests>false</failIfNoTests>
<trimStackTrace>false</trimStackTrace>
<excludes>
- <!-- doesn't run for the moment -->
- <exclude>reporting/SQLStmtTest.java</exclude>
+ <!-- it's sufficient if the SQLStmtTest test runs in the integration test suite only -->
+ <exclude>org/jbpm/test/reporting/SQLStmtTest.java</exclude>
</excludes>
</configuration>
</plugin>
@@ -206,8 +206,8 @@
<failIfNoTests>false</failIfNoTests>
<trimStackTrace>false</trimStackTrace>
<excludes>
- <!-- doesn't run for the moment -->
- <!--exclude>reporting/SQLStmtTest.java</exclude-->
+ <!-- doesn't run for the moment. see https://jira.jboss.org/jira/browse/JBPM-2354 -->
+ <exclude>org/jbpm/test/reporting/SQLStmtTest.java</exclude>
</excludes>
</configuration>
</plugin>
Copied: jbpm4/trunk/modules/test-db/src/test/java/org/jbpm/test/reporting/DOMUtils.java (from rev 5219, jbpm4/trunk/modules/test-db/src/test/java/reporting/DOMUtils.java)
===================================================================
--- jbpm4/trunk/modules/test-db/src/test/java/org/jbpm/test/reporting/DOMUtils.java (rev 0)
+++ jbpm4/trunk/modules/test-db/src/test/java/org/jbpm/test/reporting/DOMUtils.java 2009-07-04 09:39:57 UTC (rev 5221)
@@ -0,0 +1,706 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2006, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file 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.reporting;
+
+import org.w3c.dom.*;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+import javax.xml.namespace.QName;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.*;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.sax.SAXSource;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.stream.StreamSource;
+import java.io.*;
+import java.util.*;
+
+/**
+ * DOM2 utilites
+ *
+ * @author Thomas.Diesler(a)jboss.org
+ * @author alessio.soldano(a)jboss.com
+ */
+public final class DOMUtils
+{
+
+ // All elements created by the same thread are created by the same builder and belong to the same doc
+ private static ThreadLocal<Document> documentThreadLocal = new ThreadLocal<Document>();
+ private static ThreadLocal<DocumentBuilder> builderThreadLocal = new ThreadLocal<DocumentBuilder>()
+ {
+ protected DocumentBuilder initialValue()
+ {
+ try
+ {
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ factory.setValidating(false);
+ factory.setNamespaceAware(true);
+ DocumentBuilder builder = factory.newDocumentBuilder();
+ setEntityResolver(builder);
+ return builder;
+ }
+ catch (ParserConfigurationException e)
+ {
+ throw new RuntimeException("Failed to create DocumentBuilder", e);
+ }
+ }
+
+ private void setEntityResolver(DocumentBuilder builder)
+ {
+ String[] resolvers = new String[] { "org.jboss.ws.core.utils.JBossWSEntityResolver", "org.jboss.util.xml.JBossEntityResolver" };
+
+ EntityResolver entityResolver = null;
+ ClassLoader loader = Thread.currentThread().getContextClassLoader();
+ for (String resolver : resolvers)
+ {
+ try
+ {
+ Class<?> resolverClass = loader.loadClass(resolver);
+ entityResolver = (EntityResolver)resolverClass.newInstance();
+ }
+ catch (Exception ex)
+ {
+ //
+ }
+ }
+
+ if (entityResolver != null)
+ builder.setEntityResolver(entityResolver);
+ }
+ };
+
+ public static void clearThreadLocals()
+ {
+ documentThreadLocal.remove();
+ builderThreadLocal.remove();
+ }
+
+ // Hide the constructor
+ private DOMUtils()
+ {
+ }
+
+ /** Initialize the DocumentBuilder
+ */
+ public static DocumentBuilder getDocumentBuilder()
+ {
+ return builderThreadLocal.get();
+ }
+
+ /** Parse the given XML string and return the root Element
+ */
+ public static Element parse(String xmlString) throws IOException
+ {
+ try
+ {
+ return parse(new ByteArrayInputStream(xmlString.getBytes("UTF-8")));
+ }
+ catch (IOException e)
+ {
+ throw e;
+ }
+ }
+
+ /** Parse the given XML stream and return the root Element
+ */
+ public static Element parse(InputStream xmlStream) throws IOException
+ {
+ try
+ {
+ return getDocumentBuilder().parse(xmlStream).getDocumentElement();
+ }
+ catch (SAXException se)
+ {
+ throw new IOException(se.toString());
+ }
+ finally
+ {
+ xmlStream.close();
+ }
+ }
+
+ /** Parse the given input source and return the root Element
+ */
+ public static Element parse(InputSource source) throws IOException
+ {
+ try
+ {
+ return getDocumentBuilder().parse(source).getDocumentElement();
+ }
+ catch (SAXException se)
+ {
+ throw new IOException(se.toString());
+ }
+ finally
+ {
+ InputStream is = source.getByteStream();
+ if (is != null)
+ {
+ is.close();
+ }
+ Reader r = source.getCharacterStream();
+ if (r != null)
+ {
+ r.close();
+ }
+ }
+ }
+
+ /** Create an Element for a given name
+ */
+ public static Element createElement(String localPart)
+ {
+ Document doc = getOwnerDocument();
+ return doc.createElement(localPart);
+ }
+
+ /** Create an Element for a given name and prefix
+ */
+ public static Element createElement(String localPart, String prefix)
+ {
+ Document doc = getOwnerDocument();
+ return doc.createElement(prefix + ":" + localPart);
+ }
+
+ /** Create an Element for a given name, prefix and uri
+ */
+ public static Element createElement(String localPart, String prefix, String uri)
+ {
+ Document doc = getOwnerDocument();
+ if (prefix == null || prefix.length() == 0)
+ {
+ return doc.createElementNS(uri, localPart);
+ }
+ else
+ {
+ return doc.createElementNS(uri, prefix + ":" + localPart);
+ }
+ }
+
+ /** Create an Element for a given QName
+ */
+ public static Element createElement(QName qname)
+ {
+ return createElement(qname.getLocalPart(), qname.getPrefix(), qname.getNamespaceURI());
+ }
+
+ /** Create a org.w3c.dom.Text node
+ */
+ public static Text createTextNode(String value)
+ {
+ Document doc = getOwnerDocument();
+ return doc.createTextNode(value);
+ }
+
+ /** Get the qname of the given node.
+ */
+ public static QName getElementQName(Element el)
+ {
+ String qualifiedName = el.getNodeName();
+ return resolveQName(el, qualifiedName);
+ }
+
+ /** Transform the given qualified name into a QName
+ */
+ public static QName resolveQName(Element el, String qualifiedName)
+ {
+ QName qname;
+ String prefix = "";
+ String namespaceURI = "";
+ String localPart = qualifiedName;
+
+ int colIndex = qualifiedName.indexOf(":");
+ if (colIndex > 0)
+ {
+ prefix = qualifiedName.substring(0, colIndex);
+ localPart = qualifiedName.substring(colIndex + 1);
+
+ if ("xmlns".equals(prefix))
+ {
+ namespaceURI = "URI:XML_PREDEFINED_NAMESPACE";
+ }
+ else
+ {
+ Element nsElement = el;
+ while (namespaceURI.equals("") && nsElement != null)
+ {
+ namespaceURI = nsElement.getAttribute("xmlns:" + prefix);
+ if (namespaceURI.equals(""))
+ nsElement = getParentElement(nsElement);
+ }
+ }
+
+ if (namespaceURI.equals(""))
+ throw new IllegalArgumentException("Cannot find namespace uri for: " + qualifiedName);
+ }
+ else
+ {
+ Element nsElement = el;
+ while (namespaceURI.equals("") && nsElement != null)
+ {
+ namespaceURI = nsElement.getAttribute("xmlns");
+ if (namespaceURI.equals(""))
+ nsElement = getParentElement(nsElement);
+ }
+ }
+
+ qname = new QName(namespaceURI, localPart, prefix);
+ return qname;
+ }
+
+ /** Get the value from the given attribute
+ *
+ * @return null if the attribute value is empty or the attribute is not present
+ */
+ public static String getAttributeValue(Element el, String attrName)
+ {
+ return getAttributeValue(el, new QName(attrName));
+ }
+
+ /** Get the value from the given attribute
+ *
+ * @return null if the attribute value is empty or the attribute is not present
+ */
+ public static String getAttributeValue(Element el, QName attrName)
+ {
+ String attr = null;
+ if ("".equals(attrName.getNamespaceURI()))
+ attr = el.getAttribute(attrName.getLocalPart());
+ else attr = el.getAttributeNS(attrName.getNamespaceURI(), attrName.getLocalPart());
+
+ if ("".equals(attr))
+ attr = null;
+
+ return attr;
+ }
+
+ /** Get the qname value from the given attribute
+ */
+ public static QName getAttributeValueAsQName(Element el, String attrName)
+ {
+ return getAttributeValueAsQName(el, new QName(attrName));
+
+ }
+
+ /** Get the qname value from the given attribute
+ */
+ public static QName getAttributeValueAsQName(Element el, QName attrName)
+ {
+ QName qname = null;
+
+ String qualifiedName = getAttributeValue(el, attrName);
+ if (qualifiedName != null)
+ {
+ qname = resolveQName(el, qualifiedName);
+ }
+
+ return qname;
+ }
+
+ /** Get the boolean value from the given attribute
+ */
+ public static boolean getAttributeValueAsBoolean(Element el, String attrName)
+ {
+ return getAttributeValueAsBoolean(el, new QName(attrName));
+ }
+
+ /** Get the boolean value from the given attribute
+ */
+ public static boolean getAttributeValueAsBoolean(Element el, QName attrName)
+ {
+ String attrVal = getAttributeValue(el, attrName);
+ boolean ret = "true".equalsIgnoreCase(attrVal) || "1".equalsIgnoreCase(attrVal);
+ return ret;
+ }
+
+ /** Get the integer value from the given attribute
+ */
+ public static Integer getAttributeValueAsInteger(Element el, String attrName)
+ {
+ return getAttributeValueAsInteger(el, new QName(attrName));
+ }
+
+ /** Get the integer value from the given attribute
+ */
+ public static Integer getAttributeValueAsInteger(Element el, QName attrName)
+ {
+ String attrVal = getAttributeValue(el, attrName);
+ return (attrVal != null ? new Integer(attrVal) : null);
+ }
+
+ /** Get the attributes as Map<QName, String>
+ */
+ public static Map getAttributes(Element el)
+ {
+ Map attmap = new HashMap();
+ NamedNodeMap attribs = el.getAttributes();
+ for (int i = 0; i < attribs.getLength(); i++)
+ {
+ Attr attr = (Attr)attribs.item(i);
+ String name = attr.getName();
+ QName qname = resolveQName(el, name);
+ String value = attr.getNodeValue();
+ attmap.put(qname, value);
+ }
+ return attmap;
+ }
+
+ /** Copy attributes between elements
+ */
+ public static void copyAttributes(Element destElement, Element srcElement)
+ {
+ NamedNodeMap attribs = srcElement.getAttributes();
+ for (int i = 0; i < attribs.getLength(); i++)
+ {
+ Attr attr = (Attr)attribs.item(i);
+ String uri = attr.getNamespaceURI();
+ String qname = attr.getName();
+ String value = attr.getNodeValue();
+
+ // Prevent DOMException: NAMESPACE_ERR: An attempt is made to create or
+ // change an object in a way which is incorrect with regard to namespaces.
+ if (uri == null && qname.startsWith("xmlns"))
+ {
+ //
+ }
+ else
+ {
+ destElement.setAttributeNS(uri, qname, value);
+ }
+ }
+ }
+
+ /** True if the node has text child elements only
+ */
+ public static boolean hasTextChildNodesOnly(Node node)
+ {
+ NodeList nodeList = node.getChildNodes();
+ if (nodeList.getLength() == 0)
+ return false;
+
+ for (int i = 0; i < nodeList.getLength(); i++)
+ {
+ Node acksToChildNode = nodeList.item(i);
+ if (acksToChildNode.getNodeType() != Node.TEXT_NODE)
+ return false;
+ }
+
+ return true;
+ }
+
+ /** True if the node has child elements
+ */
+ public static boolean hasChildElements(Node node)
+ {
+ NodeList nlist = node.getChildNodes();
+ for (int i = 0; i < nlist.getLength(); i++)
+ {
+ Node child = nlist.item(i);
+ if (child.getNodeType() == Node.ELEMENT_NODE)
+ return true;
+ }
+ return false;
+ }
+
+ /** Gets child elements
+ */
+ public static Iterator<Element> getChildElements(Node node)
+ {
+ List<Element> list = new LinkedList<Element>();
+ NodeList nlist = node.getChildNodes();
+ for (int i = 0; i < nlist.getLength(); i++)
+ {
+ Node child = nlist.item(i);
+ if (child.getNodeType() == Node.ELEMENT_NODE)
+ list.add((Element)child);
+ }
+ return list.iterator();
+ }
+
+ /** Get the concatenated text content, or null.
+ */
+ public static String getTextContent(Node node)
+ {
+ boolean hasTextContent = false;
+ StringBuffer buffer = new StringBuffer();
+ NodeList nlist = node.getChildNodes();
+ for (int i = 0; i < nlist.getLength(); i++)
+ {
+ Node child = nlist.item(i);
+ if (child.getNodeType() == Node.TEXT_NODE)
+ {
+ buffer.append(child.getNodeValue());
+ hasTextContent = true;
+ }
+ }
+ return (hasTextContent ? buffer.toString() : null);
+ }
+
+ /** Gets the first child element
+ */
+ public static Element getFirstChildElement(Node node)
+ {
+ return getFirstChildElement(node, false);
+ }
+
+ /** Gets the first child element
+ */
+ public static Element getFirstChildElement(Node node, boolean recursive)
+ {
+ return getFirstChildElementIntern(node, null, recursive);
+ }
+
+ /** Gets the first child element for a given local name without namespace
+ */
+ public static Element getFirstChildElement(Node node, String nodeName)
+ {
+ return getFirstChildElement(node, nodeName, false);
+ }
+
+ /** Gets the first child element for a given local name without namespace
+ */
+ public static Element getFirstChildElement(Node node, String nodeName, boolean recursive)
+ {
+ return getFirstChildElementIntern(node, new QName(nodeName), recursive);
+ }
+
+ /** Gets the first child element for a given qname
+ */
+ public static Element getFirstChildElement(Node node, QName nodeName)
+ {
+ return getFirstChildElement(node, nodeName, false);
+ }
+
+ /** Gets the first child element for a given qname
+ */
+ public static Element getFirstChildElement(Node node, QName nodeName, boolean recursive)
+ {
+ return getFirstChildElementIntern(node, nodeName, recursive);
+ }
+
+ private static Element getFirstChildElementIntern(Node node, QName nodeName, boolean recursive)
+ {
+ Element childElement = null;
+ Iterator it = getChildElementsIntern(node, nodeName, recursive);
+ if (it.hasNext())
+ {
+ childElement = (Element)it.next();
+ }
+ return childElement;
+ }
+
+ /** Gets the child elements for a given local name without namespace
+ */
+ public static Iterator getChildElements(Node node, String nodeName)
+ {
+ return getChildElements(node, nodeName, false);
+ }
+
+ /** Gets the child elements for a given local name without namespace
+ */
+ public static Iterator getChildElements(Node node, String nodeName, boolean recursive)
+ {
+ return getChildElementsIntern(node, new QName(nodeName), recursive);
+ }
+
+ /** Gets the child element for a given qname
+ */
+ public static Iterator getChildElements(Node node, QName nodeName)
+ {
+ return getChildElements(node, nodeName, false);
+ }
+
+ /** Gets the child element for a given qname
+ */
+ public static Iterator getChildElements(Node node, QName nodeName, boolean recursive)
+ {
+ return getChildElementsIntern(node, nodeName, recursive);
+ }
+
+ public static List<Element> getChildElementsAsList(Node node, String nodeName)
+ {
+ return getChildElementsAsList(node, nodeName, false);
+ }
+
+ public static List<Element> getChildElementsAsList(Node node, String nodeName, boolean recursive)
+ {
+ return getChildElementsAsListIntern(node, new QName(nodeName), recursive);
+ }
+
+ public static List<Element> getChildElementsAsList(Node node, QName nodeName)
+ {
+ return getChildElementsAsList(node, nodeName, false);
+ }
+
+ public static List<Element> getChildElementsAsList(Node node, QName nodeName, boolean recursive)
+ {
+ return getChildElementsAsListIntern(node, nodeName, recursive);
+ }
+
+ private static List<Element> getChildElementsAsListIntern(Node node, QName nodeName, boolean recursive)
+ {
+ List<Element> list = new LinkedList<Element>();
+ NodeList nlist = node.getChildNodes();
+ for (int i = 0; i < nlist.getLength(); i++)
+ {
+ Node child = nlist.item(i);
+ if (child.getNodeType() == Node.ELEMENT_NODE)
+ {
+ search(list, (Element)child, nodeName, recursive);
+ }
+ }
+ return list;
+ }
+
+ private static void search(List<Element> list, Element baseElement, QName nodeName, boolean recursive)
+ {
+ if (nodeName == null)
+ {
+ list.add(baseElement);
+ }
+ else
+ {
+ QName qname;
+ if (nodeName.getNamespaceURI().length() > 0)
+ {
+ qname = new QName(baseElement.getNamespaceURI(), baseElement.getLocalName());
+ }
+ else
+ {
+ qname = new QName(baseElement.getLocalName());
+ }
+ if (qname.equals(nodeName))
+ {
+ list.add(baseElement);
+ }
+ }
+ if (recursive)
+ {
+ NodeList nlist = baseElement.getChildNodes();
+ for (int i = 0; i < nlist.getLength(); i++)
+ {
+ Node child = nlist.item(i);
+ if (child.getNodeType() == Node.ELEMENT_NODE)
+ {
+ search(list, (Element)child, nodeName, recursive);
+ }
+ }
+ }
+ }
+
+ private static Iterator getChildElementsIntern(Node node, QName nodeName, boolean recursive)
+ {
+ return getChildElementsAsListIntern(node, nodeName, recursive).iterator();
+ }
+
+ /** Gets parent element or null if there is none
+ */
+ public static Element getParentElement(Node node)
+ {
+ Node parent = node.getParentNode();
+ return (parent instanceof Element ? (Element)parent : null);
+ }
+
+ /** Get the owner document that is associated with the current thread */
+ public static Document getOwnerDocument()
+ {
+ Document doc = documentThreadLocal.get();
+ if (doc == null)
+ {
+ doc = getDocumentBuilder().newDocument();
+ documentThreadLocal.set(doc);
+ }
+ return doc;
+ }
+
+ public static Element sourceToElement(Source source) throws IOException
+ {
+ Element retElement = null;
+
+ try
+ {
+ if (source instanceof StreamSource)
+ {
+ StreamSource streamSource = (StreamSource)source;
+
+ InputStream ins = streamSource.getInputStream();
+ if (ins != null)
+ {
+ retElement = parse(ins);
+ }
+ else
+ {
+ Reader reader = streamSource.getReader();
+ retElement = parse(new InputSource(reader));
+ }
+ }
+ else if (source instanceof DOMSource)
+ {
+ DOMSource domSource = (DOMSource)source;
+ Node node = domSource.getNode();
+ if (node instanceof Element)
+ {
+ retElement = (Element)node;
+ }
+ else if (node instanceof Document)
+ {
+ retElement = ((Document)node).getDocumentElement();
+ }
+ else
+ {
+ throw new RuntimeException("Unsupported Node type: " + node.getClass().getName());
+ }
+ }
+ else if (source instanceof SAXSource)
+ {
+ // The fact that JAXBSource derives from SAXSource is an implementation detail.
+ // Thus in general applications are strongly discouraged from accessing methods defined on SAXSource.
+ // The XMLReader object obtained by the getXMLReader method shall be used only for parsing the InputSource object returned by the getInputSource method.
+
+ TransformerFactory tf = TransformerFactory.newInstance();
+ ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
+ Transformer transformer = tf.newTransformer();
+ transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
+ transformer.setOutputProperty(OutputKeys.METHOD, "xml");
+ transformer.transform(source, new StreamResult(baos));
+ retElement = parse(new ByteArrayInputStream(baos.toByteArray()));
+ }
+ else
+ {
+ throw new RuntimeException("Source type not implemented: " + source.getClass().getName());
+ }
+
+ }
+ catch (TransformerException ex)
+ {
+ IOException ioex = new IOException();
+ ioex.initCause(ex);
+ throw ioex;
+ }
+
+ return retElement;
+ }
+}
\ No newline at end of file
Copied: jbpm4/trunk/modules/test-db/src/test/java/org/jbpm/test/reporting/SQLStmtTest.java (from rev 5219, jbpm4/trunk/modules/test-db/src/test/java/reporting/SQLStmtTest.java)
===================================================================
--- jbpm4/trunk/modules/test-db/src/test/java/org/jbpm/test/reporting/SQLStmtTest.java (rev 0)
+++ jbpm4/trunk/modules/test-db/src/test/java/org/jbpm/test/reporting/SQLStmtTest.java 2009-07-04 09:39:57 UTC (rev 5221)
@@ -0,0 +1,232 @@
+package org.jbpm.test.reporting;/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2006, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file 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.
+ */
+
+import junit.framework.TestCase;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import java.io.InputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Properties;
+import java.sql.*;
+
+/**
+ * Parse the birt report templates, extract SQL statements and execute against database.
+ *
+ * @author Heiko.Braun <heiko.braun(a)jboss.com>
+ */
+public class SQLStmtTest extends TestCase
+{
+ private static final String OVERALL_ACTIVITY_RPTDESIGN = "overall_activity.rptdesign";
+
+ private static final String PROCESS_SUMMARY_RPTDESIGN = "process_summary.rptdesign";
+
+ private Connection conn;
+
+ static boolean skipTests;
+
+ protected void setUp() throws Exception
+ {
+ InputStream in =
+ Thread.currentThread().getContextClassLoader()
+ .getResourceAsStream("jbpm.hibernate.cfg.xml");
+
+ if(null==in)
+ fail("Failed to read jbpm.hibernate.cfg.xml");
+
+ Document hibnCfg = parseTemplate(in);
+ Properties jdbcProps = getConnectionSettings(hibnCfg);
+
+ // create connection
+ Class.forName(jdbcProps.getProperty("hibernate.connection.driver_class"));
+ this.conn = DriverManager.getConnection(
+ jdbcProps.getProperty("hibernate.connection.url"),
+ jdbcProps.getProperty("hibernate.connection.username"),
+ jdbcProps.getProperty("hibernate.connection.password")
+ );
+ }
+
+
+ protected void tearDown() throws Exception
+ {
+ if(this.conn!=null)
+ {
+ conn.close();
+ }
+ }
+
+ public void testOverallActivityReport_Statements() throws Exception
+ {
+ InputStream in =
+ Thread.currentThread().getContextClassLoader()
+ .getResourceAsStream(OVERALL_ACTIVITY_RPTDESIGN);
+ assertNotNull("Unable to find report:"+OVERALL_ACTIVITY_RPTDESIGN, in);
+
+ Document doc = parseTemplate(in);
+
+ List<Element> queryTextElements = getQueryTextElements(doc);
+ assertFalse("No query strings found in template", queryTextElements.isEmpty());
+
+ for(Element query : queryTextElements)
+ {
+ executeQuery(query.getTextContent());
+ }
+ }
+
+ public void testProcessSummaryReport_Statements() throws Exception
+ {
+ if(skipTests) return;
+
+ InputStream in =
+ Thread.currentThread().getContextClassLoader()
+ .getResourceAsStream(PROCESS_SUMMARY_RPTDESIGN);
+ assertNotNull("Unable to find report:"+PROCESS_SUMMARY_RPTDESIGN, in);
+
+ Document doc = parseTemplate(in);
+
+ List<Element> queryTextElements = getQueryTextElements(doc);
+ assertFalse("No query strings found in template", queryTextElements.isEmpty());
+
+ for(Element query : queryTextElements)
+ {
+ executeQuery(query.getTextContent());
+ }
+ }
+
+ private void executeQuery(String sql) throws SQLException
+ {
+
+ System.out.println("Execute:");
+ System.out.println(sql);
+
+ PreparedStatement stmt = conn.prepareStatement(sql);
+ ParameterMetaData metaData = stmt.getParameterMetaData();
+ for(int i=1; i<metaData.getParameterCount()+1; i++)
+ {
+ stmt.setString(i, "PLACEHOLDER_STRING");
+ }
+
+ // run it
+ ResultSet rs = stmt.executeQuery();
+ System.out.println("");
+ System.out.println("Result size:" +rs.getFetchSize());
+ System.out.println("--");
+ }
+
+ private List<Element> getQueryTextElements(Document doc)
+ {
+ List<Element> props = new ArrayList<Element>();
+ dfsElementSearch(props, doc.getDocumentElement(),
+ new Filter()
+ {
+ public boolean select(Element candidate)
+ {
+ return candidate.getNodeName().equals("property")
+ && DOMUtils.getAttributeValue(candidate, "name").equals("queryText");
+ }
+ });
+ return props;
+ }
+
+ private Properties getConnectionSettings(Document doc)
+ {
+ List<Element> props = new ArrayList<Element>();
+ dfsElementSearch(props, doc.getDocumentElement(),
+ new Filter()
+ {
+ public boolean select(Element candidate)
+ {
+ return candidate.getNodeName().equals("property")
+ && DOMUtils.getAttributeValue(candidate, "name").startsWith("hibernate.connection");
+ }
+ });
+
+ Properties connectionSettings = new Properties();
+ for(Element el : props)
+ {
+ connectionSettings.put(
+ DOMUtils.getAttributeValue(el, "name"),
+ el.getTextContent()
+ );
+ }
+
+ return connectionSettings;
+ }
+
+
+ private Document parseTemplate(InputStream in)
+ throws ParserConfigurationException, SAXException, IOException
+ {
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ factory.setValidating(false);
+ factory.setNamespaceAware(true);
+ DocumentBuilder builder = factory.newDocumentBuilder();
+ Document doc = builder.parse(in);
+ return doc;
+ }
+
+ private static void dfsElementSearch(List<Element> resultBuffer, Element root, Filter filter)
+ {
+ if( filter.select(root) )
+ {
+ resultBuffer.add(root);
+ return;
+ }
+
+ List<Element> children = getChildElements(root);
+ for(Element child : children)
+ {
+ dfsElementSearch(resultBuffer, child, filter);
+ }
+ }
+
+ private static List<Element> getChildElements(Node node)
+ {
+ List<Element> list = new LinkedList<Element>();
+ NodeList nlist = node.getChildNodes();
+ for (int i = 0; i < nlist.getLength(); i++)
+ {
+ Node child = nlist.item(i);
+ if (child.getNodeType() == Node.ELEMENT_NODE)
+ {
+ list.add((Element)child);
+ }
+ }
+ return list;
+ }
+
+ interface Filter
+ {
+ boolean select(Element candidate);
+ }
+
+
+}
16 years, 10 months
JBoss JBPM SVN: r5220 - in jbpm4/trunk/modules: devguide/src/main/docbook/en/modules and 3 other directories.
by do-not-reply@jboss.org
Author: tom.baeyens(a)jboss.com
Date: 2009-07-04 04:19:36 -0400 (Sat, 04 Jul 2009)
New Revision: 5220
Added:
jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch03-MigrationFromJbpm3.xml
jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch04-ProcessVirtualMachine.xml
jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch05-Architecture.xml
jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch06-ImplementingBasicActivities.xml
jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch07-ProcessAnatomy.xml
jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch08-ImplementingAdvancedActivities.xml
jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch09-Configuration.xml
jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch10-Persistence.xml
jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch11-JobExecutor.xml
jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch12-AdvancedEmail.xml
jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch13-SoftwareLogging.xml
jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch14-History.xml
jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch15-JBossIntegration.xml
jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch16-SpringIntegration.xml
Removed:
jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch03-ProcessVirtualMachine.xml
jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch04-Architecture.xml
jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch05-ImplementingBasicActivities.xml
jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch06-ProcessAnatomy.xml
jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch07-ImplementingAdvancedActivities.xml
jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch08-Configuration.xml
jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch09-Persistence.xml
jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch10-JobExecutor.xml
jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch11-AdvancedEmail.xml
jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch12-SoftwareLogging.xml
jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch13-History.xml
jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch14-JBossIntegration.xml
jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch15-SpringIntegration.xml
jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch16-Jpdl3Migration.xml
Modified:
jbpm4/trunk/modules/devguide/src/main/docbook/en/master.xml
jbpm4/trunk/modules/jpdl/src/main/java/org/jbpm/jpdl/internal/xml/JpdlParser.java
jbpm4/trunk/modules/test-db/src/test/java/org/jbpm/test/eventlistener/EventListenerTest.java
jbpm4/trunk/modules/userguide/src/main/docbook/en/modules/ch06-Jpdl.xml
Log:
JBPM-2223 event propagate property and expanded on the jbpm 3 migration in the devguide
Modified: jbpm4/trunk/modules/devguide/src/main/docbook/en/master.xml
===================================================================
--- jbpm4/trunk/modules/devguide/src/main/docbook/en/master.xml 2009-07-04 03:34:11 UTC (rev 5219)
+++ jbpm4/trunk/modules/devguide/src/main/docbook/en/master.xml 2009-07-04 08:19:36 UTC (rev 5220)
@@ -3,20 +3,20 @@
<!DOCTYPE book [
<!ENTITY ch01-Introduction SYSTEM "modules/ch01-Introduction.xml">
<!ENTITY ch02-Incubation SYSTEM "modules/ch02-Incubation.xml">
- <!ENTITY ch03-ProcessVirtualMachine SYSTEM "modules/ch03-ProcessVirtualMachine.xml">
- <!ENTITY ch04-Architecture SYSTEM "modules/ch04-Architecture.xml">
- <!ENTITY ch05-ImplementingBasicActivities SYSTEM "modules/ch05-ImplementingBasicActivities.xml">
- <!ENTITY ch06-ProcessAnatomy SYSTEM "modules/ch06-ProcessAnatomy.xml">
- <!ENTITY ch07-ImplementingAdvancedActivities SYSTEM "modules/ch07-ImplementingAdvancedActivities.xml">
- <!ENTITY ch08-Configuration SYSTEM "modules/ch08-Configuration.xml">
- <!ENTITY ch09-Persistence SYSTEM "modules/ch09-Persistence.xml">
- <!ENTITY ch10-JobExecutor SYSTEM "modules/ch10-JobExecutor.xml">
- <!ENTITY ch11-AdvancedEmail SYSTEM "modules/ch11-AdvancedEmail.xml">
- <!ENTITY ch12-SoftwareLogging SYSTEM "modules/ch12-SoftwareLogging.xml">
- <!ENTITY ch13-History SYSTEM "modules/ch13-History.xml">
- <!ENTITY ch14-JBossIntegration SYSTEM "modules/ch14-JBossIntegration.xml">
- <!ENTITY ch15-SpringIntegration SYSTEM "modules/ch15-SpringIntegration.xml">
- <!ENTITY ch16-Jpdl3Migration SYSTEM "modules/ch16-Jpdl3Migration.xml">
+ <!ENTITY ch03-MigrationFromJbpm3 SYSTEM "modules/ch03-MigrationFromJbpm3.xml">
+ <!ENTITY ch04-ProcessVirtualMachine SYSTEM "modules/ch04-ProcessVirtualMachine.xml">
+ <!ENTITY ch05-Architecture SYSTEM "modules/ch05-Architecture.xml">
+ <!ENTITY ch06-ImplementingBasicActivities SYSTEM "modules/ch06-ImplementingBasicActivities.xml">
+ <!ENTITY ch07-ProcessAnatomy SYSTEM "modules/ch07-ProcessAnatomy.xml">
+ <!ENTITY ch08-ImplementingAdvancedActivities SYSTEM "modules/ch08-ImplementingAdvancedActivities.xml">
+ <!ENTITY ch09-Configuration SYSTEM "modules/ch09-Configuration.xml">
+ <!ENTITY ch10-Persistence SYSTEM "modules/ch10-Persistence.xml">
+ <!ENTITY ch11-JobExecutor SYSTEM "modules/ch11-JobExecutor.xml">
+ <!ENTITY ch12-AdvancedEmail SYSTEM "modules/ch12-AdvancedEmail.xml">
+ <!ENTITY ch13-SoftwareLogging SYSTEM "modules/ch13-SoftwareLogging.xml">
+ <!ENTITY ch14-History SYSTEM "modules/ch14-History.xml">
+ <!ENTITY ch15-JBossIntegration SYSTEM "modules/ch15-JBossIntegration.xml">
+ <!ENTITY ch16-SpringIntegration SYSTEM "modules/ch16-SpringIntegration.xml">
]>
<book lang="en">
@@ -29,19 +29,19 @@
&ch01-Introduction;
&ch02-Incubation;
- &ch03-ProcessVirtualMachine;
- &ch04-Architecture;
- &ch05-ImplementingBasicActivities;
- &ch06-ProcessAnatomy;
- &ch07-ImplementingAdvancedActivities;
- &ch08-Configuration;
- &ch09-Persistence;
- &ch10-JobExecutor;
- &ch11-AdvancedEmail;
- &ch12-SoftwareLogging;
- &ch13-History;
- &ch14-JBossIntegration;
- &ch15-SpringIntegration;
- &ch16-Jpdl3Migration;
+ &ch03-MigrationFromJbpm3;
+ &ch04-ProcessVirtualMachine;
+ &ch05-Architecture;
+ &ch06-ImplementingBasicActivities;
+ &ch07-ProcessAnatomy;
+ &ch08-ImplementingAdvancedActivities;
+ &ch09-Configuration;
+ &ch10-Persistence;
+ &ch11-JobExecutor;
+ &ch12-AdvancedEmail;
+ &ch13-SoftwareLogging;
+ &ch14-History;
+ &ch15-JBossIntegration;
+ &ch16-SpringIntegration;
</book>
\ No newline at end of file
Copied: jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch03-MigrationFromJbpm3.xml (from rev 5215, jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch16-Jpdl3Migration.xml)
===================================================================
--- jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch03-MigrationFromJbpm3.xml (rev 0)
+++ jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch03-MigrationFromJbpm3.xml 2009-07-04 08:19:36 UTC (rev 5220)
@@ -0,0 +1,230 @@
+<chapter id="migrationfromjbpm3">
+ <title>Migration from jBPM 3</title>
+
+ <section>
+ <title>Goals of jBPM 4</title>
+ <para>In building jBPM 4, we have pursued 2 major goals:</para>
+ <itemizedlist>
+ <listitem><emphasis role="bold">Improve supportability:</emphasis> In jBPM 3 we relied only on community
+ feedback for improving stability and portability. In jBPM 4 we have added
+ a clear indication of which environments and configurations that we support.
+ Those environments will be backed with continuous integration in the JBoss QA
+ Labs. The build now supports all these environments and configurations so that
+ it is easier for us to reproduce and investigate problems if they pop up.
+ This coverage will also guarantee longer lifespan of jBPM 4.
+ </listitem>
+ <listitem><emphasis role="bold">Lowering the treshold and increasing adoption to the next level:</emphasis>
+ In jBPM 4 we created a clear differentiation between the common, basic usage on the
+ one hand and the advanced usage on the other hand. So it will be easier to
+ get started and harder (but still possible) to leverage the bleeding edge stuff
+ on which developers can burn their fingers.
+ </listitem>
+ </itemizedlist>
+ </section>
+
+ <section>
+ <title>Known limitations</title>
+ <para>As part of creating a clear separation between basic and advanced usage, the API
+ has been completely revisited. Basic usage is covered with the public API. The same API
+ is available in all the supported environments.
+ </para>
+ <para>Instead of providing a full DB migration, we opted for a strategy to
+ allow for jBPM 3 and jBPM 4 instances to run concurrently next to each
+ other. One of the main reasons is that any QA for a data migration of the
+ DB contents would be impossible for the project team to achieve.
+ </para>
+ <para>Furthermore, there are some features that are not yet available
+ on jBPM 4. They are ordered from likely to unlikely to get implemented in
+ jBPM 4.
+ </para>
+ <itemizedlist>
+ <listitem>User provided transasctional resources such as JDBC connections
+ or hibernate connections</listitem>
+ <listitem>Exception handlers</listitem>
+ <listitem>Transient variables</listitem>
+ <listitem>Identity expression to calculate the assignee of a task</listitem>
+ <listitem>Task form variable-to-parameter conversions</listitem>
+ </itemizedlist>
+ </section>
+
+ <section id="processconversiontool">
+ <title>Process conversion tool</title>
+ <para>In many cases, a lot of work has been put in the design of JPDL3 process
+ definitions. To avoid a complete manual translation of these processes to the
+ JPDL4 format, the jBPM distribution contains a subdirectory called
+ <emphasis role="bold">migration</emphasis>, which contains a command-line
+ tool for converting JPDL3 process definition files to JPDL process XML files.
+ </para>
+
+ <para>Translated processes might not be executable any more. The jBPM 4
+ features might still be missing or the translation itself might not yet
+ be implemented. But the tedious work of reformatting will be handled
+ by the tool. It will also indicate the parts that it can't translate.
+ </para>
+
+ <para>
+ The tool itself uses only dom4j to do the translation between
+ the two formats and should be easy extensible (the source code is also in
+ the same directory). The design of the tool is deliberately kept very simple
+ (ie most of the logic can be found in the <emphasis role="bold">Jpdl3Converter</emphasis> class).
+ Note that this tool is experimental and tested only a small set of JPDL3
+ process files.
+ </para>
+
+ <section>
+ <title>Overview</title>
+ <para>
+ The jPDL Conversion tool takes a jpdl3 process file as input, and
+ converts it to a jpdl4 process file.
+ </para>
+ <para>
+ Syntax:
+ <programlisting>java org.jbpm.jpdl.internal.convert.JpdlConverterTool -v -o <outputfile> <processfile></programlisting>
+ </para>
+ </section>
+
+ <section>
+ <title>Arguments</title>
+ <itemizedlist>
+ <listitem>
+ <emphasis role="bold">-v (verbose):</emphasis> The tool will print the detail
+ messages while converting the process file. When this argument is used,
+ it will also print the error stacktrace if exceptions are thrown.
+ </listitem>
+ <listitem>
+ <emphasis role="bold">-o (output)</emphasis> Specifies the output file name.
+ By default, the tool will generate a file name ending in 'converted.jpdl.xml'
+ using as a base file name the name derived from the input process file.
+ The output-filename can be an absolute file name path or a relative file name path.
+ </listitem>
+ </itemizedlist>
+ </section>
+
+ <section>
+ <title>Usage examples</title>
+ <programlisting>
+java -jar jpdl-migration-XX.jar simple.jpdl.xml
+java -jar jpdl-migration-XX.jar -v simple.jpdl.xml
+java -jar jpdl-migration-XX.jar -o /home/scott/simple.converted.xml simple.jpdl.xml
+ </programlisting>
+ </section>
+
+ <section>
+ <title>Advanced</title>
+ <para>
+ The conversion tool can easily be integrated with regular Java code
+ (or with Maven or Ant). The following code example shows how to call the
+ internal api to convert the process file:
+ <programlisting>
+URL url = new URL("simple.jpdl");
+Jpdl3Converter jpdlConverter = new Jpdl3Converter(url);
+Document jpdl4Doc = jpdlConverter.readAndConvert();
+
+for (Problem problem : jpdlConverter.problems) {
+ //do something to handle the problem
+}
+
+Writer fileWriter = new FileWriter(outputFile);
+OutputFormat format = OutputFormat.createPrettyPrint();
+XMLWriter writer = new XMLWriter( fileWriter, format );
+writer.write(jpdl4Doc);
+writer.close();</programlisting>
+ </para>
+ </section>
+ </section>
+
+ <section>
+ <title>Translations and changes</title>
+ <para>This section gives an indication of the most important renamings and changes that
+ were applied in jBPM4
+ </para>
+
+ <table><title>General name changes</title>
+ <tgroup cols="2" rowsep="1" colsep="1">
+ <thead>
+ <row>
+ <entry>jBPM 3</entry>
+ <entry>jBPM 4</entry>
+ <entry>Remarks</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>Node</entry>
+ <entry>Activity</entry>
+ </row>
+ <row>
+ <entry>Token</entry>
+ <entry>Execution</entry>
+ <entry>The root execution is now the same object as the
+ process instance. (In jBPM 3, the ProcessInstance had
+ a pointer to the root token)
+ </entry>
+ </row>
+ <row>
+ <entry>Action</entry>
+ <entry>Event listener</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <table><title>jPDL XML changes</title>
+ <tgroup cols="2" rowsep="1" colsep="1">
+ <thead>
+ <row>
+ <entry>jBPM 3</entry>
+ <entry>jBPM 4</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>process-definition</entry>
+ <entry>process</entry>
+ </row>
+ <row>
+ <entry>event type="..."</entry>
+ <entry>on event="..."</entry>
+ </row>
+ <row>
+ <entry>action</entry>
+ <entry>event-listener</entry>
+ </row>
+ <row>
+ <entry>node</entry>
+ <entry>custom</entry>
+ </row>
+ <row>
+ <entry>process-state</entry>
+ <entry>sub-process</entry>
+ </row>
+ <row>
+ <entry>super-state</entry>
+ <entry>group (still in incubation)</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <table><title>Default changes</title>
+ <tgroup cols="2" rowsep="1" colsep="1">
+ <thead>
+ <row>
+ <entry>jBPM 3</entry>
+ <entry>jBPM 4</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>by default, propagated events trigger actions in outer process elements</entry>
+ <entry>by default, propagated events <emphasis role="bold">do not</emphasis>
+ invoke event-listeners in outer elements, but only in the element on which the
+ event listener is subscribed.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ </section>
+
+</chapter>
Deleted: jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch03-ProcessVirtualMachine.xml
===================================================================
--- jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch03-ProcessVirtualMachine.xml 2009-07-04 03:34:11 UTC (rev 5219)
+++ jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch03-ProcessVirtualMachine.xml 2009-07-04 08:19:36 UTC (rev 5220)
@@ -1,50 +0,0 @@
-<chapter id="processvirtualmachine">
- <title>The Process Virtual Machine</title>
- <para>To accomodate multiple process languages and activity pluggability, jBPM is based on
- the Process Virtual Machine. In essence, the Process Virtual Machine is a framework specifying
- executable graphs. A process definition represents an execution flow
- and has a structure that be represented graphically as a diagram.
- </para>
- <para>The Process Virtual Machine separates the structure from a process definition from
- the activity behaviours. The Process Virtual Machine takes the execution of a process from
- one activity to the next and delegates the behaviour of the activities to pluggable Java classes.
- There is an API (<literal>ActivityBehaviour</literal>) that serves as the interface between
- the Process Virtual Machine and the activity behaviour code. Languages like jPDL are
- merely a set of ActivityBehaviour implementations and a parser.
- </para>
- <figure id="example.process.graph">
- <title>Example process definition</title>
- <mediaobject><imageobject><imagedata align="center" fileref="images/process.loan.png"/></imageobject></mediaobject>
- </figure>
- <para>Typically, process definitions are static. A process definition is composed of
- activities and transitions. The runtime behaviour of a activity is encapsulated in a so called
- Activity and it's decoupled from the process graph structure.
- </para>
- <figure id="class.diagram.process.definition">
- <title>Process structure class diagram</title>
- <mediaobject><imageobject><imagedata align="center" fileref="images/class.diagram.process.definition.png"/></imageobject></mediaobject>
- </figure>
- <para>The Process Virtual
- Machine doesn't contain any such activity implementations. It only provides the
- execution environment and an activity API to write <literal>ActivityBehaviour</literal>
- implementations as Java components. Activities can also be wait states. This means
- that the activity control flow goes outside the process system. For example a human task
- or invoking an service asynchronously. While the execution is waiting, the runtime state
- of that execution can be persisted in a DB.
- </para>
- <para>Many executions can be started for one process definition. An execution is a pointer
- that keeps track of the current activity.
- </para>
- <figure id="example.execution">
- <title>Example execution</title>
- <mediaobject><imageobject><imagedata align="center" fileref="images/loan.execution.png"/></imageobject></mediaobject>
- </figure>
- <para>To represent concurrent paths of execution, there is
- a hierarchical parent-child relation between so that one process instance can cope with concurrent
- paths of execution.
- </para>
- <figure id="class.diagram.process.execution">
- <title>Execution class diagram</title>
- <mediaobject><imageobject><imagedata align="center" fileref="images/class.diagram.process.execution.png"/></imageobject></mediaobject>
- </figure>
-</chapter>
Deleted: jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch04-Architecture.xml
===================================================================
--- jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch04-Architecture.xml 2009-07-04 03:34:11 UTC (rev 5219)
+++ jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch04-Architecture.xml 2009-07-04 08:19:36 UTC (rev 5220)
@@ -1,260 +0,0 @@
-<chapter id="architecture">
- <title>Architecture</title>
-
- <section id="apis">
- <title>APIs</title>
- <para>The Process Virtual Machine has 4 integrated API's that together
- offer a complete coverage of working with processes in the different execution modes.
- Each of the APIs has a specific purpose that fits within the following overall
- architecture.
- </para>
- <figure id="apis">
- <title>The 4 API's of the Process Virtual Machine</title>
- <mediaobject><imageobject><imagedata align="center" fileref="images/apis.png"/></imageobject></mediaobject>
- </figure>
- <para>The services interfaces should be used from application code that wants to interact
- with the Process Virtual Machine which runs in transactional persistent mode, backed by a
- database. This is the most typical way how users interact with the PVM as a workflow engine.
- </para>
- <para>To execute processes without persistence, the client API can be used to work with process
- and execution objects directly. The client API expose the methods of the core model objects.
- </para>
- <para>The activity API is used to implement the runtime behaviour of activities. So a activity
- type is in fact a component with at the core an implementation of the <literal>ActivityBehaviour</literal>
- interface. ActivityBehaviour implementations can control the flow of execution.
- </para>
- <para>The event listener API serves to write pieces of Java code that should be executed upon
- process events. It's very similar to the activity API with that exception that event listeners
- are not able to control the flow of execution.
- </para>
- </section>
-
- <section>
- <title>Activity API</title>
- <para>The activity API allows to implement the runtime activity behaviour in Java.
- </para>
- <programlisting>public interface ActivityBehaviour extends Serializable {
- void execute(ActivityExecution execution) throws Exception;
-}</programlisting>
- <para>An activity is the behaviour of the activity to which it is associated.
- The provided execution is the execution that arrives in the activity.
- The interface <literal>ActivityExecution</literal> exposes special
- methods to control the execution flow.
- </para>
- <programlisting>public interface ActivityExecution extends OpenExecution {
-
- void waitForSignal();
- void take(String transitionName);
- void execute(String activityName);
-
- ...
-
-}</programlisting>
- </section>
-
- <section>
- <title>Event listener API</title>
- <para>The event listener API allows for listeners to be developed in Java code
- and that are invoked on specific process events like entering a activity or leaving
- a activity. It is very similar to the activity API, but the difference is
- that the propagation of the execution flow cannot be controlled. E.g. when an execution
- is taking a transition, a listener to that event can be notified, but since the
- transition is already being taking, the execution flow cannot be changed
- by the event listeners.
- </para>
- <programlisting>public interface EventListener extends Serializable {
-
- void notify(EventListenerExecution execution) throws Exception;
-
-}</programlisting>
- </section>
-
- <section>
- <title>Client API</title>
- <para>The client API is the interface that exposes the methods for
- managing executions on the plain process definition and execution objects directly.
- </para>
- <para>At a minimal, the client API and the activity API are needed to create
- some a process definition with activities and execute it.
- </para>
- </section>
-
- <section>
- <title>Environment</title>
- <para>In the persistent execution mode, the first purpose of the environment is
- to enable processes to be executed in different transactional environments like
- standard Java, enterprise Java, SEAM and Spring.
- </para>
- <para>The PVM code itself will only use transactional resources through self-defined
- interfaces. For example, the PVM itself has interfaces for some methods on the hibernate
- session, a async messaging session and a timer session.
- </para>
- <para>The environment allows to configure the actual implementations, lazy
- initialization of the services on a request-basis and caching the service
- objects for the duration of the transaction.
- </para>
- <para>An environment factory is static and one environment factory can serve
- all the threads in an application.
- </para>
- <programlisting>EnvironmentFactory environmentFactory = new PvmEnvironmentFactory("environment.cfg.xml");</programlisting>
- <para>Environment blocks can surround persistent process operations
- like this:
- </para>
- <programlisting>Environment environment = environmentFactory.openEnvironment();
-try {
-
- ... inside the environment block...
-
-} finally {
- environment.close();
-}</programlisting>
- <para>The PVM itself will fetch all it's transactional resources and configurations
- from the environment. It's recommended that <literal>Activity</literal> implementations
- do the same.
- </para>
- <para>The <literal>org.jbpm.pvm.internal.cfg.JbpmConfiguration</literal> acts as Configuration,
- ProcessEngine and EnvironmentFactory.
- </para>
- </section>
-
- <section>
- <title>Commands</title>
- <para>Commands encapsulate operations that are to be executed within an environment
- block. The main purpose for commands is to capture the logic of
- </para>
- <programlisting>public interface Command<T> extends Serializable {
-
- T execute(Environment environment) throws Exception;
-
-}</programlisting>
- <para></para>
- </section>
-
- <section>
- <title>Services</title>
- <para>There are three main services: <literal>RepositoryService</literal>,
- <literal>ExecutionService</literal> and <literal>ManagementService</literal>.
- In general, services are session facades that expose methods for persistent
- usage of the PVM. The next fragments show the essential methods as example
- to illustrate those services.
- </para>
- <para>The <literal>RepositoryService</literal> manages the repository of
- process definitions.
- </para>
- <programlisting>public interface RepositoryService {
-
- Deployment createDeployment();
-
- ProcessDefinitionQuery createProcessDefinitionQuery();
-
- ...
-
-}</programlisting>
- <para>The <literal>ExecutionService</literal> manages the runtime
- executions.</para>
- <programlisting>public interface ExecutionService {
-
- ProcessInstance startProcessInstanceById(String processDefinitionId);
-
- ProcessInstance signalExecutionById(String executionId);
-
- ...
-
-}</programlisting>
- <para>The <literal>ManagementService</literal> groups all management operations
- that are needed to keep the system up and running.
- </para>
- <programlisting>public interface ManagementService {
-
- JobQuery createJobQuery();
-
- void executeJob(long jobDbid);
-
- ...
-
-}</programlisting>
- <para>The implementation of all these methods is encapsulated in
- <literal>Command</literal>s. And the three services all delegate the
- execution of the commands to a <literal>CommandService</literal>:
- </para>
- <programlisting>public interface CommandService {
-
- <T> T execute(Command<T> command);
-
-}</programlisting>
- <para>The <literal>CommandService</literal> is configured in the
- environment. A chain of CommandServices can act as interceptors
- around a command. This is the core mechanism on how persistence and
- transactional support can be offered in a variety of environments.
- </para>
- <para>The default configuration file <literal>jbpm.default.cfg.xml</literal>
- includes following section that configures the services
- </para>
- <programlisting><jbpm-configuration>
-
- <process-engine>
-
- <repository-service />
- <repository-cache />
- <execution-service />
- <history-service />
- <management-service />
- <identity-service />
- <task-service /></programlisting>
- <para>And the file <literal>jbpm.tx.hibernate.cfg.xml</literal> contains the
- following command service configuration:</para>
- <programlisting><jbpm-configuration>
-
- <process-engine-context>
- <command-service>
- <retry-interceptor />
- <environment-interceptor />
- <standard-transaction-interceptor />
- </command-service>
- </process-engine-context>
-
- ...</programlisting>
- <para>The services like e.g. <literal>repository-service</literal>, <literal>execution-service</literal>
- and <literal>management-service</literal> will look up the configured
- <literal>command-service</literal> by type. The <literal>command-service</literal>
- tag corresponds to the default command service that essentially does nothing else
- then just execute the command providing it the current environment.
- </para>
- <para>The configured <literal>command-service</literal> results into the following
- a chain of three interceptors followed by the default command executor.
- </para>
- <figure id="interceptors">
- <title>The CommandService interceptors</title>
- <mediaobject><imageobject><imagedata align="center" fileref="images/interceptors.png"/></imageobject></mediaobject>
- </figure>
- <para>The retry interceptor is the first in the chain and that one that will be exposed as the
- <literal>CommandService.class</literal> from the environment. So the retry interceptor
- will be given to the respective services <literal>repository-service</literal>, <literal>execution-service</literal>
- and <literal>management-service</literal>.
- </para>
- <para>The <literal>retry-interceptor</literal> will catch hibernate StaleObjectExceptions
- (indicating optimistic locking failures) and retry to execute the command.
- </para>
- <para>The <literal>environment-interceptor</literal> will put an environment block
- around the execution of the command.
- </para>
- <para>The <literal>standard-transaction-interceptor</literal> will initialize a
- <literal>StandardTransaction</literal>. The hibernate session/transaction will be
- enlisted as a resource with this standard transaction.
- </para>
- <para>Different configurations of this interceptor stack will also enable to
- </para>
- <itemizedlist>
- <listitem>delegate execution to a local ejb command service so that an container
- managed transaction is started.
- </listitem>
- <listitem>delegate to a remote ejb command service so that the command actually
- gets executed on a different JVM.
- </listitem>
- <listitem>package the command as an asynchronous message so that the command gets
- executed asynchronously in a different transaction.
- </listitem>
- </itemizedlist>
- </section>
-
-</chapter>
\ No newline at end of file
Copied: jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch04-ProcessVirtualMachine.xml (from rev 5215, jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch03-ProcessVirtualMachine.xml)
===================================================================
--- jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch04-ProcessVirtualMachine.xml (rev 0)
+++ jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch04-ProcessVirtualMachine.xml 2009-07-04 08:19:36 UTC (rev 5220)
@@ -0,0 +1,50 @@
+<chapter id="processvirtualmachine">
+ <title>The Process Virtual Machine</title>
+ <para>To accomodate multiple process languages and activity pluggability, jBPM is based on
+ the Process Virtual Machine. In essence, the Process Virtual Machine is a framework specifying
+ executable graphs. A process definition represents an execution flow
+ and has a structure that be represented graphically as a diagram.
+ </para>
+ <para>The Process Virtual Machine separates the structure from a process definition from
+ the activity behaviours. The Process Virtual Machine takes the execution of a process from
+ one activity to the next and delegates the behaviour of the activities to pluggable Java classes.
+ There is an API (<literal>ActivityBehaviour</literal>) that serves as the interface between
+ the Process Virtual Machine and the activity behaviour code. Languages like jPDL are
+ merely a set of ActivityBehaviour implementations and a parser.
+ </para>
+ <figure id="example.process.graph">
+ <title>Example process definition</title>
+ <mediaobject><imageobject><imagedata align="center" fileref="images/process.loan.png"/></imageobject></mediaobject>
+ </figure>
+ <para>Typically, process definitions are static. A process definition is composed of
+ activities and transitions. The runtime behaviour of a activity is encapsulated in a so called
+ Activity and it's decoupled from the process graph structure.
+ </para>
+ <figure id="class.diagram.process.definition">
+ <title>Process structure class diagram</title>
+ <mediaobject><imageobject><imagedata align="center" fileref="images/class.diagram.process.definition.png"/></imageobject></mediaobject>
+ </figure>
+ <para>The Process Virtual
+ Machine doesn't contain any such activity implementations. It only provides the
+ execution environment and an activity API to write <literal>ActivityBehaviour</literal>
+ implementations as Java components. Activities can also be wait states. This means
+ that the activity control flow goes outside the process system. For example a human task
+ or invoking an service asynchronously. While the execution is waiting, the runtime state
+ of that execution can be persisted in a DB.
+ </para>
+ <para>Many executions can be started for one process definition. An execution is a pointer
+ that keeps track of the current activity.
+ </para>
+ <figure id="example.execution">
+ <title>Example execution</title>
+ <mediaobject><imageobject><imagedata align="center" fileref="images/loan.execution.png"/></imageobject></mediaobject>
+ </figure>
+ <para>To represent concurrent paths of execution, there is
+ a hierarchical parent-child relation between so that one process instance can cope with concurrent
+ paths of execution.
+ </para>
+ <figure id="class.diagram.process.execution">
+ <title>Execution class diagram</title>
+ <mediaobject><imageobject><imagedata align="center" fileref="images/class.diagram.process.execution.png"/></imageobject></mediaobject>
+ </figure>
+</chapter>
Property changes on: jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch04-ProcessVirtualMachine.xml
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Copied: jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch05-Architecture.xml (from rev 5215, jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch04-Architecture.xml)
===================================================================
--- jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch05-Architecture.xml (rev 0)
+++ jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch05-Architecture.xml 2009-07-04 08:19:36 UTC (rev 5220)
@@ -0,0 +1,260 @@
+<chapter id="architecture">
+ <title>Architecture</title>
+
+ <section id="apis">
+ <title>APIs</title>
+ <para>The Process Virtual Machine has 4 integrated API's that together
+ offer a complete coverage of working with processes in the different execution modes.
+ Each of the APIs has a specific purpose that fits within the following overall
+ architecture.
+ </para>
+ <figure id="apis">
+ <title>The 4 API's of the Process Virtual Machine</title>
+ <mediaobject><imageobject><imagedata align="center" fileref="images/apis.png"/></imageobject></mediaobject>
+ </figure>
+ <para>The services interfaces should be used from application code that wants to interact
+ with the Process Virtual Machine which runs in transactional persistent mode, backed by a
+ database. This is the most typical way how users interact with the PVM as a workflow engine.
+ </para>
+ <para>To execute processes without persistence, the client API can be used to work with process
+ and execution objects directly. The client API expose the methods of the core model objects.
+ </para>
+ <para>The activity API is used to implement the runtime behaviour of activities. So a activity
+ type is in fact a component with at the core an implementation of the <literal>ActivityBehaviour</literal>
+ interface. ActivityBehaviour implementations can control the flow of execution.
+ </para>
+ <para>The event listener API serves to write pieces of Java code that should be executed upon
+ process events. It's very similar to the activity API with that exception that event listeners
+ are not able to control the flow of execution.
+ </para>
+ </section>
+
+ <section>
+ <title>Activity API</title>
+ <para>The activity API allows to implement the runtime activity behaviour in Java.
+ </para>
+ <programlisting>public interface ActivityBehaviour extends Serializable {
+ void execute(ActivityExecution execution) throws Exception;
+}</programlisting>
+ <para>An activity is the behaviour of the activity to which it is associated.
+ The provided execution is the execution that arrives in the activity.
+ The interface <literal>ActivityExecution</literal> exposes special
+ methods to control the execution flow.
+ </para>
+ <programlisting>public interface ActivityExecution extends OpenExecution {
+
+ void waitForSignal();
+ void take(String transitionName);
+ void execute(String activityName);
+
+ ...
+
+}</programlisting>
+ </section>
+
+ <section>
+ <title>Event listener API</title>
+ <para>The event listener API allows for listeners to be developed in Java code
+ and that are invoked on specific process events like entering a activity or leaving
+ a activity. It is very similar to the activity API, but the difference is
+ that the propagation of the execution flow cannot be controlled. E.g. when an execution
+ is taking a transition, a listener to that event can be notified, but since the
+ transition is already being taking, the execution flow cannot be changed
+ by the event listeners.
+ </para>
+ <programlisting>public interface EventListener extends Serializable {
+
+ void notify(EventListenerExecution execution) throws Exception;
+
+}</programlisting>
+ </section>
+
+ <section>
+ <title>Client API</title>
+ <para>The client API is the interface that exposes the methods for
+ managing executions on the plain process definition and execution objects directly.
+ </para>
+ <para>At a minimal, the client API and the activity API are needed to create
+ some a process definition with activities and execute it.
+ </para>
+ </section>
+
+ <section>
+ <title>Environment</title>
+ <para>In the persistent execution mode, the first purpose of the environment is
+ to enable processes to be executed in different transactional environments like
+ standard Java, enterprise Java, SEAM and Spring.
+ </para>
+ <para>The PVM code itself will only use transactional resources through self-defined
+ interfaces. For example, the PVM itself has interfaces for some methods on the hibernate
+ session, a async messaging session and a timer session.
+ </para>
+ <para>The environment allows to configure the actual implementations, lazy
+ initialization of the services on a request-basis and caching the service
+ objects for the duration of the transaction.
+ </para>
+ <para>An environment factory is static and one environment factory can serve
+ all the threads in an application.
+ </para>
+ <programlisting>EnvironmentFactory environmentFactory = new PvmEnvironmentFactory("environment.cfg.xml");</programlisting>
+ <para>Environment blocks can surround persistent process operations
+ like this:
+ </para>
+ <programlisting>Environment environment = environmentFactory.openEnvironment();
+try {
+
+ ... inside the environment block...
+
+} finally {
+ environment.close();
+}</programlisting>
+ <para>The PVM itself will fetch all it's transactional resources and configurations
+ from the environment. It's recommended that <literal>Activity</literal> implementations
+ do the same.
+ </para>
+ <para>The <literal>org.jbpm.pvm.internal.cfg.JbpmConfiguration</literal> acts as Configuration,
+ ProcessEngine and EnvironmentFactory.
+ </para>
+ </section>
+
+ <section>
+ <title>Commands</title>
+ <para>Commands encapsulate operations that are to be executed within an environment
+ block. The main purpose for commands is to capture the logic of
+ </para>
+ <programlisting>public interface Command<T> extends Serializable {
+
+ T execute(Environment environment) throws Exception;
+
+}</programlisting>
+ <para></para>
+ </section>
+
+ <section>
+ <title>Services</title>
+ <para>There are three main services: <literal>RepositoryService</literal>,
+ <literal>ExecutionService</literal> and <literal>ManagementService</literal>.
+ In general, services are session facades that expose methods for persistent
+ usage of the PVM. The next fragments show the essential methods as example
+ to illustrate those services.
+ </para>
+ <para>The <literal>RepositoryService</literal> manages the repository of
+ process definitions.
+ </para>
+ <programlisting>public interface RepositoryService {
+
+ Deployment createDeployment();
+
+ ProcessDefinitionQuery createProcessDefinitionQuery();
+
+ ...
+
+}</programlisting>
+ <para>The <literal>ExecutionService</literal> manages the runtime
+ executions.</para>
+ <programlisting>public interface ExecutionService {
+
+ ProcessInstance startProcessInstanceById(String processDefinitionId);
+
+ ProcessInstance signalExecutionById(String executionId);
+
+ ...
+
+}</programlisting>
+ <para>The <literal>ManagementService</literal> groups all management operations
+ that are needed to keep the system up and running.
+ </para>
+ <programlisting>public interface ManagementService {
+
+ JobQuery createJobQuery();
+
+ void executeJob(long jobDbid);
+
+ ...
+
+}</programlisting>
+ <para>The implementation of all these methods is encapsulated in
+ <literal>Command</literal>s. And the three services all delegate the
+ execution of the commands to a <literal>CommandService</literal>:
+ </para>
+ <programlisting>public interface CommandService {
+
+ <T> T execute(Command<T> command);
+
+}</programlisting>
+ <para>The <literal>CommandService</literal> is configured in the
+ environment. A chain of CommandServices can act as interceptors
+ around a command. This is the core mechanism on how persistence and
+ transactional support can be offered in a variety of environments.
+ </para>
+ <para>The default configuration file <literal>jbpm.default.cfg.xml</literal>
+ includes following section that configures the services
+ </para>
+ <programlisting><jbpm-configuration>
+
+ <process-engine>
+
+ <repository-service />
+ <repository-cache />
+ <execution-service />
+ <history-service />
+ <management-service />
+ <identity-service />
+ <task-service /></programlisting>
+ <para>And the file <literal>jbpm.tx.hibernate.cfg.xml</literal> contains the
+ following command service configuration:</para>
+ <programlisting><jbpm-configuration>
+
+ <process-engine-context>
+ <command-service>
+ <retry-interceptor />
+ <environment-interceptor />
+ <standard-transaction-interceptor />
+ </command-service>
+ </process-engine-context>
+
+ ...</programlisting>
+ <para>The services like e.g. <literal>repository-service</literal>, <literal>execution-service</literal>
+ and <literal>management-service</literal> will look up the configured
+ <literal>command-service</literal> by type. The <literal>command-service</literal>
+ tag corresponds to the default command service that essentially does nothing else
+ then just execute the command providing it the current environment.
+ </para>
+ <para>The configured <literal>command-service</literal> results into the following
+ a chain of three interceptors followed by the default command executor.
+ </para>
+ <figure id="interceptors">
+ <title>The CommandService interceptors</title>
+ <mediaobject><imageobject><imagedata align="center" fileref="images/interceptors.png"/></imageobject></mediaobject>
+ </figure>
+ <para>The retry interceptor is the first in the chain and that one that will be exposed as the
+ <literal>CommandService.class</literal> from the environment. So the retry interceptor
+ will be given to the respective services <literal>repository-service</literal>, <literal>execution-service</literal>
+ and <literal>management-service</literal>.
+ </para>
+ <para>The <literal>retry-interceptor</literal> will catch hibernate StaleObjectExceptions
+ (indicating optimistic locking failures) and retry to execute the command.
+ </para>
+ <para>The <literal>environment-interceptor</literal> will put an environment block
+ around the execution of the command.
+ </para>
+ <para>The <literal>standard-transaction-interceptor</literal> will initialize a
+ <literal>StandardTransaction</literal>. The hibernate session/transaction will be
+ enlisted as a resource with this standard transaction.
+ </para>
+ <para>Different configurations of this interceptor stack will also enable to
+ </para>
+ <itemizedlist>
+ <listitem>delegate execution to a local ejb command service so that an container
+ managed transaction is started.
+ </listitem>
+ <listitem>delegate to a remote ejb command service so that the command actually
+ gets executed on a different JVM.
+ </listitem>
+ <listitem>package the command as an asynchronous message so that the command gets
+ executed asynchronously in a different transaction.
+ </listitem>
+ </itemizedlist>
+ </section>
+
+</chapter>
\ No newline at end of file
Deleted: jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch05-ImplementingBasicActivities.xml
===================================================================
--- jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch05-ImplementingBasicActivities.xml 2009-07-04 03:34:11 UTC (rev 5219)
+++ jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch05-ImplementingBasicActivities.xml 2009-07-04 08:19:36 UTC (rev 5220)
@@ -1,486 +0,0 @@
-<chapter id="implementingbasicactivities">
- <title>Implementing basic activities</title>
-
- <para>This chapter explains the basics of process definitions, the features offered by
- the Process Virtual Machine and how activity implementations can be build. At the same
- time the client API is shown to execute processes with those activity implementations.
- </para>
-
- <!-- ### Activity ####################################################### -->
- <section id="activity">
- <title>ActivityBehaviour</title>
- <para>The PVM library doesn't have a fixed set of process constructs.
- Instead, runtime behaviour of a activity is delegated to an <literal>ActivityBehaviour</literal>.
- In other words, <literal>ActivityBehaviour</literal> is an interface to implement the runtime
- behaviour of process constructs in plain Java.
- </para>
- <programlisting>public <emphasis role="bold">interface ActivityBehaviour</emphasis> extends Serializable {
-
- void <emphasis role="bold">execute</emphasis>(ActivityExecution execution) throws Exception;
-
-}</programlisting>
- <para>When an activity behaviour is called, it is in full control of the further
- propagation of the execution. In other words, an activity behaviour can decide what the execution
- should do next. For example, it can take a transition with
- <literal>execution.take(Transition)</literal> or go into a wait state with
- <literal>execution.waitForSignal()</literal>. In case the activity behaviour does not invoke
- any of the above execution propagation methods, the execution will
- <link linkend="implicitproceedbehaviour">proceed in a default way</link>.
- </para>
- </section>
-
- <!-- ### ActivityBehaviour example ############################################### -->
- <section id="activitybehaviourexample">
- <title>ActivityBehaviour example</title>
- <para>We'll start with a very original hello world example. A Display
- activity will print a message to the console:
- </para>
- <programlisting>public <emphasis role="bold">class Display</emphasis> implements <emphasis role="bold">ActivityBehaviour</emphasis> {
-
- String message;
-
- public Display(String message) {
- this.message = message;
- }
-
- public void execute(ActivityExecution execution) {
- <emphasis role="bold">System.out.println(message);</emphasis>
- }
-}</programlisting>
- <para>Let' build our first process definition with this activity:</para>
- <figure id="activity.example">
- <title>Display example process</title>
- <mediaobject><imageobject><imagedata align="center" fileref="images/process.ab.png"/></imageobject></mediaobject>
- </figure>
- <programlisting>TODO add ProcessBuilder example code</programlisting>
- <para>Now we can execute this process as follows:</para>
- <programlisting>Execution execution = processDefinition.startExecution();</programlisting>
- <para>The invocation of <literal>startExecution</literal> will print hello world to the console:</para>
- <programlisting>hello
-world</programlisting>
- <para>One thing already worth noticing is that activities can be configured
- with properties. In the Display example, you can see that the message property
- is configured differently in the two usages. With configuration properties
- it becomes possible to write reusable activities. They can then be configured
- differently each time they are used in a process. That is an essential part of
- how process languages can be build on top of the Process Virtual Machine.
- </para>
- <para>The other part that needs explanation is that this activity
- implementation does not contain any instructions for the propagation of the
- execution. When a new process instance is started, the execution is positioned
- in the initial activity and that activity is executed. The method
- <literal>Display.execute</literal> makes use of what is called implicit propagation
- of execution. Concretely this means that the activity itself does not
- invoke any of the methods on the execution to propagate it. In that case
- implicit propagation kicks in. Implicit propagation will take the first
- transition if there is one. If not, it will end the execution. This explains
- why both activities <literal>a</literal> and <literal>b</literal> are executed and that
- the execution stops after activity <literal>b</literal> is executed.
- </para>
- <para>More details about the implicit proceed behaviour can be found
- in <xref linkend="implicitproceedbehaviour" /></para>
- </section>
-
- <!-- ### ExternalActivityBehaviour ############################################### -->
- <section id="externalactivitybehaviour">
- <title>ExternalActivityBehaviour</title>
- <para>External activities are activities for which the responsibility for proceeding
- the execution is transferred externally, meaning outside the process system. This
- means that for the system that is executing the process, it's a wait state. The
- execution will wait until an external trigger is given.
- </para>
- <para>For dealing with external triggers, <literal>ExternalActivityBehaviour</literal>
- adds one method to the <literal>ActivityBehaviour</literal>:</para>
- <programlisting>public <emphasis role="bold">interface ExternalActivity</emphasis> extends <emphasis role="bold">Activity</emphasis> {
-
- void <emphasis role="bold">signal</emphasis>(Execution execution,
- String signal,
- Map<String, Object> parameters) throws Exception;
-
-}</programlisting>
- <para>Just like with plain activities, when an execution arrives in a activity, the
- <literal>execute</literal>-method of the external activity behaviour is invoked.
- In external activities, the execute method typically does something to
- transfer the responsibility to another system and then enters a wait
- state by invoking <literal>execution.waitForSignal()</literal>. For
- example in the execute method, responsibility could be transferred to a
- person by creating a task entry in a task management system and then
- wait until the person completes the task.
- </para>
- <para>In case a activity behaves as a wait state, then the execution will
- wait in that activity until the execution's <literal>signal</literal> method
- is invoked. The execution will delegate that signal to the ExternalActivityBehaviour
- object associated to the current activity.
- </para>
- <para>So the Activity's <literal>signal</literal>-method is invoked
- when the execution receives an external trigger during the wait state. With the
- signal method, responsibility is transferred back to the process execution. For
- example, when a person completes a task, the task management system calls the
- signal method on the execution.
- </para>
- <para>A signal can optionally have a signal name and a map of parameters. Most
- common way on how activity behaviours interprete the signal and parameters is that
- the signal relates to the outgoing transition that needs to be taken and that the
- parameters are set as variables on the execution. But those are just examples, it
- is up to the activity to use the signal and the parameters as it pleases.
- </para>
- </section>
-
- <!-- ### ExternalActivity example ####################################### -->
- <section id="externalactivityexample">
- <title>ExternalActivity example</title>
- <para>Here's a first example of a simple wait state implementation:
- </para>
- <programlisting>public <emphasis role="bold">class WaitState</emphasis> implements <emphasis role="bold">ExternalActivity</emphasis> {
-
- public void execute(ActivityExecution execution) {
- <emphasis role="bold">execution.waitForSignal();</emphasis>
- }
-
- public void signal(ActivityExecution execution,
- String signalName,
- Map<String, Object> parameters) {
- <emphasis role="bold">execution.take(signalName);</emphasis>
- }
-}</programlisting>
- <para>The <literal>execute</literal>-method calls
- <literal>execution.waitForSignal()</literal>. The invocation of
- <literal>execution.waitForSignal()</literal> will bring the process execution
- into a wait state until an external trigger is given.
- </para>
- <para><literal>signal</literal>-method takes the transition with
- the signal parameter as the transition name. So when an execution receives an
- external trigger, the signal name is interpreted as the name of an outgoing
- transition and the execution will be propagated over that transition.
- </para>
- <para>Here's the same simple process that has a transition from a to b. This
- time, the behaviour of the two activities will be WaitState's.
- </para>
- <figure id="process.diagram">
- <title>The external activity example process</title>
- <mediaobject><imageobject><imagedata align="center" fileref="images/process.ab.png"/></imageobject></mediaobject>
- </figure>
- <programlisting>ClientProcessDefinition processDefinition = ProcessFactory.build()
- <emphasis role="bold">.activity("a").initial().behaviour(new WaitState())</emphasis>
- .transition().to("b")
- <emphasis role="bold">.activity("b").behaviour(new WaitState())</emphasis>
-.done();</programlisting>
- <para>Let's start a new process instance for this process definition:</para>
- <programlisting>ClientExecution execution = processDefinition.startProcessInstance();</programlisting>
- <para>Starting this process will execute the <literal>WaitState</literal> activity
- in activity <literal>a</literal>. <literal>WaitState.execute</literal> will invoke
- <literal>ActivityExecution.waitForSignal</literal>. So when the
- <literal>processDefinition.startProcessInstance()</literal> returns, the execution
- will still be positioned in activity a.
- </para>
- <programlisting>assertEquals("a", execution.getActivityName());</programlisting>
- <para>Then we provide the external trigger by calling the <literal>signal</literal>
- method.
- </para>
- <programlisting>execution.signal();</programlisting>
- <para>The <literal>execution.signal()</literal> will delegate to the activity
- of the current activity. So in this case that is the <literal>WaitState</literal>
- activity in activity <literal>a</literal>. The <literal>WaitState.signal</literal>
- will invoke the <literal>ActivityExecution.take(String transitionName)</literal>.
- Since we didn't supply a signalName, the first transition with name <literal>null</literal>
- will be taken. The only transition we specified out of activity <literal>a</literal>
- didn't get a name so that one will be taken. And that transition points to activity
- <literal>b</literal>. When the execution arrives in activity <literal>b</literal>,
- the <literal>WaitState</literal> in activity <literal>b</literal> is executed.
- Similar as we saw above, the execution will wait in activity <literal>b</literal>
- and this time the <literal>signal</literal> method will return, leaving the
- execution positioned in activity <literal>b</literal>.
- </para>
- <programlisting>assertEquals("b", execution.getActivityName());</programlisting>
- </section>
-
- <!-- ### BASIC PROCESS EXECUTION ######################################## -->
- <section id="basicprocessexecution">
- <title>Basic process execution</title>
- <para>In this next example, we'll combine automatic activities and wait states.
- This example builds upon the loan approval process with the <literal>WaitState</literal>
- and <literal>Display</literal> activities that we've just created. Graphically,
- the loan process looks like this:
- </para>
- <figure id="basicprocessexecution.loan.process">
- <title>The loan process</title>
- <mediaobject><imageobject><imagedata align="center" fileref="images/process.loan.png"/></imageobject></mediaobject>
- </figure>
- <para>Building process graphs in Java code can be tedious because you have to keep track of all the
- references in local variables. To resolve that, the Process Virtual Machine comes with a
- ProcessFactory. The ProcessFactory is a kind of domain specific language (DSL) that is embedded
- in Java and eases the construction of process graphs. This pattern is also known as
- a <ulink url="http://martinfowler.com/bliki/FluentInterface.html">fluent
- interface</ulink>.
- </para>
- <programlisting>ClientProcessDefinition processDefinition = ProcessFactory.build("loan")
- .activity(<emphasis role="bold">"submit loan request"</emphasis>).initial().behaviour(new Display("loan request submitted"))
- .transition().to("evaluate")
- <emphasis role="bold">.activity("evaluate").behaviour(new WaitState())</emphasis>
- .transition("approve").to("wire money")
- .transition("reject").to("end")
- <emphasis role="bold">.activity("wire money").behaviour(new Display("wire the money"))</emphasis>
- .transition().to("archive")
- <emphasis role="bold">.activity("archive").behaviour(new WaitState())</emphasis>
- .transition().to("end")
- <emphasis role="bold">.activity("end").behaviour(new WaitState())</emphasis>
-.done();</programlisting>
- <para>For more details about the ProcessFactory, see <ulink url="../../api/org/jbpm/pvm/package-summary.html">the
- api docs</ulink>. An alternative for
- the ProcessFactory would be to create an XML language and an XML parser for expressing
- processes. The XML parser can then instantiate the classes of package
- <literal>org.jbpm.pvm.internal.model</literal> directly. That approach is typically taken by
- process languages.
- </para>
- <para>The initial activity <literal>submit loan request</literal> and the activity
- <literal>wire the money</literal> are automatic activities. In this example,
- the <literal>Display</literal> implementation of activity
- <literal>wire the money</literal> uses the Java API's to just print a
- message to the console. But the witty reader can imagine an alternative
- <literal>Activity</literal> implementation that uses the Java API of a payment
- processing library to make a real automatic payment.
- </para>
- <para>A new execution for the process above can be started like this
- </para>
- <programlisting>ClientExecution execution = processDefinition.startProcessInstance();</programlisting>
- <para>When the <literal>startExecution</literal>-method returns, the activity
- <literal>submit loan request</literal> will be executed and the execution will be
- positioned in the activity <literal>evaluate</literal>.
- </para>
- <figure id="execution.loan.evaluate">
- <title>Execution positioned in the 'evaluate' activity</title>
- <mediaobject><imageobject><imagedata align="center" fileref="images/execution.loan.evaluate.png"/></imageobject></mediaobject>
- </figure>
- <para>Now, the execution is at an interesting point. There are two transitions out of
- the state <literal>evaluate</literal>. One transition is called <literal>approve</literal>
- and one transition is called <literal>reject</literal>. As we explained above, the WaitState
- implementation will take the transition that corresponds to the signal that is given.
- Let's feed in the 'approve' signal like this:
- </para>
- <programlisting>execution.signal("approve");</programlisting>
- <para>The <literal>approve</literal> signal will cause the execution to take the <literal>approve</literal>
- transition and it will arrive in the activity <literal>wire money</literal>.
- </para>
- <para>In activity <literal>wire money</literal>, the message will be printed to the console.
- Since, the <literal>Display</literal> activity didn't invoke the
- <literal>execution.waitForSignal()</literal>, nor any of the other execution propagation
- methods, the implicit proceed behaviour will just make the execution continue
- over the outgoing transition to activity <literal>archive</literal>, which is again
- a <literal>WaitState</literal>.
- </para>
- <figure id="execution.loan.archive">
- <title>Execution positioned in 'archive' activity</title>
- <mediaobject><imageobject><imagedata align="center" fileref="images/execution.loan.archive.png"/></imageobject></mediaobject>
- </figure>
- <para>So only when the <literal>archive</literal> wait state is reached,
- the <literal>signal("approve")</literal> returns.
- </para>
- <para>Another signal like this:</para>
- <programlisting>execution.signal("approve");</programlisting>
- <para>will bring the execution eventually in the end state.</para>
- <figure id="execution.loan.end">
- <title>Execution positioned in the 'end' activity</title>
- <mediaobject><imageobject><imagedata align="center" fileref="images/execution.loan.end.png"/></imageobject></mediaobject>
- </figure>
- </section>
-
- <!-- ### EVENTS ######################################################### -->
- <section id="events">
- <title>Events</title>
- <para>Events are points in the process definition to which a list of
- <literal>EventListener</literal>s can be subscribed.
- </para>
- <programlisting>public interface EventListener extends Serializable {
-
- void notify(EventListenerExecution execution) throws Exception;
-
-}</programlisting>
- <para>The motivation for events is to allow for
- developers to add programming logic to a process without changing the process diagram.
- This is a very valuable instrument in facilitating the collaboration between business analysts
- and developers. Business analysts
- are responsible for expressing the requirements. When they use a process graph to document
- those requirements, developers can take this diagram and make it executable. Events can
- be a very handy to insert technical details into a process (like e.g. some database insert)
- in which the business analyst is not interested.
- </para>
- <para>Most common events are fired by the execution automatically:
- </para>
- <para>TODO: explain events in userguide</para>
- <para>Events are identified by the combination of a process element
- and an event name. Users and process languages can also fire events
- programmatically with the fire method on the Execution:
- </para>
- <programlisting>public interface Execution extends Serializable {
- ...
- void fire(String eventName, ProcessElement eventSource);
- ...
-}</programlisting>
-
- <para>A list of <literal>EventListeners</literal> can be associated to an
- event. But event listeners can not influence the control flow of the execution since
- they are merely listeners to an execution which is already in progress. This is different from
- activities that serve as the behaviour for activities. Activity behaviour activities are responsible
- for propagating the execution.
- </para>
- <para>We'll create a <literal>PrintLn</literal> event listener which is
- very similar to the <literal>Display</literal> activity from above.
- </para>
- <programlisting>public class PrintLn implements EventListener {
-
- String message;
-
- public PrintLn(String message) {
- this.message = message;
- }
-
- public void notify(EventListenerExecution execution) throws Exception {
- System.out.println("message");
- }
-}</programlisting>
- <para>Several <literal>PrintLn</literal> listeners will be subscribed to events in
- the process.</para>
- <figure id="action.process">
- <title>The PrintLn listener process</title>
- <mediaobject><imageobject><imagedata align="center" fileref="images/process.ab.png"/></imageobject></mediaobject>
- </figure>
- <programlisting>ClientProcessDefinition processDefinition = ProcessFactory.build()
- .activity("a").initial().behaviour(new AutomaticActivity())
- <emphasis role="bold">.event("end")
- .listener(new PrintLn("leaving a"))
- .listener(new PrintLn("second message while leaving a"))</emphasis>
- .transition().to("b")
- <emphasis role="bold">.listener(new PrintLn("taking transition"))</emphasis>
- .activity("b").behaviour(new WaitState())
- .event("start")
- <emphasis role="bold">.listener(new PrintLn("entering b"))</emphasis>
-.done();</programlisting>
- <para>The first event shows how to register multiple listeners to the same
- event. They will be notified in the order as they are specified.
- </para>
- <para>Then, on the transition, there is only one type of event. So in that case,
- the event type must not be specified and the listeners can be added directly on
- the transition.
- </para>
- <para>A listeners will be called each time an execution fires the event to
- which the listener is subscribed. The execution will be provided in the activity
- interface as a parameter and can be used by listeners except for the methods that
- control the propagation of execution.
- </para>
- </section>
-
- <!-- ### EVENT PROPAGATION ############################################## -->
- <section>
- <title>Event propagation</title>
- <para>Events are by default propagated to enclosing process elements. The motivation
- is to allow for listeners on process definitions or composite activities that get executed
- for all events that occur within that process element. For example this feature
- allows to register an event listener on a process definition or a composite activity on
- <literal>end</literal> events. Such action will be executed if that activity is
- left. And if that event listener is registered on a composite activity, it will also be executed
- for all activities that are left within that composite activity.
- </para>
- <para>To show this clearly, we'll create a <literal>DisplaySource</literal> event listener
- that will print the message <literal>leaving</literal> and the source of the event
- to the console.
- </para>
- <programlisting>public class <emphasis role="bold">DisplaySource</emphasis> implements EventListener {
-
- public void execute(EventListenerExecution execution) {
- <emphasis role="bold">System.out.println("leaving "+execution.getEventSource());</emphasis>
- }
-}</programlisting>
- <para>Note that the purpose of event listeners is not to be visible, that's why the event listener
- itself should not be displayed in the diagram. A <literal>DisplaySource</literal> event listener
- will be added as a listener to the event <literal>end</literal> on the composite activity.
- </para>
- <para>The next process shows how the <literal>DisplaySource</literal> event listener is registered
- as a listener to to the 'end' event on the <literal>composite</literal> activity:</para>
- <figure id="process.propagate">
- <title>A process with an invisible event listener on a end event on a composite activity.</title>
- <mediaobject><imageobject><imagedata align="center" fileref="images/process.propagate.png"/></imageobject></mediaobject>
- </figure>
- <programlisting>TODO update code snippet</programlisting>
- <para>Next we'll start an execution.</para>
- <programlisting>ClientExecution execution = processDefinition.startProcessInstance();</programlisting>
- <para>After starting a new execution, the execution will be in activity <literal>a</literal> as
- that is the initial activity. No activities have been left so no message is logged. Next a signal
- will be given to the execution, causing it to take the transition from <literal>a</literal>
- to <literal>b</literal>.
- </para>
- <programlisting>execution.signal();</programlisting>
- <para>When the signal method returns, the execution will have taken the transition and
- the <literal>end</literal> event will be fired on activity <literal>a</literal>. That
- event will be propagated to the
- composite activity and to the process definition. Since our <literal>DisplaySource</literal>
- event listener is placed
- on the <literal>composite</literal> activity, it will receive the event and print the following
- message on the console:
- </para>
- <programlisting>leaving activity(a)</programlisting>
- <para>Another</para>
- <programlisting>execution.signal();</programlisting>
- <para>will take the transition from b to c. That will fire two activity-leave events. One on
- activity b and one on activity composite. So the following lines will be appended to the console
- output:</para>
- <programlisting>leaving activity(b)
-leaving activity(composite)</programlisting>
- <para>Event propagation is build on the hierarchical composition structure of the process
- definition. The top level element is always the process definition. The process
- definition contains a list of activities. Each activity can be a leaf activity or it can be a
- composite activity, which means that it contains a list of nested activities. Nested activities
- can be used for e.g. super states or composite activities in nested process languages like BPEL.
- </para>
- <para>So the even model also works similarly for composite activities as it did for the process
- definition above. Suppose that 'Phase one' models
- a super state as in state machines. Then event propagation allows to subscribe to all events
- within that super state. The idea is that the hierarchical composition corresponds to
- diagram representation. If an element 'e' is drawn inside another element 'p', then p
- is the parent of e. A process definition has a set of top level activities. Every activity can have
- a set of nested activities. The parent of a transition is considered as the first common
- parent for it's source and destination.
- </para>
- <para>If an event listener is not interested in propagated events, propagation can be disabled
- with <literal>propagationDisabled()</literal> while building the process with the
- <literal>ProcessFactory</literal>. The next process is the same process
- as above except that propagated events will be disabled on the event listener. The graph diagram
- remains the same.
- </para>
- <figure id="process.propagate.propagation.disabled">
- <title>A process with an event listener to 'end' events with propagation disabled.</title>
- <mediaobject><imageobject><imagedata align="center" fileref="images/process.propagate.png"/></imageobject></mediaobject>
- </figure>
- <para>Building the process with the process factory:
- </para>
- <programlisting>TODO update code snippet</programlisting>
- <para>So when the first signal is given for this process, again the <literal>end</literal>
- event will be fired on activity <literal>a</literal>, but now the event listener on the composite
- activity will not be executed cause
- propagated events have been disabled. Disabling propagation is a property on the individual
- event listener and doesn't influence the other listeners. The event will always be fired and
- propagated over the whole parent hierarchy.
- </para>
- <programlisting>ClientExecution execution = processDefinition.startProcessInstance();</programlisting>
- <para>The first signal will take the process from <literal>a</literal> to
- <literal>b</literal>. No messages will be printed to the console.
- </para>
- <programlisting>execution.signal();</programlisting>
- <para>Next, the second signal will take the transition from b to c.
- </para>
- <programlisting>execution.signal()</programlisting>
- <para>Again two <literal>end</literal>
- events are fired just like above on activities <literal>b</literal> and <literal>composite</literal>
- respectively. The first event
- is the <literal>end</literal> event on activity <literal>b</literal>. That will be propagated
- to the <literal>composite</literal> activity. So the event
- listener will not be executed for this event cause it has propagation disabled. But the
- event listener will be executed for the <literal>end</literal> event on the
- <literal>composite</literal> activity. That is not
- propagated, but fired directly on the <literal>composite</literal> activity. So the event
- listener will now be executed
- only once for the composite activity as shown in the following console output:
- </para>
- <programlisting>leaving activity(composite)</programlisting>
- </section>
-
-</chapter>
Copied: jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch06-ImplementingBasicActivities.xml (from rev 5215, jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch05-ImplementingBasicActivities.xml)
===================================================================
--- jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch06-ImplementingBasicActivities.xml (rev 0)
+++ jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch06-ImplementingBasicActivities.xml 2009-07-04 08:19:36 UTC (rev 5220)
@@ -0,0 +1,486 @@
+<chapter id="implementingbasicactivities">
+ <title>Implementing basic activities</title>
+
+ <para>This chapter explains the basics of process definitions, the features offered by
+ the Process Virtual Machine and how activity implementations can be build. At the same
+ time the client API is shown to execute processes with those activity implementations.
+ </para>
+
+ <!-- ### Activity ####################################################### -->
+ <section id="activity">
+ <title>ActivityBehaviour</title>
+ <para>The PVM library doesn't have a fixed set of process constructs.
+ Instead, runtime behaviour of a activity is delegated to an <literal>ActivityBehaviour</literal>.
+ In other words, <literal>ActivityBehaviour</literal> is an interface to implement the runtime
+ behaviour of process constructs in plain Java.
+ </para>
+ <programlisting>public <emphasis role="bold">interface ActivityBehaviour</emphasis> extends Serializable {
+
+ void <emphasis role="bold">execute</emphasis>(ActivityExecution execution) throws Exception;
+
+}</programlisting>
+ <para>When an activity behaviour is called, it is in full control of the further
+ propagation of the execution. In other words, an activity behaviour can decide what the execution
+ should do next. For example, it can take a transition with
+ <literal>execution.take(Transition)</literal> or go into a wait state with
+ <literal>execution.waitForSignal()</literal>. In case the activity behaviour does not invoke
+ any of the above execution propagation methods, the execution will
+ <link linkend="implicitproceedbehaviour">proceed in a default way</link>.
+ </para>
+ </section>
+
+ <!-- ### ActivityBehaviour example ############################################### -->
+ <section id="activitybehaviourexample">
+ <title>ActivityBehaviour example</title>
+ <para>We'll start with a very original hello world example. A Display
+ activity will print a message to the console:
+ </para>
+ <programlisting>public <emphasis role="bold">class Display</emphasis> implements <emphasis role="bold">ActivityBehaviour</emphasis> {
+
+ String message;
+
+ public Display(String message) {
+ this.message = message;
+ }
+
+ public void execute(ActivityExecution execution) {
+ <emphasis role="bold">System.out.println(message);</emphasis>
+ }
+}</programlisting>
+ <para>Let' build our first process definition with this activity:</para>
+ <figure id="activity.example">
+ <title>Display example process</title>
+ <mediaobject><imageobject><imagedata align="center" fileref="images/process.ab.png"/></imageobject></mediaobject>
+ </figure>
+ <programlisting>TODO add ProcessBuilder example code</programlisting>
+ <para>Now we can execute this process as follows:</para>
+ <programlisting>Execution execution = processDefinition.startExecution();</programlisting>
+ <para>The invocation of <literal>startExecution</literal> will print hello world to the console:</para>
+ <programlisting>hello
+world</programlisting>
+ <para>One thing already worth noticing is that activities can be configured
+ with properties. In the Display example, you can see that the message property
+ is configured differently in the two usages. With configuration properties
+ it becomes possible to write reusable activities. They can then be configured
+ differently each time they are used in a process. That is an essential part of
+ how process languages can be build on top of the Process Virtual Machine.
+ </para>
+ <para>The other part that needs explanation is that this activity
+ implementation does not contain any instructions for the propagation of the
+ execution. When a new process instance is started, the execution is positioned
+ in the initial activity and that activity is executed. The method
+ <literal>Display.execute</literal> makes use of what is called implicit propagation
+ of execution. Concretely this means that the activity itself does not
+ invoke any of the methods on the execution to propagate it. In that case
+ implicit propagation kicks in. Implicit propagation will take the first
+ transition if there is one. If not, it will end the execution. This explains
+ why both activities <literal>a</literal> and <literal>b</literal> are executed and that
+ the execution stops after activity <literal>b</literal> is executed.
+ </para>
+ <para>More details about the implicit proceed behaviour can be found
+ in <xref linkend="implicitproceedbehaviour" /></para>
+ </section>
+
+ <!-- ### ExternalActivityBehaviour ############################################### -->
+ <section id="externalactivitybehaviour">
+ <title>ExternalActivityBehaviour</title>
+ <para>External activities are activities for which the responsibility for proceeding
+ the execution is transferred externally, meaning outside the process system. This
+ means that for the system that is executing the process, it's a wait state. The
+ execution will wait until an external trigger is given.
+ </para>
+ <para>For dealing with external triggers, <literal>ExternalActivityBehaviour</literal>
+ adds one method to the <literal>ActivityBehaviour</literal>:</para>
+ <programlisting>public <emphasis role="bold">interface ExternalActivity</emphasis> extends <emphasis role="bold">Activity</emphasis> {
+
+ void <emphasis role="bold">signal</emphasis>(Execution execution,
+ String signal,
+ Map<String, Object> parameters) throws Exception;
+
+}</programlisting>
+ <para>Just like with plain activities, when an execution arrives in a activity, the
+ <literal>execute</literal>-method of the external activity behaviour is invoked.
+ In external activities, the execute method typically does something to
+ transfer the responsibility to another system and then enters a wait
+ state by invoking <literal>execution.waitForSignal()</literal>. For
+ example in the execute method, responsibility could be transferred to a
+ person by creating a task entry in a task management system and then
+ wait until the person completes the task.
+ </para>
+ <para>In case a activity behaves as a wait state, then the execution will
+ wait in that activity until the execution's <literal>signal</literal> method
+ is invoked. The execution will delegate that signal to the ExternalActivityBehaviour
+ object associated to the current activity.
+ </para>
+ <para>So the Activity's <literal>signal</literal>-method is invoked
+ when the execution receives an external trigger during the wait state. With the
+ signal method, responsibility is transferred back to the process execution. For
+ example, when a person completes a task, the task management system calls the
+ signal method on the execution.
+ </para>
+ <para>A signal can optionally have a signal name and a map of parameters. Most
+ common way on how activity behaviours interprete the signal and parameters is that
+ the signal relates to the outgoing transition that needs to be taken and that the
+ parameters are set as variables on the execution. But those are just examples, it
+ is up to the activity to use the signal and the parameters as it pleases.
+ </para>
+ </section>
+
+ <!-- ### ExternalActivity example ####################################### -->
+ <section id="externalactivityexample">
+ <title>ExternalActivity example</title>
+ <para>Here's a first example of a simple wait state implementation:
+ </para>
+ <programlisting>public <emphasis role="bold">class WaitState</emphasis> implements <emphasis role="bold">ExternalActivity</emphasis> {
+
+ public void execute(ActivityExecution execution) {
+ <emphasis role="bold">execution.waitForSignal();</emphasis>
+ }
+
+ public void signal(ActivityExecution execution,
+ String signalName,
+ Map<String, Object> parameters) {
+ <emphasis role="bold">execution.take(signalName);</emphasis>
+ }
+}</programlisting>
+ <para>The <literal>execute</literal>-method calls
+ <literal>execution.waitForSignal()</literal>. The invocation of
+ <literal>execution.waitForSignal()</literal> will bring the process execution
+ into a wait state until an external trigger is given.
+ </para>
+ <para><literal>signal</literal>-method takes the transition with
+ the signal parameter as the transition name. So when an execution receives an
+ external trigger, the signal name is interpreted as the name of an outgoing
+ transition and the execution will be propagated over that transition.
+ </para>
+ <para>Here's the same simple process that has a transition from a to b. This
+ time, the behaviour of the two activities will be WaitState's.
+ </para>
+ <figure id="process.diagram">
+ <title>The external activity example process</title>
+ <mediaobject><imageobject><imagedata align="center" fileref="images/process.ab.png"/></imageobject></mediaobject>
+ </figure>
+ <programlisting>ClientProcessDefinition processDefinition = ProcessFactory.build()
+ <emphasis role="bold">.activity("a").initial().behaviour(new WaitState())</emphasis>
+ .transition().to("b")
+ <emphasis role="bold">.activity("b").behaviour(new WaitState())</emphasis>
+.done();</programlisting>
+ <para>Let's start a new process instance for this process definition:</para>
+ <programlisting>ClientExecution execution = processDefinition.startProcessInstance();</programlisting>
+ <para>Starting this process will execute the <literal>WaitState</literal> activity
+ in activity <literal>a</literal>. <literal>WaitState.execute</literal> will invoke
+ <literal>ActivityExecution.waitForSignal</literal>. So when the
+ <literal>processDefinition.startProcessInstance()</literal> returns, the execution
+ will still be positioned in activity a.
+ </para>
+ <programlisting>assertEquals("a", execution.getActivityName());</programlisting>
+ <para>Then we provide the external trigger by calling the <literal>signal</literal>
+ method.
+ </para>
+ <programlisting>execution.signal();</programlisting>
+ <para>The <literal>execution.signal()</literal> will delegate to the activity
+ of the current activity. So in this case that is the <literal>WaitState</literal>
+ activity in activity <literal>a</literal>. The <literal>WaitState.signal</literal>
+ will invoke the <literal>ActivityExecution.take(String transitionName)</literal>.
+ Since we didn't supply a signalName, the first transition with name <literal>null</literal>
+ will be taken. The only transition we specified out of activity <literal>a</literal>
+ didn't get a name so that one will be taken. And that transition points to activity
+ <literal>b</literal>. When the execution arrives in activity <literal>b</literal>,
+ the <literal>WaitState</literal> in activity <literal>b</literal> is executed.
+ Similar as we saw above, the execution will wait in activity <literal>b</literal>
+ and this time the <literal>signal</literal> method will return, leaving the
+ execution positioned in activity <literal>b</literal>.
+ </para>
+ <programlisting>assertEquals("b", execution.getActivityName());</programlisting>
+ </section>
+
+ <!-- ### BASIC PROCESS EXECUTION ######################################## -->
+ <section id="basicprocessexecution">
+ <title>Basic process execution</title>
+ <para>In this next example, we'll combine automatic activities and wait states.
+ This example builds upon the loan approval process with the <literal>WaitState</literal>
+ and <literal>Display</literal> activities that we've just created. Graphically,
+ the loan process looks like this:
+ </para>
+ <figure id="basicprocessexecution.loan.process">
+ <title>The loan process</title>
+ <mediaobject><imageobject><imagedata align="center" fileref="images/process.loan.png"/></imageobject></mediaobject>
+ </figure>
+ <para>Building process graphs in Java code can be tedious because you have to keep track of all the
+ references in local variables. To resolve that, the Process Virtual Machine comes with a
+ ProcessFactory. The ProcessFactory is a kind of domain specific language (DSL) that is embedded
+ in Java and eases the construction of process graphs. This pattern is also known as
+ a <ulink url="http://martinfowler.com/bliki/FluentInterface.html">fluent
+ interface</ulink>.
+ </para>
+ <programlisting>ClientProcessDefinition processDefinition = ProcessFactory.build("loan")
+ .activity(<emphasis role="bold">"submit loan request"</emphasis>).initial().behaviour(new Display("loan request submitted"))
+ .transition().to("evaluate")
+ <emphasis role="bold">.activity("evaluate").behaviour(new WaitState())</emphasis>
+ .transition("approve").to("wire money")
+ .transition("reject").to("end")
+ <emphasis role="bold">.activity("wire money").behaviour(new Display("wire the money"))</emphasis>
+ .transition().to("archive")
+ <emphasis role="bold">.activity("archive").behaviour(new WaitState())</emphasis>
+ .transition().to("end")
+ <emphasis role="bold">.activity("end").behaviour(new WaitState())</emphasis>
+.done();</programlisting>
+ <para>For more details about the ProcessFactory, see <ulink url="../../api/org/jbpm/pvm/package-summary.html">the
+ api docs</ulink>. An alternative for
+ the ProcessFactory would be to create an XML language and an XML parser for expressing
+ processes. The XML parser can then instantiate the classes of package
+ <literal>org.jbpm.pvm.internal.model</literal> directly. That approach is typically taken by
+ process languages.
+ </para>
+ <para>The initial activity <literal>submit loan request</literal> and the activity
+ <literal>wire the money</literal> are automatic activities. In this example,
+ the <literal>Display</literal> implementation of activity
+ <literal>wire the money</literal> uses the Java API's to just print a
+ message to the console. But the witty reader can imagine an alternative
+ <literal>Activity</literal> implementation that uses the Java API of a payment
+ processing library to make a real automatic payment.
+ </para>
+ <para>A new execution for the process above can be started like this
+ </para>
+ <programlisting>ClientExecution execution = processDefinition.startProcessInstance();</programlisting>
+ <para>When the <literal>startExecution</literal>-method returns, the activity
+ <literal>submit loan request</literal> will be executed and the execution will be
+ positioned in the activity <literal>evaluate</literal>.
+ </para>
+ <figure id="execution.loan.evaluate">
+ <title>Execution positioned in the 'evaluate' activity</title>
+ <mediaobject><imageobject><imagedata align="center" fileref="images/execution.loan.evaluate.png"/></imageobject></mediaobject>
+ </figure>
+ <para>Now, the execution is at an interesting point. There are two transitions out of
+ the state <literal>evaluate</literal>. One transition is called <literal>approve</literal>
+ and one transition is called <literal>reject</literal>. As we explained above, the WaitState
+ implementation will take the transition that corresponds to the signal that is given.
+ Let's feed in the 'approve' signal like this:
+ </para>
+ <programlisting>execution.signal("approve");</programlisting>
+ <para>The <literal>approve</literal> signal will cause the execution to take the <literal>approve</literal>
+ transition and it will arrive in the activity <literal>wire money</literal>.
+ </para>
+ <para>In activity <literal>wire money</literal>, the message will be printed to the console.
+ Since, the <literal>Display</literal> activity didn't invoke the
+ <literal>execution.waitForSignal()</literal>, nor any of the other execution propagation
+ methods, the implicit proceed behaviour will just make the execution continue
+ over the outgoing transition to activity <literal>archive</literal>, which is again
+ a <literal>WaitState</literal>.
+ </para>
+ <figure id="execution.loan.archive">
+ <title>Execution positioned in 'archive' activity</title>
+ <mediaobject><imageobject><imagedata align="center" fileref="images/execution.loan.archive.png"/></imageobject></mediaobject>
+ </figure>
+ <para>So only when the <literal>archive</literal> wait state is reached,
+ the <literal>signal("approve")</literal> returns.
+ </para>
+ <para>Another signal like this:</para>
+ <programlisting>execution.signal("approve");</programlisting>
+ <para>will bring the execution eventually in the end state.</para>
+ <figure id="execution.loan.end">
+ <title>Execution positioned in the 'end' activity</title>
+ <mediaobject><imageobject><imagedata align="center" fileref="images/execution.loan.end.png"/></imageobject></mediaobject>
+ </figure>
+ </section>
+
+ <!-- ### EVENTS ######################################################### -->
+ <section id="events">
+ <title>Events</title>
+ <para>Events are points in the process definition to which a list of
+ <literal>EventListener</literal>s can be subscribed.
+ </para>
+ <programlisting>public interface EventListener extends Serializable {
+
+ void notify(EventListenerExecution execution) throws Exception;
+
+}</programlisting>
+ <para>The motivation for events is to allow for
+ developers to add programming logic to a process without changing the process diagram.
+ This is a very valuable instrument in facilitating the collaboration between business analysts
+ and developers. Business analysts
+ are responsible for expressing the requirements. When they use a process graph to document
+ those requirements, developers can take this diagram and make it executable. Events can
+ be a very handy to insert technical details into a process (like e.g. some database insert)
+ in which the business analyst is not interested.
+ </para>
+ <para>Most common events are fired by the execution automatically:
+ </para>
+ <para>TODO: explain events in userguide</para>
+ <para>Events are identified by the combination of a process element
+ and an event name. Users and process languages can also fire events
+ programmatically with the fire method on the Execution:
+ </para>
+ <programlisting>public interface Execution extends Serializable {
+ ...
+ void fire(String eventName, ProcessElement eventSource);
+ ...
+}</programlisting>
+
+ <para>A list of <literal>EventListeners</literal> can be associated to an
+ event. But event listeners can not influence the control flow of the execution since
+ they are merely listeners to an execution which is already in progress. This is different from
+ activities that serve as the behaviour for activities. Activity behaviour activities are responsible
+ for propagating the execution.
+ </para>
+ <para>We'll create a <literal>PrintLn</literal> event listener which is
+ very similar to the <literal>Display</literal> activity from above.
+ </para>
+ <programlisting>public class PrintLn implements EventListener {
+
+ String message;
+
+ public PrintLn(String message) {
+ this.message = message;
+ }
+
+ public void notify(EventListenerExecution execution) throws Exception {
+ System.out.println("message");
+ }
+}</programlisting>
+ <para>Several <literal>PrintLn</literal> listeners will be subscribed to events in
+ the process.</para>
+ <figure id="action.process">
+ <title>The PrintLn listener process</title>
+ <mediaobject><imageobject><imagedata align="center" fileref="images/process.ab.png"/></imageobject></mediaobject>
+ </figure>
+ <programlisting>ClientProcessDefinition processDefinition = ProcessFactory.build()
+ .activity("a").initial().behaviour(new AutomaticActivity())
+ <emphasis role="bold">.event("end")
+ .listener(new PrintLn("leaving a"))
+ .listener(new PrintLn("second message while leaving a"))</emphasis>
+ .transition().to("b")
+ <emphasis role="bold">.listener(new PrintLn("taking transition"))</emphasis>
+ .activity("b").behaviour(new WaitState())
+ .event("start")
+ <emphasis role="bold">.listener(new PrintLn("entering b"))</emphasis>
+.done();</programlisting>
+ <para>The first event shows how to register multiple listeners to the same
+ event. They will be notified in the order as they are specified.
+ </para>
+ <para>Then, on the transition, there is only one type of event. So in that case,
+ the event type must not be specified and the listeners can be added directly on
+ the transition.
+ </para>
+ <para>A listeners will be called each time an execution fires the event to
+ which the listener is subscribed. The execution will be provided in the activity
+ interface as a parameter and can be used by listeners except for the methods that
+ control the propagation of execution.
+ </para>
+ </section>
+
+ <!-- ### EVENT PROPAGATION ############################################## -->
+ <section>
+ <title>Event propagation</title>
+ <para>Events are by default propagated to enclosing process elements. The motivation
+ is to allow for listeners on process definitions or composite activities that get executed
+ for all events that occur within that process element. For example this feature
+ allows to register an event listener on a process definition or a composite activity on
+ <literal>end</literal> events. Such action will be executed if that activity is
+ left. And if that event listener is registered on a composite activity, it will also be executed
+ for all activities that are left within that composite activity.
+ </para>
+ <para>To show this clearly, we'll create a <literal>DisplaySource</literal> event listener
+ that will print the message <literal>leaving</literal> and the source of the event
+ to the console.
+ </para>
+ <programlisting>public class <emphasis role="bold">DisplaySource</emphasis> implements EventListener {
+
+ public void execute(EventListenerExecution execution) {
+ <emphasis role="bold">System.out.println("leaving "+execution.getEventSource());</emphasis>
+ }
+}</programlisting>
+ <para>Note that the purpose of event listeners is not to be visible, that's why the event listener
+ itself should not be displayed in the diagram. A <literal>DisplaySource</literal> event listener
+ will be added as a listener to the event <literal>end</literal> on the composite activity.
+ </para>
+ <para>The next process shows how the <literal>DisplaySource</literal> event listener is registered
+ as a listener to to the 'end' event on the <literal>composite</literal> activity:</para>
+ <figure id="process.propagate">
+ <title>A process with an invisible event listener on a end event on a composite activity.</title>
+ <mediaobject><imageobject><imagedata align="center" fileref="images/process.propagate.png"/></imageobject></mediaobject>
+ </figure>
+ <programlisting>TODO update code snippet</programlisting>
+ <para>Next we'll start an execution.</para>
+ <programlisting>ClientExecution execution = processDefinition.startProcessInstance();</programlisting>
+ <para>After starting a new execution, the execution will be in activity <literal>a</literal> as
+ that is the initial activity. No activities have been left so no message is logged. Next a signal
+ will be given to the execution, causing it to take the transition from <literal>a</literal>
+ to <literal>b</literal>.
+ </para>
+ <programlisting>execution.signal();</programlisting>
+ <para>When the signal method returns, the execution will have taken the transition and
+ the <literal>end</literal> event will be fired on activity <literal>a</literal>. That
+ event will be propagated to the
+ composite activity and to the process definition. Since our <literal>DisplaySource</literal>
+ event listener is placed
+ on the <literal>composite</literal> activity, it will receive the event and print the following
+ message on the console:
+ </para>
+ <programlisting>leaving activity(a)</programlisting>
+ <para>Another</para>
+ <programlisting>execution.signal();</programlisting>
+ <para>will take the transition from b to c. That will fire two activity-leave events. One on
+ activity b and one on activity composite. So the following lines will be appended to the console
+ output:</para>
+ <programlisting>leaving activity(b)
+leaving activity(composite)</programlisting>
+ <para>Event propagation is build on the hierarchical composition structure of the process
+ definition. The top level element is always the process definition. The process
+ definition contains a list of activities. Each activity can be a leaf activity or it can be a
+ composite activity, which means that it contains a list of nested activities. Nested activities
+ can be used for e.g. super states or composite activities in nested process languages like BPEL.
+ </para>
+ <para>So the even model also works similarly for composite activities as it did for the process
+ definition above. Suppose that 'Phase one' models
+ a super state as in state machines. Then event propagation allows to subscribe to all events
+ within that super state. The idea is that the hierarchical composition corresponds to
+ diagram representation. If an element 'e' is drawn inside another element 'p', then p
+ is the parent of e. A process definition has a set of top level activities. Every activity can have
+ a set of nested activities. The parent of a transition is considered as the first common
+ parent for it's source and destination.
+ </para>
+ <para>If an event listener is not interested in propagated events, propagation can be disabled
+ with <literal>propagationDisabled()</literal> while building the process with the
+ <literal>ProcessFactory</literal>. The next process is the same process
+ as above except that propagated events will be disabled on the event listener. The graph diagram
+ remains the same.
+ </para>
+ <figure id="process.propagate.propagation.disabled">
+ <title>A process with an event listener to 'end' events with propagation disabled.</title>
+ <mediaobject><imageobject><imagedata align="center" fileref="images/process.propagate.png"/></imageobject></mediaobject>
+ </figure>
+ <para>Building the process with the process factory:
+ </para>
+ <programlisting>TODO update code snippet</programlisting>
+ <para>So when the first signal is given for this process, again the <literal>end</literal>
+ event will be fired on activity <literal>a</literal>, but now the event listener on the composite
+ activity will not be executed cause
+ propagated events have been disabled. Disabling propagation is a property on the individual
+ event listener and doesn't influence the other listeners. The event will always be fired and
+ propagated over the whole parent hierarchy.
+ </para>
+ <programlisting>ClientExecution execution = processDefinition.startProcessInstance();</programlisting>
+ <para>The first signal will take the process from <literal>a</literal> to
+ <literal>b</literal>. No messages will be printed to the console.
+ </para>
+ <programlisting>execution.signal();</programlisting>
+ <para>Next, the second signal will take the transition from b to c.
+ </para>
+ <programlisting>execution.signal()</programlisting>
+ <para>Again two <literal>end</literal>
+ events are fired just like above on activities <literal>b</literal> and <literal>composite</literal>
+ respectively. The first event
+ is the <literal>end</literal> event on activity <literal>b</literal>. That will be propagated
+ to the <literal>composite</literal> activity. So the event
+ listener will not be executed for this event cause it has propagation disabled. But the
+ event listener will be executed for the <literal>end</literal> event on the
+ <literal>composite</literal> activity. That is not
+ propagated, but fired directly on the <literal>composite</literal> activity. So the event
+ listener will now be executed
+ only once for the composite activity as shown in the following console output:
+ </para>
+ <programlisting>leaving activity(composite)</programlisting>
+ </section>
+
+</chapter>
Deleted: jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch06-ProcessAnatomy.xml
===================================================================
--- jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch06-ProcessAnatomy.xml 2009-07-04 03:34:11 UTC (rev 5219)
+++ jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch06-ProcessAnatomy.xml 2009-07-04 08:19:36 UTC (rev 5220)
@@ -1,67 +0,0 @@
-<chapter id="processanatomy">
- <title>Process anatomy</title>
-
- <para>Above we already touched briefly on the two main process constructs:
- Activities, transitions and activity composition. This chapter explores in full
- all the possibilities of the process definition structures.
- </para>
-
- <para>There are basically two forms of process languages: graph based and composite
- process languages. First of all, the process supports both. Even graph based execution
- and activity composition can be used in combination to implement something like UML super states.
- Furthermore, automatic functional activities can be implemented so that they can be
- used with transitions as well as with activity composition.
- </para>
-
- <figure id="process.anatomy">
- <title>UML class diagram of the logical process structure</title>
- <mediaobject><imageobject><imagedata align="center" fileref="images/process.anatomy.classes.png"/></imageobject></mediaobject>
- </figure>
-
- <para>By separating the structure of a process from the behaviour of the activities,
- any process model can be formed in the PVM. It's up to the activity implementations
- to use this structure. Activities can also impose restrictions on the diagram
- structures they can support. Typically activities that control process concurrency
- will impose restrictions on the process model structures that they can support.
- Next we'll show a series of example diagram structures that can be formed
- with the PVM process model.
- </para>
-
- <figure id="transition">
- <title>Any two activities can be connected with a transition.</title>
- <mediaobject><imageobject><imagedata align="center" fileref="images/transition.png"/></imageobject></mediaobject>
- </figure>
-
- <figure id="self.transition">
- <title>A self transition.</title>
- <mediaobject><imageobject><imagedata align="center" fileref="images/self.transition.png"/></imageobject></mediaobject>
- </figure>
- <figure id="composite.activity">
- <title>Composite activity is a list of nested activities.</title>
- <mediaobject><imageobject><imagedata align="center" fileref="images/composite.activity.png"/></imageobject></mediaobject>
- </figure>
- <figure id="transition.into.composite">
- <title>Transition to a activity inside a composite.</title>
- <mediaobject><imageobject><imagedata align="center" fileref="images/transition.into.composite.png"/></imageobject></mediaobject>
- </figure>
- <figure id="transition.out.of.composite">
- <title>Transition from a activity inside a composite to a activity outside the composite.</title>
- <mediaobject><imageobject><imagedata align="center" fileref="images/transition.out.of.composite.png"/></imageobject></mediaobject>
- </figure>
- <figure id="transition.inheritence">
- <title>Transition of composite activities are inherited. The activity inside can take the transition of the composite activity.</title>
- <mediaobject><imageobject><imagedata align="center" fileref="images/transition.inheritence.png"/></imageobject></mediaobject>
- </figure>
- <figure id="transition.to.outer">
- <title>Transition from a activity to an outer composite.</title>
- <mediaobject><imageobject><imagedata align="center" fileref="images/transition.to.outer.png"/></imageobject></mediaobject>
- </figure>
- <figure id="transition.to.inner">
- <title>Transition from a composite activity to an inner composed activity.</title>
- <mediaobject><imageobject><imagedata align="center" fileref="images/transition.to.inner.png"/></imageobject></mediaobject>
- </figure>
- <figure id="initial.in.composite">
- <title>An initial activity inside a composite activity.</title>
- <mediaobject><imageobject><imagedata align="center" fileref="images/initial.in.composite.png"/></imageobject></mediaobject>
- </figure>
-</chapter>
\ No newline at end of file
Deleted: jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch07-ImplementingAdvancedActivities.xml
===================================================================
--- jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch07-ImplementingAdvancedActivities.xml 2009-07-04 03:34:11 UTC (rev 5219)
+++ jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch07-ImplementingAdvancedActivities.xml 2009-07-04 08:19:36 UTC (rev 5220)
@@ -1,398 +0,0 @@
-<chapter id="advancedgraphexecution">
- <title>Advanced graph execution</title>
-
- <!-- ### LOOPS ########################################################## -->
- <section>
- <title>Loops</title>
- <para>Activities can implement loops based on transitions or on activity composition.
- Loops can contain wait states.
- </para>
- <para>To support high numbers of automatic loop executions, the Process Virtual Machine
- tranformed the propagation of execution from tail recursion to a while loop.
- </para>
- </section>
-
- <!-- ### DEFAULT PROCEED BEHAVIOUR ###################################### -->
- <section id="implicitproceedbehaviour">
- <title>Implicit proceed behaviour</title>
- <para>An <literal>ActivityBehaviour</literal> can
- explicitely propagate the execution with following methods:
- </para>
- <itemizedlist>
- <listitem><literal>waitForSignal()</literal></listitem>
- <listitem><literal>take(Transition)</literal></listitem>
- <listitem><literal>end(*)</literal></listitem>
- <listitem><literal>execute(Activity)</literal></listitem>
- <listitem><literal>createExecution(*)</literal></listitem>
- </itemizedlist>
-
- <para>As a side note, some of these methods are not exposed in the
- interfaces, but only in the implementation. Those methods are still
- in 'incubation'. So if you want to use those, you can use them at your
- own risk by casting the ActivityExecution interface to the implementation
- class ExecutionImpl.
- </para>
-
- <para>When <literal>ActivityBehaviour</literal> implementations used for activity behviour
- don't call any of the following execution propagation methods, then, after
- the activity is executed, the execution will apply the implicit proceed behaviour.
- </para>
- <para>The implicit proceed behaviour is defined as follows:</para>
- <itemizedlist>
- <listitem>If the current activity has a default outgoing transition, take it.</listitem>
- <listitem>If the current activity has a parent activity, move back to the parent activity.</listitem>
- <listitem>Otherwise, end this execution.</listitem>
- </itemizedlist>
- <para>Process languages can overwrite the implicit proceed behaviour
- by overriding the <literal>proceed</literal> method in
- <literal>ExecutionImpl</literal>.
- </para>
- </section>
-
- <!-- ### FUNCTIONAL ACTIVITIES ################################ -->
- <section id="functionalactivities">
- <title>Functional activities</title>
- <para>ActivityBehaviours that also can be used as event listeners are called functional
- activities. Examples of automatic activities are sending an email, doing a database
- update, generating a pdf, calculating an average, etc. All of these are automatic
- activities that do not change the execution flow. Here's how such activities can
- be implemented:
- </para>
- <programlisting>public class FunctionalActivity implements ActivityBehaviour, EventListener {
- public void execute(ActivityExecution execution) {
- perform(execution);
- }
- public void notify(EventListenerExecution execution) {
- perform(execution);
- }
- void perform(OpenExecution execution) {
- ...do functional work...
- }
- }</programlisting>
- <para>The <literal>perform</literal> method takes an <literal>OpenExecution</literal>,
- which is the supertype of both <literal>ActivityExecution</literal> and
- <literal>EventListenerExecution</literal>. <literal>OpenExecution</literal>
- does not allow any of the specific purpose methods, but still
- the current state and the process definition can be inspected as well
- as the variables, which contain the context information for the process
- execution.
- </para>
- <para>None of these methods actually invoke execution propagation methods.
- So after the perform method is completed, the execution will
- <link linkend="implicitproceedbehaviour">proceed in the default way</link>.
- </para>
- </section>
-
-
- <!-- ### EXECUTION AND THREADS ########################################## -->
- <section id="executionandthreads">
- <title>Execution and threads</title>
- <para>This section explains how the Process Virtual Machine boroughs the thread
- from the client to bring an execution from one wait state to another.
- </para>
- <para>When a client invokes a method (like e.g. the signal method) on an execution,
- by default, the Process Virtual Machine will use that thread to progress the execution
- until it reached a wait state. Once the next wait state has been reached, the
- method returns and the client gets the thread back. This is the default way
- for the Process Virtual Machine to operate. Two more levels of asynchonous
- execution complement this default behaviour:
- <link linkend="asynchronouscontinuations">Asynchronous continuations</link>
- and in the future we'll also provide a way to invoke service methods asynchronously.
- </para>
- <para>TODO: update the example that is now commented</para>
- <!--
- <para>The next process will show the basics concretely. It has three wait states
- and four automatic activities.
- </para>
- <figure id="process.automatic">
- <title>Process with many sequential automatic activities.</title>
- <mediaobject><imageobject><imagedata align="center" fileref="images/process.automatic.png"/></imageobject></mediaobject>
- </figure>
- <para>Here's how to build the process:</para>
- <programlisting>ClientProcessDefinition processDefinition = ProcessFactory.build("automatic")
- .<emphasis role="bold">activity("wait 1").initial()</emphasis>.behaviour(new <emphasis role="bold">WaitState</emphasis>())
- .transition().to("automatic 1")
- .<emphasis role="bold">activity("automatic 1")</emphasis>.behaviour(new <emphasis role="bold">Display("one")</emphasis>)
- .transition().to("wait 2")
- .<emphasis role="bold">activity("wait 2")</emphasis>.behaviour(new <emphasis role="bold">WaitState</emphasis>())
- .transition().to("automatic 2")
- .<emphasis role="bold">activity("automatic 2")</emphasis>.behaviour(new <emphasis role="bold">Display("two")</emphasis>)
- .transition().to("automatic 3")
- .<emphasis role="bold">activity("automatic 3")</emphasis>.behaviour(new <emphasis role="bold">Display("three")</emphasis>)
- .transition().to("automatic 4")
- .<emphasis role="bold">activity("automatic 4")</emphasis>.behaviour(new <emphasis role="bold">Display("four")</emphasis>)
- .transition().to("wait 3")
- .<emphasis role="bold">activity("wait 3")</emphasis>.behaviour(new <emphasis role="bold">WaitState</emphasis>())
-.done();</programlisting>
- <para>Let's walk you through one execution of this process.
- </para>
- <programlisting>ClientExecution execution = processDefinition.startProcessInstance();</programlisting>
- <para>Starting a new execution means that the initial activity is executed. So if an automatic
- activity is the initial activity, this means that immediately the first unnamed outgoing transition
- is taken. This happens all inside of the invocation of <literal>startProcessInstance</literal>.
- </para>
- <para>In this case however, the initial activity is a wait state. So
- the method <literal>startProcessInstance</literal> returns immediately and the execution will be
- positioned in the initial activity 'wait 1'.
- </para>
- <figure id="execution.automatic.wait1">
- <title>A new execution will be positioned in 'wait 1'.</title>
- <mediaobject><imageobject><imagedata align="center" fileref="images/execution.automatic.wait1.png"/></imageobject></mediaobject>
- </figure>
- <para>Then an external trigger is given with the signal method.</para>
- <programlisting>execution.signal();</programlisting>
- <para>As explained above when <link linkend="externalactivityexample">introducing the WaitState</link>,
- that signal will cause the default transition to be taken. The
- transition will move the execution to activity <literal>automatic 1</literal> and execute it.
- The execute method of the <literal>Display</literal> activity in <literal>automatic 1</literal>
- print a line to the console and it will <emphasis role="bold">not</emphasis> call
- <literal>execution.waitForSignal()</literal>. Therefore, the execution will proceed by
- taking the default transition out of <literal>automatic 1</literal>. At this stage, the
- signal method is still blocking. Another way to think about it is that the execution
- methods like <literal>signal</literal> will use the thread of the client to interpret
- the process definition until a wait state is reached.
- </para>
- <para>Then the execution arrives in <literal>wait 2</literal> and executes
- the <literal>WaitState</literal> activity. That method will invoke
- the <literal>execution.waitForSignal()</literal>, which will cause the signal method
- to return. That is when the thread is given back to the client that invoked the
- <literal>signal</literal> method.
- </para>
- <para>So when the signal method returns, the execution is positioned in <literal>wait 2</literal>.</para>
- <figure id="execution.automatic.wait2">
- <title>One signal brought the execution from 'initial' to 'wait 2'.</title>
- <mediaobject><imageobject><imagedata align="center" fileref="images/execution.automatic.wait2.png"/></imageobject></mediaobject>
- </figure>
- <para>Then the execution is now waiting for an external trigger just as an object
- (more precisely an object graph) in memory until the next external trigger is given
- with the signal method.
- </para>
- <programlisting>execution.signal();</programlisting>
- <para>This second invocation of signal will take the execution similarly all the
- way to <literal>wait 3</literal> before it returns.
- </para>
- <figure id="automatic.wait3">
- <title>The second signal brought the execution all the way to 'wait 3'.</title>
- <mediaobject><imageobject><imagedata align="center" fileref="images/ch04.automatic.wait3.png"/></imageobject></mediaobject>
- </figure>
- -->
- <para>The benefits of using this paradigm is that the same process definition
- can be executed in <link linkend="clientexecutionmode">client execution mode</link>
- (in-memory without persistence) as well as in <link linkend="persistentexecutionmode">
- persistent execution mode</link>, depending on the application and on the environment.
- </para>
- <para>When executing a process in persistent mode, this is how you typically want
- to bind that process execution to transactions of the database:
- </para>
- <figure id="transactions.png">
- <title>Transactions over time in persistent execution mode.</title>
- <mediaobject><imageobject><imagedata align="center" fileref="images/transactions.png"/></imageobject></mediaobject>
- </figure>
- <para>In most situations, the computational work that needs to be done as part of
- the process after an external trigger (the red pieces) is pretty minimal. Typically
- transactions combining the process execution and processing the request from the
- UI takes typically less then a second. Whereas the wait state in business processes
- typically can span for hours, days or even years. The clue is to clearly distinct
- when a wait state starts so that only the computational work done before the start
- of that wait state should be included in the transaction.
- </para>
- <para>Think of
- it this way: "When an approval arrives, what are all the automated processing that
- needs to be done before the process system needs to wait for another external
- trigger?" Unless pdf's need to be generated or mass emails need to be send,
- the amount of time that this takes is usually neglectable. That is why in the
- default persistent execution mode, the process work is executed in the thread
- of the client.
- </para>
- <para>This reasoning even holds in case of concurrent paths of execution.
- When a single path of execution splits into concurrent paths of execution,
- the process overhead of calculating that is neglectable. So that is why it
- makes sense for a fork or split activity implementation that targets persistent
- execution mode to spawn the concurrent paths sequentially in the same thread.
- Basically it's all just computational work as part of the same transaction.
- This can only be done because the fork/split knows that each concurrent path
- of execution will return whenever a wait state is encountered.
- </para>
- <para>Since this is a difficult concept to grasp, I'll explain it again with other
- words. Look at it from the overhead that is produced by the process execution
- itself in persistent execution mode. If in a transaction, an execution is given
- an external trigger and that causes the execution to split into multiple concurrent
- paths of execution. Then the process overhead of calculating this is neglectable.
- Also the overhead of the generated SQL is neglectable. And since all the work done
- in the concurrent branches must be done inside that single transaction, there is
- typically no point in having fork/split implementations spawn the concurrent
- paths of execution in multiple threads.
- </para>
- <para>To make executable processes, developers need to know exactly what the automatic activities
- are, what the wait states are and which threads will be allocated to the process execution.
- For business analysts that draw the analysis process, things are a bit simpler. For the
- activities they draw, they usually know whether it's a human or a system that is responsible.
- But they typically don't not how this translates to threads and transactions.
- </para>
- <para>So for the developer, the first job is to analyse what needs to be executed
- within the thread of control of the process and what is outside. Looking for the external
- triggers can be a good start to find the wait states in a process, just like verbs and nouns
- can be the rule of thumb in building UML class diagrams.
- </para>
- </section>
-
- <!-- ### PROCESS CONCURRENCY ############################################ -->
- <section>
- <title>Process concurrency</title>
- <para>To model process concurrency, there is a parent-child tree structure on the
- execution. The idea is that the main path of execution is the root of that tree.
- The main path of execution is also called the process instance. It is the execution
- that is created when starting or creating a new process instance for a given
- process definition.
- </para>
- <para>Now, because the main path of execution is the same object as the
- process instance, this keeps the usage simple in case of simple processes
- without concurrency.
- </para>
- <figure id="execution.structure">
- <title>UML class diagram of the basic execution structure</title>
- <mediaobject><imageobject><imagedata align="center" fileref="images/class.diagram.process.execution.png"/></imageobject></mediaobject>
- </figure>
- <para>To establish multiple concurrent paths of execution, activity implementations
- like a fork or split can create child executions with method
- <literal>ActivityExecution.createExecution</literal>. Activity implementations
- like join or merge can stop these concurrent paths of execution by calling
- method <literal>stop</literal> on the concurrent execution.
- </para>
- <para>Only leaf executions can be active. Non-leave executions should be
- inactive. This tree structure of executions doesn't enforce a particular type of
- concurrency or join behaviour. It's up to the forks or and-splits and to the joins
- or and-merges to use the execution tree structure in any way they want to define
- the wanted concurrency behaviour. Here you see an example
- of concurrent executions.
- </para>
- <figure id="concurrency">
- <title>Concurrent paths of execution</title>
- <mediaobject><imageobject><imagedata align="center" fileref="images/execution.concurrency.png"/></imageobject></mediaobject>
- </figure>
- <para>There is a billing and a shipping path of execution. In this case, the
- flat bar activities represent activities that fork and join. The execution shows a three
- executions. The main path of execution is inactive (represented as gray) and the
- billing and shipping paths of execution are active and point to the activity
- <literal>bill</literal> and <literal>ship</literal> respectively.
- </para>
- <para>It's up to the activity behaviour implementations how they want to use this
- execution structure. Suppose that multiple tasks have to be completed before the
- execution is to proceed. The activity behaviour can spawn a series of child executions
- for this. Or alternatively, the task component could support task groups that
- are associated to one single execution. In that case, the task component becomes
- responsible for synchronizing the tasks, thereby moving this responsibility
- outside the scope of the execution tree structure.
- </para>
- </section>
-
- <!-- ### EXCEPTION HANDLERS ############################################# -->
- <section>
- <title>Exception handlers</title>
- <para>In all the code that is associated to a process
- like <literal>Activity</literal>s, <literal>EventListeners</literal> and
- <literal>Condition</literal>s, it's possible to associate exception handlers. This
- can be thought of as including try-catch blocks in
- the method implementations of those implementations. But in order to build more reusable building
- blocks for both the delegation classes and the exception handling logic, exception handlers are
- added to the core process model.
- </para>
- <para>An exception handler can be associated to any process element. When an exception
- occurs in a delegation class, a matching exception handler will be searched for. If
- such an exception handler is found, it will get a chance to handle the exception.
- </para>
- <para>If an exception handler completes without problems, then the exception is considered
- handled and the execution resumes right after the delegation code that was called. For example,
- a transition has three actions and the second action throws an exception that is handled
- by an exception handler, then
- </para>
- <para>Writing automatic activities that are exception handler aware is easy. The
- default is to proceed anyway. No method needs to be called on the execution. So
- if an automatic activity throws an exception that is handled by an exception handler,
- the execution will just proceed after that activity. It becomes a big more difficult
- for control flow activities. They might have to include try-finally blocks to
- invoke the proper methods on the execution before an exception handler gets a
- chance to handle the exception. For example, if an activity is a wait state and
- an exception occurs, then there is a risk that the thread jumps over the
- invocation of <literal>execution.waitForSignal()</literal>, causing the execution
- to proceed after the activity.
- </para>
- <para>TODO: exceptionhandler.isRethrowMasked</para>
- <para>TODO: transactional exception handlers</para>
- <para>TODO: we never catch errors</para>
- </section>
-
- <!-- ### PROCESS MODIFICATIONS ########################################## -->
- <section>
- <title>Process modifications</title>
- <para>TODO: process modifications</para>
- </section>
-
- <!-- ### LOCKING AND EXECUTION STATE #################################### -->
- <section>
- <title>Locking and execution state</title>
- <para>The state of an execution is either active or locked. An active
- execution is either executing or waiting for an external trigger. If an
- execution is not in <literal>STATE_ACTIVE</literal>, then it is locked.
- A locked execution is read only and cannot receive any external triggers.
- </para>
- <para>When a new execution is created, it is in STATE_ACTIVE. To change
- the state to a locked state, use lock(String). Some STATE_* constants
- are provided that represent the most commonly used locked states. But
- the state '...' in the picture indicates that any string can be provided
- as the state in the lock method.
- </para>
- <figure id="execution.states">
- <title>States of an execution</title>
- <mediaobject><imageobject><imagedata align="center" fileref="images/ch04.execution.states.png"/></imageobject></mediaobject>
- </figure>
- <para>If an execution is locked, methods that change the execution will
- throw a PvmException and the message will reference the actual locking state.
- Firing events, updating variables, updating priority and adding comments
- are not considered to change an execution. Also creation and removal of child
- executions are unchecked, which means that those methods can be invoked by
- external API clients and activity behaviour methods, even while the execution
- is in a locked state.
- </para>
- <para>Make sure that comparisons between getState() and the STATE_* constants
- are done with .equals and not with '==' because if executions are loaded
- from persistent storage, a new string is created instead of the constants.
- </para>
- <para>An execution implementation will be locked:
- </para>
- <itemizedlist>
- <listitem>When it is ended</listitem>
- <listitem>When it is suspended</listitem>
- <listitem>During asynchronous continuations</listitem>
- </itemizedlist>
- <para>Furthermore, locking can be used by Activity implementations to make
- executions read only during wait states hen responsibility for the execution is
- transferred to an external entity such as:
- </para>
- <itemizedlist>
- <listitem>A human task</listitem>
- <listitem>A service invocation</listitem>
- <listitem>A wait state that ends when a scanner detects that a file appears</listitem>
- </itemizedlist>
- <para>In these situations the strategy is that the external entity should get
- full control over the execution because it wants to control what is allowed
- and what not. To get that control, they lock the execution so that all interactions
- have to go through the external entity.
- </para>
- <para>One of the main reasons to create external entities is that they can live
- on after the execution has already proceeded. For example, in case
- of a service invocation, a timer could cause the execution to take the timeout transition.
- When the response arrives after the timeout, the service invocation entity should
- make sure it doesn't signal the execution. So the service invocation can be
- seen as a activity instance (aka activity instance) and is unique for every execution
- of the activity.
- </para>
- <para>External entities themselves are responsible for managing the execution
- lock. If the timers and client applications are consequent in addressing the
- external entities instead of the execution directly, then locking is in theory
- unnecessary. It's up to the activity behaviour implementations whether they want
- to take the overhead of locking and unlocking.
- </para>
- </section>
-
-</chapter>
Copied: jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch07-ProcessAnatomy.xml (from rev 5215, jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch06-ProcessAnatomy.xml)
===================================================================
--- jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch07-ProcessAnatomy.xml (rev 0)
+++ jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch07-ProcessAnatomy.xml 2009-07-04 08:19:36 UTC (rev 5220)
@@ -0,0 +1,67 @@
+<chapter id="processanatomy">
+ <title>Process anatomy</title>
+
+ <para>Above we already touched briefly on the two main process constructs:
+ Activities, transitions and activity composition. This chapter explores in full
+ all the possibilities of the process definition structures.
+ </para>
+
+ <para>There are basically two forms of process languages: graph based and composite
+ process languages. First of all, the process supports both. Even graph based execution
+ and activity composition can be used in combination to implement something like UML super states.
+ Furthermore, automatic functional activities can be implemented so that they can be
+ used with transitions as well as with activity composition.
+ </para>
+
+ <figure id="process.anatomy">
+ <title>UML class diagram of the logical process structure</title>
+ <mediaobject><imageobject><imagedata align="center" fileref="images/process.anatomy.classes.png"/></imageobject></mediaobject>
+ </figure>
+
+ <para>By separating the structure of a process from the behaviour of the activities,
+ any process model can be formed in the PVM. It's up to the activity implementations
+ to use this structure. Activities can also impose restrictions on the diagram
+ structures they can support. Typically activities that control process concurrency
+ will impose restrictions on the process model structures that they can support.
+ Next we'll show a series of example diagram structures that can be formed
+ with the PVM process model.
+ </para>
+
+ <figure id="transition">
+ <title>Any two activities can be connected with a transition.</title>
+ <mediaobject><imageobject><imagedata align="center" fileref="images/transition.png"/></imageobject></mediaobject>
+ </figure>
+
+ <figure id="self.transition">
+ <title>A self transition.</title>
+ <mediaobject><imageobject><imagedata align="center" fileref="images/self.transition.png"/></imageobject></mediaobject>
+ </figure>
+ <figure id="composite.activity">
+ <title>Composite activity is a list of nested activities.</title>
+ <mediaobject><imageobject><imagedata align="center" fileref="images/composite.activity.png"/></imageobject></mediaobject>
+ </figure>
+ <figure id="transition.into.composite">
+ <title>Transition to a activity inside a composite.</title>
+ <mediaobject><imageobject><imagedata align="center" fileref="images/transition.into.composite.png"/></imageobject></mediaobject>
+ </figure>
+ <figure id="transition.out.of.composite">
+ <title>Transition from a activity inside a composite to a activity outside the composite.</title>
+ <mediaobject><imageobject><imagedata align="center" fileref="images/transition.out.of.composite.png"/></imageobject></mediaobject>
+ </figure>
+ <figure id="transition.inheritence">
+ <title>Transition of composite activities are inherited. The activity inside can take the transition of the composite activity.</title>
+ <mediaobject><imageobject><imagedata align="center" fileref="images/transition.inheritence.png"/></imageobject></mediaobject>
+ </figure>
+ <figure id="transition.to.outer">
+ <title>Transition from a activity to an outer composite.</title>
+ <mediaobject><imageobject><imagedata align="center" fileref="images/transition.to.outer.png"/></imageobject></mediaobject>
+ </figure>
+ <figure id="transition.to.inner">
+ <title>Transition from a composite activity to an inner composed activity.</title>
+ <mediaobject><imageobject><imagedata align="center" fileref="images/transition.to.inner.png"/></imageobject></mediaobject>
+ </figure>
+ <figure id="initial.in.composite">
+ <title>An initial activity inside a composite activity.</title>
+ <mediaobject><imageobject><imagedata align="center" fileref="images/initial.in.composite.png"/></imageobject></mediaobject>
+ </figure>
+</chapter>
\ No newline at end of file
Deleted: jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch08-Configuration.xml
===================================================================
--- jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch08-Configuration.xml 2009-07-04 03:34:11 UTC (rev 5219)
+++ jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch08-Configuration.xml 2009-07-04 08:19:36 UTC (rev 5220)
@@ -1,118 +0,0 @@
-<chapter id="configuration">
- <title>Configuration</title>
-
- <section>
- <title>Configuration basics</title>
-
- <para>The userguide explains how to install jBPM into the most
- common runtime environments. That is the most simple and convenient
- way to get started with jBPM. Please use those instructions.
- These docs provide some background information for developers
- that want to understand more about the way how configurations are
- handled. Use at your own risk :-)
- </para>
- <para>The jbpm.jar contains a number of default configuration
- files that can be imported by the user configuration file.
- </para>
- <para>This way, it's easy to include
- or exclude features for users. And also the configuration details are kept in
- the implementation so users that only import those configuration files
- will not be affected when we release changes in those configuration files.
- </para>
- <para>Configuration files that can be imported by the user's <literal>jbpm.cfg.xml</literal>:</para>
- <itemizedlist>
- <listitem>jbpm.default.cfg.xml</listitem>
- <listitem>jbpm.identity.cfg.xml</listitem>
- <listitem>jbpm.jbossremote.cfg.xml</listitem>
- <listitem>jbpm.jobexecutor.cfg.xml</listitem>
- <listitem>jbpm.tx.hibernate.cfg.xml</listitem>
- <listitem>jbpm.tx.jta.cfg.xml</listitem>
- </itemizedlist>
- <para><literal>jbpm.default.cfg.xml</literal>: Contains the default configurations
- like the services, the hibernate configuration (configured from resource jbpm.hibernate.cfg.xml),
- hibernate session factory, business calendar and so on.
- </para>
- <para>A typical configuration for standard java would look like this:
- </para>
- <programlisting><?xml version="1.0" encoding="UTF-8"?>
-
- <jbpm-configuration>
-
- <import resource="jbpm.default.cfg.xml" />
- <import resource="jbpm.tx.hibernate.cfg.xml" />
- <import resource="jbpm.jpdl.cfg.xml" />
- <import resource="jbpm.identity.cfg.xml" />
- <import resource="jbpm.jobexecutor.cfg.xml" />
-
- </jbpm-configuration></programlisting>
-
- <para>When you want to change the configuration, first consider
- to change an import with one of the other provided importable
- configuration files.
- </para>
-
- <para>For example, in a JTA environment, replace the import of
- <literal>jbpm.tx.hibernate.cfg.xml</literal>
- with <literal>jbpm.tx.jta.cfg.xml</literal>
- </para>
-
- <para>The second way to define a more customized configuration is to
- specify configuration items directly into the <literal>jbpm.cfg.xml</literal>.
- For an example, see <xref linkend="customizingtheidentitycomponent" /> below.
- The more you customize, the more likely you are doing things we didn't
- anticipate.
- </para>
-
- <para>The jbpm.jar contains also following hibernate mapping configuration files:</para>
- <programlisting>jbpm.execution.hbm.xml
- jbpm.history.hbm.xml
- jbpm.identity.hbm.xml
- jbpm.repository.hbm.xml
- jbpm.task.hbm.xml</programlisting>
- <para>These all map the java domain model objects to a relational database.
- </para>
- <para>Other various configuration files that are included in jbpm.jar:</para>
- <programlisting>jbpm.task.lifecycle.xml
- jbpm.variable.types.xml
- jbpm.wire.bindings.xml
- jbpm.jpdl.activities.xml
- jbpm.jpdl.eventlisteners.xml</programlisting>
-
- <para>Normally it is not necessary to dive into the parsing itself. It's most
- a matter of figuring out how to specify the configuration that you want :-)
- But just in case: To get started on the parsing for the configuration files, see
- </para>
- <itemizedlist>
- <listitem>class org.jbpm.pvm.internal.env.JbpmConfigurationParser</listitem>
- <listitem>resource modules/pvm/src/main/resources/jbpm.wire.bindings.xml</listitem>
- <listitem>package modules/pvm/src/main/java/org/jbpm/pvm/internal/wire/binding</listitem>
- </itemizedlist>
- </section>
-
- <section id="customizingtheidentitycomponent">
- <title>Customizing the identity component</title>
- <para>There are 2 identity components that we support out of the box:
- </para>
- <itemizedlist>
- <listitem>jBPM's built-in identity component: ships with the jBPM project distro</listitem>
- <listitem>JBoss IDM: ships in the JBoss product platforms</listitem>
- </itemizedlist>
- <para>The <literal>jboss/build.xml</literal> installation scripts can be used
- to install jBPM in JBoss using the JBoss IDM component. There is some
- property in that build file to overwrite the default built-in identity component
- with the value for the JBoss IDM component.
- </para>
- <para>If you want to plug in your own identity component, remove the
- following line in the <literal>jbpm.cfg.xml</literal>:
- </para>
- <programlisting><import resource="jbpm.identity.cfg.xml" /></programlisting>
- <para>And in the same file, add following section</para>
- <programlisting><transaction-context>
- <object class="your.package.YourIdentitySessionImpl" />
-</transaction-context></programlisting>
- <para>YourIdentitySessionImpl should implement <literal>org.jbpm.pvm.internal.identity.spi.IdentitySession</literal>
- Making this identity pluggable is not our first target, but it was taken into the design. Let us know how it goes.
- </para>
- </section>
-
-</chapter>
\ No newline at end of file
Copied: jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch08-ImplementingAdvancedActivities.xml (from rev 5215, jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch07-ImplementingAdvancedActivities.xml)
===================================================================
--- jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch08-ImplementingAdvancedActivities.xml (rev 0)
+++ jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch08-ImplementingAdvancedActivities.xml 2009-07-04 08:19:36 UTC (rev 5220)
@@ -0,0 +1,398 @@
+<chapter id="advancedgraphexecution">
+ <title>Advanced graph execution</title>
+
+ <!-- ### LOOPS ########################################################## -->
+ <section>
+ <title>Loops</title>
+ <para>Activities can implement loops based on transitions or on activity composition.
+ Loops can contain wait states.
+ </para>
+ <para>To support high numbers of automatic loop executions, the Process Virtual Machine
+ tranformed the propagation of execution from tail recursion to a while loop.
+ </para>
+ </section>
+
+ <!-- ### DEFAULT PROCEED BEHAVIOUR ###################################### -->
+ <section id="implicitproceedbehaviour">
+ <title>Implicit proceed behaviour</title>
+ <para>An <literal>ActivityBehaviour</literal> can
+ explicitely propagate the execution with following methods:
+ </para>
+ <itemizedlist>
+ <listitem><literal>waitForSignal()</literal></listitem>
+ <listitem><literal>take(Transition)</literal></listitem>
+ <listitem><literal>end(*)</literal></listitem>
+ <listitem><literal>execute(Activity)</literal></listitem>
+ <listitem><literal>createExecution(*)</literal></listitem>
+ </itemizedlist>
+
+ <para>As a side note, some of these methods are not exposed in the
+ interfaces, but only in the implementation. Those methods are still
+ in 'incubation'. So if you want to use those, you can use them at your
+ own risk by casting the ActivityExecution interface to the implementation
+ class ExecutionImpl.
+ </para>
+
+ <para>When <literal>ActivityBehaviour</literal> implementations used for activity behviour
+ don't call any of the following execution propagation methods, then, after
+ the activity is executed, the execution will apply the implicit proceed behaviour.
+ </para>
+ <para>The implicit proceed behaviour is defined as follows:</para>
+ <itemizedlist>
+ <listitem>If the current activity has a default outgoing transition, take it.</listitem>
+ <listitem>If the current activity has a parent activity, move back to the parent activity.</listitem>
+ <listitem>Otherwise, end this execution.</listitem>
+ </itemizedlist>
+ <para>Process languages can overwrite the implicit proceed behaviour
+ by overriding the <literal>proceed</literal> method in
+ <literal>ExecutionImpl</literal>.
+ </para>
+ </section>
+
+ <!-- ### FUNCTIONAL ACTIVITIES ################################ -->
+ <section id="functionalactivities">
+ <title>Functional activities</title>
+ <para>ActivityBehaviours that also can be used as event listeners are called functional
+ activities. Examples of automatic activities are sending an email, doing a database
+ update, generating a pdf, calculating an average, etc. All of these are automatic
+ activities that do not change the execution flow. Here's how such activities can
+ be implemented:
+ </para>
+ <programlisting>public class FunctionalActivity implements ActivityBehaviour, EventListener {
+ public void execute(ActivityExecution execution) {
+ perform(execution);
+ }
+ public void notify(EventListenerExecution execution) {
+ perform(execution);
+ }
+ void perform(OpenExecution execution) {
+ ...do functional work...
+ }
+ }</programlisting>
+ <para>The <literal>perform</literal> method takes an <literal>OpenExecution</literal>,
+ which is the supertype of both <literal>ActivityExecution</literal> and
+ <literal>EventListenerExecution</literal>. <literal>OpenExecution</literal>
+ does not allow any of the specific purpose methods, but still
+ the current state and the process definition can be inspected as well
+ as the variables, which contain the context information for the process
+ execution.
+ </para>
+ <para>None of these methods actually invoke execution propagation methods.
+ So after the perform method is completed, the execution will
+ <link linkend="implicitproceedbehaviour">proceed in the default way</link>.
+ </para>
+ </section>
+
+
+ <!-- ### EXECUTION AND THREADS ########################################## -->
+ <section id="executionandthreads">
+ <title>Execution and threads</title>
+ <para>This section explains how the Process Virtual Machine boroughs the thread
+ from the client to bring an execution from one wait state to another.
+ </para>
+ <para>When a client invokes a method (like e.g. the signal method) on an execution,
+ by default, the Process Virtual Machine will use that thread to progress the execution
+ until it reached a wait state. Once the next wait state has been reached, the
+ method returns and the client gets the thread back. This is the default way
+ for the Process Virtual Machine to operate. Two more levels of asynchonous
+ execution complement this default behaviour:
+ <link linkend="asynchronouscontinuations">Asynchronous continuations</link>
+ and in the future we'll also provide a way to invoke service methods asynchronously.
+ </para>
+ <para>TODO: update the example that is now commented</para>
+ <!--
+ <para>The next process will show the basics concretely. It has three wait states
+ and four automatic activities.
+ </para>
+ <figure id="process.automatic">
+ <title>Process with many sequential automatic activities.</title>
+ <mediaobject><imageobject><imagedata align="center" fileref="images/process.automatic.png"/></imageobject></mediaobject>
+ </figure>
+ <para>Here's how to build the process:</para>
+ <programlisting>ClientProcessDefinition processDefinition = ProcessFactory.build("automatic")
+ .<emphasis role="bold">activity("wait 1").initial()</emphasis>.behaviour(new <emphasis role="bold">WaitState</emphasis>())
+ .transition().to("automatic 1")
+ .<emphasis role="bold">activity("automatic 1")</emphasis>.behaviour(new <emphasis role="bold">Display("one")</emphasis>)
+ .transition().to("wait 2")
+ .<emphasis role="bold">activity("wait 2")</emphasis>.behaviour(new <emphasis role="bold">WaitState</emphasis>())
+ .transition().to("automatic 2")
+ .<emphasis role="bold">activity("automatic 2")</emphasis>.behaviour(new <emphasis role="bold">Display("two")</emphasis>)
+ .transition().to("automatic 3")
+ .<emphasis role="bold">activity("automatic 3")</emphasis>.behaviour(new <emphasis role="bold">Display("three")</emphasis>)
+ .transition().to("automatic 4")
+ .<emphasis role="bold">activity("automatic 4")</emphasis>.behaviour(new <emphasis role="bold">Display("four")</emphasis>)
+ .transition().to("wait 3")
+ .<emphasis role="bold">activity("wait 3")</emphasis>.behaviour(new <emphasis role="bold">WaitState</emphasis>())
+.done();</programlisting>
+ <para>Let's walk you through one execution of this process.
+ </para>
+ <programlisting>ClientExecution execution = processDefinition.startProcessInstance();</programlisting>
+ <para>Starting a new execution means that the initial activity is executed. So if an automatic
+ activity is the initial activity, this means that immediately the first unnamed outgoing transition
+ is taken. This happens all inside of the invocation of <literal>startProcessInstance</literal>.
+ </para>
+ <para>In this case however, the initial activity is a wait state. So
+ the method <literal>startProcessInstance</literal> returns immediately and the execution will be
+ positioned in the initial activity 'wait 1'.
+ </para>
+ <figure id="execution.automatic.wait1">
+ <title>A new execution will be positioned in 'wait 1'.</title>
+ <mediaobject><imageobject><imagedata align="center" fileref="images/execution.automatic.wait1.png"/></imageobject></mediaobject>
+ </figure>
+ <para>Then an external trigger is given with the signal method.</para>
+ <programlisting>execution.signal();</programlisting>
+ <para>As explained above when <link linkend="externalactivityexample">introducing the WaitState</link>,
+ that signal will cause the default transition to be taken. The
+ transition will move the execution to activity <literal>automatic 1</literal> and execute it.
+ The execute method of the <literal>Display</literal> activity in <literal>automatic 1</literal>
+ print a line to the console and it will <emphasis role="bold">not</emphasis> call
+ <literal>execution.waitForSignal()</literal>. Therefore, the execution will proceed by
+ taking the default transition out of <literal>automatic 1</literal>. At this stage, the
+ signal method is still blocking. Another way to think about it is that the execution
+ methods like <literal>signal</literal> will use the thread of the client to interpret
+ the process definition until a wait state is reached.
+ </para>
+ <para>Then the execution arrives in <literal>wait 2</literal> and executes
+ the <literal>WaitState</literal> activity. That method will invoke
+ the <literal>execution.waitForSignal()</literal>, which will cause the signal method
+ to return. That is when the thread is given back to the client that invoked the
+ <literal>signal</literal> method.
+ </para>
+ <para>So when the signal method returns, the execution is positioned in <literal>wait 2</literal>.</para>
+ <figure id="execution.automatic.wait2">
+ <title>One signal brought the execution from 'initial' to 'wait 2'.</title>
+ <mediaobject><imageobject><imagedata align="center" fileref="images/execution.automatic.wait2.png"/></imageobject></mediaobject>
+ </figure>
+ <para>Then the execution is now waiting for an external trigger just as an object
+ (more precisely an object graph) in memory until the next external trigger is given
+ with the signal method.
+ </para>
+ <programlisting>execution.signal();</programlisting>
+ <para>This second invocation of signal will take the execution similarly all the
+ way to <literal>wait 3</literal> before it returns.
+ </para>
+ <figure id="automatic.wait3">
+ <title>The second signal brought the execution all the way to 'wait 3'.</title>
+ <mediaobject><imageobject><imagedata align="center" fileref="images/ch04.automatic.wait3.png"/></imageobject></mediaobject>
+ </figure>
+ -->
+ <para>The benefits of using this paradigm is that the same process definition
+ can be executed in <link linkend="clientexecutionmode">client execution mode</link>
+ (in-memory without persistence) as well as in <link linkend="persistentexecutionmode">
+ persistent execution mode</link>, depending on the application and on the environment.
+ </para>
+ <para>When executing a process in persistent mode, this is how you typically want
+ to bind that process execution to transactions of the database:
+ </para>
+ <figure id="transactions.png">
+ <title>Transactions over time in persistent execution mode.</title>
+ <mediaobject><imageobject><imagedata align="center" fileref="images/transactions.png"/></imageobject></mediaobject>
+ </figure>
+ <para>In most situations, the computational work that needs to be done as part of
+ the process after an external trigger (the red pieces) is pretty minimal. Typically
+ transactions combining the process execution and processing the request from the
+ UI takes typically less then a second. Whereas the wait state in business processes
+ typically can span for hours, days or even years. The clue is to clearly distinct
+ when a wait state starts so that only the computational work done before the start
+ of that wait state should be included in the transaction.
+ </para>
+ <para>Think of
+ it this way: "When an approval arrives, what are all the automated processing that
+ needs to be done before the process system needs to wait for another external
+ trigger?" Unless pdf's need to be generated or mass emails need to be send,
+ the amount of time that this takes is usually neglectable. That is why in the
+ default persistent execution mode, the process work is executed in the thread
+ of the client.
+ </para>
+ <para>This reasoning even holds in case of concurrent paths of execution.
+ When a single path of execution splits into concurrent paths of execution,
+ the process overhead of calculating that is neglectable. So that is why it
+ makes sense for a fork or split activity implementation that targets persistent
+ execution mode to spawn the concurrent paths sequentially in the same thread.
+ Basically it's all just computational work as part of the same transaction.
+ This can only be done because the fork/split knows that each concurrent path
+ of execution will return whenever a wait state is encountered.
+ </para>
+ <para>Since this is a difficult concept to grasp, I'll explain it again with other
+ words. Look at it from the overhead that is produced by the process execution
+ itself in persistent execution mode. If in a transaction, an execution is given
+ an external trigger and that causes the execution to split into multiple concurrent
+ paths of execution. Then the process overhead of calculating this is neglectable.
+ Also the overhead of the generated SQL is neglectable. And since all the work done
+ in the concurrent branches must be done inside that single transaction, there is
+ typically no point in having fork/split implementations spawn the concurrent
+ paths of execution in multiple threads.
+ </para>
+ <para>To make executable processes, developers need to know exactly what the automatic activities
+ are, what the wait states are and which threads will be allocated to the process execution.
+ For business analysts that draw the analysis process, things are a bit simpler. For the
+ activities they draw, they usually know whether it's a human or a system that is responsible.
+ But they typically don't not how this translates to threads and transactions.
+ </para>
+ <para>So for the developer, the first job is to analyse what needs to be executed
+ within the thread of control of the process and what is outside. Looking for the external
+ triggers can be a good start to find the wait states in a process, just like verbs and nouns
+ can be the rule of thumb in building UML class diagrams.
+ </para>
+ </section>
+
+ <!-- ### PROCESS CONCURRENCY ############################################ -->
+ <section>
+ <title>Process concurrency</title>
+ <para>To model process concurrency, there is a parent-child tree structure on the
+ execution. The idea is that the main path of execution is the root of that tree.
+ The main path of execution is also called the process instance. It is the execution
+ that is created when starting or creating a new process instance for a given
+ process definition.
+ </para>
+ <para>Now, because the main path of execution is the same object as the
+ process instance, this keeps the usage simple in case of simple processes
+ without concurrency.
+ </para>
+ <figure id="execution.structure">
+ <title>UML class diagram of the basic execution structure</title>
+ <mediaobject><imageobject><imagedata align="center" fileref="images/class.diagram.process.execution.png"/></imageobject></mediaobject>
+ </figure>
+ <para>To establish multiple concurrent paths of execution, activity implementations
+ like a fork or split can create child executions with method
+ <literal>ActivityExecution.createExecution</literal>. Activity implementations
+ like join or merge can stop these concurrent paths of execution by calling
+ method <literal>stop</literal> on the concurrent execution.
+ </para>
+ <para>Only leaf executions can be active. Non-leave executions should be
+ inactive. This tree structure of executions doesn't enforce a particular type of
+ concurrency or join behaviour. It's up to the forks or and-splits and to the joins
+ or and-merges to use the execution tree structure in any way they want to define
+ the wanted concurrency behaviour. Here you see an example
+ of concurrent executions.
+ </para>
+ <figure id="concurrency">
+ <title>Concurrent paths of execution</title>
+ <mediaobject><imageobject><imagedata align="center" fileref="images/execution.concurrency.png"/></imageobject></mediaobject>
+ </figure>
+ <para>There is a billing and a shipping path of execution. In this case, the
+ flat bar activities represent activities that fork and join. The execution shows a three
+ executions. The main path of execution is inactive (represented as gray) and the
+ billing and shipping paths of execution are active and point to the activity
+ <literal>bill</literal> and <literal>ship</literal> respectively.
+ </para>
+ <para>It's up to the activity behaviour implementations how they want to use this
+ execution structure. Suppose that multiple tasks have to be completed before the
+ execution is to proceed. The activity behaviour can spawn a series of child executions
+ for this. Or alternatively, the task component could support task groups that
+ are associated to one single execution. In that case, the task component becomes
+ responsible for synchronizing the tasks, thereby moving this responsibility
+ outside the scope of the execution tree structure.
+ </para>
+ </section>
+
+ <!-- ### EXCEPTION HANDLERS ############################################# -->
+ <section>
+ <title>Exception handlers</title>
+ <para>In all the code that is associated to a process
+ like <literal>Activity</literal>s, <literal>EventListeners</literal> and
+ <literal>Condition</literal>s, it's possible to associate exception handlers. This
+ can be thought of as including try-catch blocks in
+ the method implementations of those implementations. But in order to build more reusable building
+ blocks for both the delegation classes and the exception handling logic, exception handlers are
+ added to the core process model.
+ </para>
+ <para>An exception handler can be associated to any process element. When an exception
+ occurs in a delegation class, a matching exception handler will be searched for. If
+ such an exception handler is found, it will get a chance to handle the exception.
+ </para>
+ <para>If an exception handler completes without problems, then the exception is considered
+ handled and the execution resumes right after the delegation code that was called. For example,
+ a transition has three actions and the second action throws an exception that is handled
+ by an exception handler, then
+ </para>
+ <para>Writing automatic activities that are exception handler aware is easy. The
+ default is to proceed anyway. No method needs to be called on the execution. So
+ if an automatic activity throws an exception that is handled by an exception handler,
+ the execution will just proceed after that activity. It becomes a big more difficult
+ for control flow activities. They might have to include try-finally blocks to
+ invoke the proper methods on the execution before an exception handler gets a
+ chance to handle the exception. For example, if an activity is a wait state and
+ an exception occurs, then there is a risk that the thread jumps over the
+ invocation of <literal>execution.waitForSignal()</literal>, causing the execution
+ to proceed after the activity.
+ </para>
+ <para>TODO: exceptionhandler.isRethrowMasked</para>
+ <para>TODO: transactional exception handlers</para>
+ <para>TODO: we never catch errors</para>
+ </section>
+
+ <!-- ### PROCESS MODIFICATIONS ########################################## -->
+ <section>
+ <title>Process modifications</title>
+ <para>TODO: process modifications</para>
+ </section>
+
+ <!-- ### LOCKING AND EXECUTION STATE #################################### -->
+ <section>
+ <title>Locking and execution state</title>
+ <para>The state of an execution is either active or locked. An active
+ execution is either executing or waiting for an external trigger. If an
+ execution is not in <literal>STATE_ACTIVE</literal>, then it is locked.
+ A locked execution is read only and cannot receive any external triggers.
+ </para>
+ <para>When a new execution is created, it is in STATE_ACTIVE. To change
+ the state to a locked state, use lock(String). Some STATE_* constants
+ are provided that represent the most commonly used locked states. But
+ the state '...' in the picture indicates that any string can be provided
+ as the state in the lock method.
+ </para>
+ <figure id="execution.states">
+ <title>States of an execution</title>
+ <mediaobject><imageobject><imagedata align="center" fileref="images/ch04.execution.states.png"/></imageobject></mediaobject>
+ </figure>
+ <para>If an execution is locked, methods that change the execution will
+ throw a PvmException and the message will reference the actual locking state.
+ Firing events, updating variables, updating priority and adding comments
+ are not considered to change an execution. Also creation and removal of child
+ executions are unchecked, which means that those methods can be invoked by
+ external API clients and activity behaviour methods, even while the execution
+ is in a locked state.
+ </para>
+ <para>Make sure that comparisons between getState() and the STATE_* constants
+ are done with .equals and not with '==' because if executions are loaded
+ from persistent storage, a new string is created instead of the constants.
+ </para>
+ <para>An execution implementation will be locked:
+ </para>
+ <itemizedlist>
+ <listitem>When it is ended</listitem>
+ <listitem>When it is suspended</listitem>
+ <listitem>During asynchronous continuations</listitem>
+ </itemizedlist>
+ <para>Furthermore, locking can be used by Activity implementations to make
+ executions read only during wait states hen responsibility for the execution is
+ transferred to an external entity such as:
+ </para>
+ <itemizedlist>
+ <listitem>A human task</listitem>
+ <listitem>A service invocation</listitem>
+ <listitem>A wait state that ends when a scanner detects that a file appears</listitem>
+ </itemizedlist>
+ <para>In these situations the strategy is that the external entity should get
+ full control over the execution because it wants to control what is allowed
+ and what not. To get that control, they lock the execution so that all interactions
+ have to go through the external entity.
+ </para>
+ <para>One of the main reasons to create external entities is that they can live
+ on after the execution has already proceeded. For example, in case
+ of a service invocation, a timer could cause the execution to take the timeout transition.
+ When the response arrives after the timeout, the service invocation entity should
+ make sure it doesn't signal the execution. So the service invocation can be
+ seen as a activity instance (aka activity instance) and is unique for every execution
+ of the activity.
+ </para>
+ <para>External entities themselves are responsible for managing the execution
+ lock. If the timers and client applications are consequent in addressing the
+ external entities instead of the execution directly, then locking is in theory
+ unnecessary. It's up to the activity behaviour implementations whether they want
+ to take the overhead of locking and unlocking.
+ </para>
+ </section>
+
+</chapter>
Copied: jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch09-Configuration.xml (from rev 5215, jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch08-Configuration.xml)
===================================================================
--- jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch09-Configuration.xml (rev 0)
+++ jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch09-Configuration.xml 2009-07-04 08:19:36 UTC (rev 5220)
@@ -0,0 +1,118 @@
+<chapter id="configuration">
+ <title>Configuration</title>
+
+ <section>
+ <title>Configuration basics</title>
+
+ <para>The userguide explains how to install jBPM into the most
+ common runtime environments. That is the most simple and convenient
+ way to get started with jBPM. Please use those instructions.
+ These docs provide some background information for developers
+ that want to understand more about the way how configurations are
+ handled. Use at your own risk :-)
+ </para>
+ <para>The jbpm.jar contains a number of default configuration
+ files that can be imported by the user configuration file.
+ </para>
+ <para>This way, it's easy to include
+ or exclude features for users. And also the configuration details are kept in
+ the implementation so users that only import those configuration files
+ will not be affected when we release changes in those configuration files.
+ </para>
+ <para>Configuration files that can be imported by the user's <literal>jbpm.cfg.xml</literal>:</para>
+ <itemizedlist>
+ <listitem>jbpm.default.cfg.xml</listitem>
+ <listitem>jbpm.identity.cfg.xml</listitem>
+ <listitem>jbpm.jbossremote.cfg.xml</listitem>
+ <listitem>jbpm.jobexecutor.cfg.xml</listitem>
+ <listitem>jbpm.tx.hibernate.cfg.xml</listitem>
+ <listitem>jbpm.tx.jta.cfg.xml</listitem>
+ </itemizedlist>
+ <para><literal>jbpm.default.cfg.xml</literal>: Contains the default configurations
+ like the services, the hibernate configuration (configured from resource jbpm.hibernate.cfg.xml),
+ hibernate session factory, business calendar and so on.
+ </para>
+ <para>A typical configuration for standard java would look like this:
+ </para>
+ <programlisting><?xml version="1.0" encoding="UTF-8"?>
+
+ <jbpm-configuration>
+
+ <import resource="jbpm.default.cfg.xml" />
+ <import resource="jbpm.tx.hibernate.cfg.xml" />
+ <import resource="jbpm.jpdl.cfg.xml" />
+ <import resource="jbpm.identity.cfg.xml" />
+ <import resource="jbpm.jobexecutor.cfg.xml" />
+
+ </jbpm-configuration></programlisting>
+
+ <para>When you want to change the configuration, first consider
+ to change an import with one of the other provided importable
+ configuration files.
+ </para>
+
+ <para>For example, in a JTA environment, replace the import of
+ <literal>jbpm.tx.hibernate.cfg.xml</literal>
+ with <literal>jbpm.tx.jta.cfg.xml</literal>
+ </para>
+
+ <para>The second way to define a more customized configuration is to
+ specify configuration items directly into the <literal>jbpm.cfg.xml</literal>.
+ For an example, see <xref linkend="customizingtheidentitycomponent" /> below.
+ The more you customize, the more likely you are doing things we didn't
+ anticipate.
+ </para>
+
+ <para>The jbpm.jar contains also following hibernate mapping configuration files:</para>
+ <programlisting>jbpm.execution.hbm.xml
+ jbpm.history.hbm.xml
+ jbpm.identity.hbm.xml
+ jbpm.repository.hbm.xml
+ jbpm.task.hbm.xml</programlisting>
+ <para>These all map the java domain model objects to a relational database.
+ </para>
+ <para>Other various configuration files that are included in jbpm.jar:</para>
+ <programlisting>jbpm.task.lifecycle.xml
+ jbpm.variable.types.xml
+ jbpm.wire.bindings.xml
+ jbpm.jpdl.activities.xml
+ jbpm.jpdl.eventlisteners.xml</programlisting>
+
+ <para>Normally it is not necessary to dive into the parsing itself. It's most
+ a matter of figuring out how to specify the configuration that you want :-)
+ But just in case: To get started on the parsing for the configuration files, see
+ </para>
+ <itemizedlist>
+ <listitem>class org.jbpm.pvm.internal.env.JbpmConfigurationParser</listitem>
+ <listitem>resource modules/pvm/src/main/resources/jbpm.wire.bindings.xml</listitem>
+ <listitem>package modules/pvm/src/main/java/org/jbpm/pvm/internal/wire/binding</listitem>
+ </itemizedlist>
+ </section>
+
+ <section id="customizingtheidentitycomponent">
+ <title>Customizing the identity component</title>
+ <para>There are 2 identity components that we support out of the box:
+ </para>
+ <itemizedlist>
+ <listitem>jBPM's built-in identity component: ships with the jBPM project distro</listitem>
+ <listitem>JBoss IDM: ships in the JBoss product platforms</listitem>
+ </itemizedlist>
+ <para>The <literal>jboss/build.xml</literal> installation scripts can be used
+ to install jBPM in JBoss using the JBoss IDM component. There is some
+ property in that build file to overwrite the default built-in identity component
+ with the value for the JBoss IDM component.
+ </para>
+ <para>If you want to plug in your own identity component, remove the
+ following line in the <literal>jbpm.cfg.xml</literal>:
+ </para>
+ <programlisting><import resource="jbpm.identity.cfg.xml" /></programlisting>
+ <para>And in the same file, add following section</para>
+ <programlisting><transaction-context>
+ <object class="your.package.YourIdentitySessionImpl" />
+</transaction-context></programlisting>
+ <para>YourIdentitySessionImpl should implement <literal>org.jbpm.pvm.internal.identity.spi.IdentitySession</literal>
+ Making this identity pluggable is not our first target, but it was taken into the design. Let us know how it goes.
+ </para>
+ </section>
+
+</chapter>
\ No newline at end of file
Property changes on: jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch09-Configuration.xml
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Deleted: jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch09-Persistence.xml
===================================================================
--- jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch09-Persistence.xml 2009-07-04 03:34:11 UTC (rev 5219)
+++ jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch09-Persistence.xml 2009-07-04 08:19:36 UTC (rev 5220)
@@ -1,25 +0,0 @@
-<chapter id="persistence">
- <title>Persistence</title>
-
- <para>Currently jBPM's persistence is based on hibernate. But in the future we might
- switch to JPA. That is why we recommend to stick with the API as much as possible as
- the API will hide you from those changes.
- </para>
-
- <para>Here's the jBPM database schema in an ER diagram. Thanks to
- <ulink url="http://dev.mysql.com/workbench/">MySQL Workbench></ulink>.
- </para>
-
- <figure id="schema ">
- <title>The jBPM Schema ER Diagram</title>
- <mediaobject><imageobject><imagedata align="center" fileref="images/jbpm.erd.png"/></imageobject></mediaobject>
- </figure>
-
-
- <para>TODO: hibernate-session and the standard transaction
- </para>
-
- <para>TODO: process definition caching
- </para>
-
-</chapter>
\ No newline at end of file
Deleted: jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch10-JobExecutor.xml
===================================================================
--- jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch10-JobExecutor.xml 2009-07-04 03:34:11 UTC (rev 5219)
+++ jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch10-JobExecutor.xml 2009-07-04 08:19:36 UTC (rev 5220)
@@ -1,135 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<chapter id="jobexecutor">
- <title>JobExecutor</title>
-
- <para>
- For jPDL features like asynchronous continuations and timers, jBPM
- relies on transactional asynchronous messaging and transactional
- timers. Those are not available on the standard Java platform.
- Therefore, jBPM includes the JobExecutor component, which executes
- asynchronous messages and timers in any (potentially clustered)
- environment.
- </para>
-
- <section id="overview">
- <title>Overview</title>
- <para>
- By default, when calling a jBPM service operation (eg. TaskService,
- ExecutionService, etc.), the jBPM logic is executed on the same thread
- as where the call came from. In most cases, this is sufficient since
- most steps in a process don't take much time. This means that
- signalling a process instance from one wait state to another, passing
- by several other steps in the business process, can be done in one
- transaction.
- </para>
- <para>
- However, in some occasions business processes can be made more efficient by
- introducing asynchronous continuations. By marking an activity as
- asynchronous, the jBPM engine will take care that the logic
- encapsulated in the activity isn't executed on the thread of the
- caller, but on a separate dedicated thread. The same mechanism is used
- for timers and asynchronous mailing (which means mails will be sent
- later, in a separate thread). The following picture shows which components
- come into play when using this mechanism.
- </para>
- <figure id="jobexecutor.overview.image">
- <title>JobExecutor components overview</title>
- <mediaobject><imageobject><imagedata align="center" fileref="images/jobexecutor.overview.png"/></imageobject></mediaobject>
- </figure>
- <para>
- When using timers or asynchronous continuations in a business process, the
- jBPM engine will store a 'job' into the database (a job contains mainly a
- duedate and continuation logic). Do note that this mechanism is
- pluggable, which means that in the future other destinations could be
- used (JMS, JCR, etc).
- </para>
- <para>
- Now the JobExecutor comes in to play, which is in fact a manager
- for several subcomponents:
-
- <itemizedlist>
- <listitem>
- A <emphasis role="bold">shared BlockingQueue</emphasis>,
- which is used to temporary store job identifiers of jobs which
- are executable (eg duedate is passed).
- </listitem>
- <listitem>
- Every JobExecutor has one <emphasis role="bold">DispatcherThread.</emphasis>
- This thread will query the database for 'acquirable jobs' (eg timers
- which duedate is passed), using a dedicated command through the CommandService.
- Since the dispatcher uses the CommandService, the command is
- automatically made transactional and wrapped by the configured
- interceptors. As long as jobs are available the dispatcher will put
- job identifiers on the shared queue, until the queue is either full
- (the thread will automatically be blocked by the JVM until a slot is
- free) or until no new jobs can be found in the database. If the latter
- case, the dispatcher will wait for a configured time (ie the 'idle
- time').
- </listitem>
- <listitem>
- The JobExecutor also maintains a pool of
- <emphasis role="bold">JobExecutorThreads</emphasis>. The number of
- JobExecutorThreads can be configured and influences the size of the
- shared queue. Every one of the JobExecutorThreads will try to take a
- jobId from the queue. The shared queue implementation is guaranteed to
- block the JobexecutorThread until a queue slot is filled and the new
- job id will be passed to exactly one waiting JobexecutorThread.
- After taking a job id from the queue, the job is transactionally
- executed using a dedicated command through the CommandService. This
- means that the job logic will completely be executed on the
- JobExecutorThread, instead of the default calling thread. This also
- means that the order in which the jobs are executed is unknown since
- there could be multiple competing JobExecutorThreads, but it
- is certain that only one job per transaction will be done (unless using
- 'exclusive jobs' - in this case all exclusive jobs are sequentially
- executed).
- </listitem>
- </itemizedlist>
- </para>
-
- </section>
-
- <section id="configuration">
- <title>Configuration</title>
- <para>
- Enabling the jobExecutor is very easy by adding the following line to the
- jbpm.cfg.xml file (using default settings):
- </para>
- <programlisting>
- <import resource="jbpm.jobexecutor.cfg.xml" />
- </programlisting>
- <para>
- Additional attributes can be set to fine-tune the JobExecutor:
- <itemizedlist>
- <listitem>
- <emphasis role="bold">threads:</emphasis> defines the number of
- JobexecutorThreads (default 3 threads)
- </listitem>
- <listitem>
- <emphasis role="bold">idle:</emphasis> number of milliseconds the dispatcher
- component waits after no new jobs were found in the database (default 5 seconds)
- </listitem>
- <listitem>
- <emphasis role="bold">idle-max:</emphasis> each time an exception occurs,
- the idle period will be doubled until the 'idle-max' is reached
- (back-off mechanism used to avoid a constant load on a failing database)
- </listitem>
- <listitem>
- <emphasis role="bold">lock-millis:</emphasis> Number of milliseconds
- that a job will be locked after being acquired by the dispatcher.
- This prevents starvation in case one of more JobExecutorThreads would die
- (eg when used in a cluster).
- </listitem>
- </itemizedlist>
- <programlisting>
-
- <process-engine-context>
-
- <job-executor threads="4" idle="15000" idle-max="60000" lock-millis="3600000" />
-
- </process-engine-context>
- </programlisting>
- </para>
- </section>
-
-</chapter>
Copied: jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch10-Persistence.xml (from rev 5215, jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch09-Persistence.xml)
===================================================================
--- jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch10-Persistence.xml (rev 0)
+++ jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch10-Persistence.xml 2009-07-04 08:19:36 UTC (rev 5220)
@@ -0,0 +1,25 @@
+<chapter id="persistence">
+ <title>Persistence</title>
+
+ <para>Currently jBPM's persistence is based on hibernate. But in the future we might
+ switch to JPA. That is why we recommend to stick with the API as much as possible as
+ the API will hide you from those changes.
+ </para>
+
+ <para>Here's the jBPM database schema in an ER diagram. Thanks to
+ <ulink url="http://dev.mysql.com/workbench/">MySQL Workbench></ulink>.
+ </para>
+
+ <figure id="schema ">
+ <title>The jBPM Schema ER Diagram</title>
+ <mediaobject><imageobject><imagedata align="center" fileref="images/jbpm.erd.png"/></imageobject></mediaobject>
+ </figure>
+
+
+ <para>TODO: hibernate-session and the standard transaction
+ </para>
+
+ <para>TODO: process definition caching
+ </para>
+
+</chapter>
\ No newline at end of file
Deleted: jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch11-AdvancedEmail.xml
===================================================================
--- jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch11-AdvancedEmail.xml 2009-07-04 03:34:11 UTC (rev 5219)
+++ jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch11-AdvancedEmail.xml 2009-07-04 08:19:36 UTC (rev 5220)
@@ -1,196 +0,0 @@
-<chapter id="mailsupport">
- <title>Advanced Mail Support</title>
- <para>jBPM 4 takes advantage of the JavaMail API to make high-level email
- services available to business process authors.</para>
-
- <section id="mailproducers">
- <title>Producers</title>
- <para>Producers are responsible for creating email messages within jBPM. All mail producers
- implement the <literal>org.jbpm.pvm.internal.email.spi.MailProducer</literal> interface.
- A default mail producer is available out of the box to address typical email needs.</para>
-
- <section id="defaultmailproducer">
- <title>Default Producer</title>
- <para>The default mail producer is capable of creating email messages with text,
- HTML and attachments from a template. Templates can be provided inline or
- in the process-engine-context section of the jBPM configuration. Templates
- may contain expressions which are evaluated through the script manager.
- </para>
- <para>The following listing presents a mail activity with an inline template.</para>
- <programlisting><![CDATA[<mail name="rectify" language="juel"> (1)
- <from addresses='winston@minitrue' /> (2)
- <to addresses='julia@minitrue, obrien@miniluv'/> (3)
- <cc users='bigbrother'/>
- <bcc groups='thinkpol, innerparty'/>
- <subject>Part ${part} Chapter ${chapter}</subject> (4)
- <text>times ${date} reporting bb dayorder doubleplusungood (5)
- refs ${unpersons} rewrite fullwise upsub antefiling</text>
- <html><table><tr><td>times</td><td>${date}</td> (6)
- <td>reporting bb dayorder doubleplusungood
- refs ${unpersons} rewrite fullwise upsub antefiling</td>
- </tr></table></html>
- <attachments> (7)
- <attachment url='http://www.george-orwell.org/1984/3.html'/>
- <attachment resource='org/example/pic.jpg'/>
- <attachment file='${user.home}/.face'/>
- </attachments>
-</mail>]]></programlisting>
- <orderedlist>
- <listitem><para>Expressions within the template are written in the scripting language
- indicated here. If not specified, the default expression language will be assumed.
- </para></listitem>
- <listitem><para>List of message senders. Senders are either identified directly by
- their email addresses or appointed by means of the identity model.</para></listitem>
- <listitem><para>Lists of message recipients, categorized as follows: <emphasis>To</emphasis>
- (primary), <emphasis>CC</emphasis> (carbon copy) and <emphasis>BCC</emphasis> (blind
- carbon copy). Like senders, recipients are directly identified by their email addresses
- or appointed by means of the identity model.</para></listitem>
- <listitem><para>Character data contained in element <literal>subject</literal>
- are used as the message subject.</para></listitem>
- <listitem><para>Character data contained in element <literal>text</literal>
- are used as the plain text content of the message.</para></listitem>
- <listitem><para>Nodes contained in element <literal>html</literal>
- are used as the HTML content of the message.</para></listitem>
- <listitem><para>Attachments can be specified as absolute URLs,
- classpath resources or local files.</para></listitem>
- </orderedlist>
- <para>Note that every section of the template is amenable to expression evaluation.</para>
- </section>
- <para>For complex emails or custom generation of attachments, see: <link
- linkend="customemails">Extension Points: Custom Emails</link>.</para>
- </section>
-
- <section id="mailtemplates">
- <title>Templates</title>
- <para>Mail templates are available to externalize commonly used messages from process definitions.
- Templates are placed in the process-engine-context section of your configuration file. All elements
- available to inline templates, as described in the <link linkend="defaultmailproducer">previous
- section</link> are available to external templates. Consider the fragment below.</para>
- <programlisting><![CDATA[<jbpm-configuration>
-<process-engine-context>
- <mail-template name="rectify-template">
- <!-- same elements as inline template -->
- </mail-template>
-</process-engine-context>
-</jbpm-configuration>]]></programlisting>
- <para>Each template must have an unique name. Mail activities may reference the template
- through the <literal>template</literal> attribute, as follows.</para>
- <programlisting><![CDATA[<mail name="rectify" template="rectify-template />]]></programlisting>
- </section>
-
- <section id="mailservers">
- <title>Servers</title>
- <para>Mail servers are declared in the configuration file. The <literal>mail-server</literal>
- element describes an SMTP mail server capable of sending email messages.
- Because jBPM uses JavaMail to send mail, all properties supported by JavaMail are also
- exposed to jBPM. Within the <literal>session-properties</literal> child element,
- the SMTP properties must be provided as shown in the example below.</para>
- <para>See the Sun JavaMail API for more information on supported properties:
- <ulink url="http://java.sun.com/products/javamail/javadocs/com/sun/mail/smtp/package-...">
- Sun SMTP Properties</ulink>.</para>
- <programlisting><![CDATA[<jbpm-configuration>
-<transaction-context>
- <mail-session>
- <mail-server>
- <session-properties>
- <property name="mail.smtp.host" value="localhost" />
- <property name="mail.smtp.port" value="2525" />
- <property name="mail.from" value="noreply(a)jbpm.org" />
- </session-properties>
- </mail-server>
- </mail-session>
-</transaction-context>
-</jbpm-configuration>]]></programlisting>
- <para>If the "From" attribute is not present in an outgoing message, the value of the
- <literal>mail.from</literal> property will be used instead.</para>
-
- <section id="multiplemailservers">
- <title>Multiple Servers</title>
- <para>Multiple SMTP server support has been added to jBPM 4 to accommodate a wider
- variety of organizational server structures. For example, this is useful for companies
- that have both internal and external SMTP servers.</para>
- <para>To setup multiple SMTP mail servers, declare multiple mail servers within the
- configuration file, as described below. The tag <literal>address-filter</literal> exists
- to define which domains are serviced by each mail server. The address filter consists
- of regular expressions that determine whether an address will be processed by a given
- server.</para>
- <para>See the Sun Pattern API for more information on supported regular expressions:
- <ulink url="http://java.sun.com/j2se/1.5.0/docs/api/java/util/regex/Pattern.html">
- Sun Regex Patterns</ulink>.</para>
- <programlisting><![CDATA[<jbpm-configuration>
-<transaction-context>
- <mail-session>
- <mail-server>
- <address-filter>
- <include>.+(a)jbpm.org</include>
- </address-filter>
- <session-properties>
- <property name="mail.smtp.host" value="int.smtp.jbpm.org" />
- <property name="mail.from" value="noreply(a)jbpm.org" />
- </session-properties>
- </mail-server>
- <mail-server>
- <address-filter>
- <exclude>.+(a)jbpm.org</exclude>
- </address-filter>
- <session-properties>
- <property name="mail.smtp.host" value="ext.smtp.jbpm.org" />
- <property name="mail.from" value="noreply(a)jbpm.org" />
- </session-properties>
- </mail-server>
- </mail-session>
-</transaction-context>
-</jbpm-configuration>]]></programlisting>
- <para>Address filters follow the logic below to accept an address.</para>
- <itemizedlist>
- <listitem><para>Address is accepted if it is <emphasis>included</emphasis> and
- <emphasis>not excluded</emphasis>.</para></listitem>
- <listitem><para>Absence of includes implies the address is
- <emphasis>included</emphasis>.</para></listitem>
- <listitem><para>Absence of excludes implies the address is
- <emphasis>not excluded</emphasis>.</para></listitem>
- </itemizedlist>
- </section>
- </section>
-
- <section id="extensibility">
- <title>Extension Points</title>
-
- <section id="customproducers">
- <title>Custom Producers</title>
- <para>jBPM 4 allows the creation of your own Mail Producers to address an organization's
- specific email needs. To do so, users must implement the
- <literal>org.jbpm.pvm.internal.email.spi.MailProducer</literal> interface. The method
- <literal>produce</literal> will return one or more <literal>Message</literal> objects,
- which will be sent through the <literal>MailSession</literal>.</para>
-
- <section id="custom attachments">
- <title>Example: Custom Attachments</title>
- <para>Generation of custom attachments at runtime can be easily implemented in jBPM 4.
- By extending the default mail producer, or implementing your own with the
- <literal>MailProducer</literal> interface, attachments can be generated and
- added to email messages at runtime.</para>
- <para>The following is an example of how to extend <literal>MailProducerImpl</literal>
- to add an extra attachment to every outgoing mail.</para>
- <programlisting><![CDATA[public class CustomMailProducer extends MailProducerImpl {
-
- protected void addAttachments(Execution execution, Multipart multipart) {
- // have default mail producer create attachments from template
- super.addAttachments(execution, multipart);
-
- // create a body part to carry the content
- BodyPart attachmentPart = new MimeBodyPart();
-
- // set content provided by an arbitrary data handler
- attachmentPart.setDataHandler(...);
-
- // attach content
- multipart.addBodyPart(attachmentPart);
- }
-}]]></programlisting>
- </section>
- </section>
-
- </section>
-
-</chapter>
\ No newline at end of file
Copied: jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch11-JobExecutor.xml (from rev 5215, jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch10-JobExecutor.xml)
===================================================================
--- jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch11-JobExecutor.xml (rev 0)
+++ jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch11-JobExecutor.xml 2009-07-04 08:19:36 UTC (rev 5220)
@@ -0,0 +1,135 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<chapter id="jobexecutor">
+ <title>JobExecutor</title>
+
+ <para>
+ For jPDL features like asynchronous continuations and timers, jBPM
+ relies on transactional asynchronous messaging and transactional
+ timers. Those are not available on the standard Java platform.
+ Therefore, jBPM includes the JobExecutor component, which executes
+ asynchronous messages and timers in any (potentially clustered)
+ environment.
+ </para>
+
+ <section id="overview">
+ <title>Overview</title>
+ <para>
+ By default, when calling a jBPM service operation (eg. TaskService,
+ ExecutionService, etc.), the jBPM logic is executed on the same thread
+ as where the call came from. In most cases, this is sufficient since
+ most steps in a process don't take much time. This means that
+ signalling a process instance from one wait state to another, passing
+ by several other steps in the business process, can be done in one
+ transaction.
+ </para>
+ <para>
+ However, in some occasions business processes can be made more efficient by
+ introducing asynchronous continuations. By marking an activity as
+ asynchronous, the jBPM engine will take care that the logic
+ encapsulated in the activity isn't executed on the thread of the
+ caller, but on a separate dedicated thread. The same mechanism is used
+ for timers and asynchronous mailing (which means mails will be sent
+ later, in a separate thread). The following picture shows which components
+ come into play when using this mechanism.
+ </para>
+ <figure id="jobexecutor.overview.image">
+ <title>JobExecutor components overview</title>
+ <mediaobject><imageobject><imagedata align="center" fileref="images/jobexecutor.overview.png"/></imageobject></mediaobject>
+ </figure>
+ <para>
+ When using timers or asynchronous continuations in a business process, the
+ jBPM engine will store a 'job' into the database (a job contains mainly a
+ duedate and continuation logic). Do note that this mechanism is
+ pluggable, which means that in the future other destinations could be
+ used (JMS, JCR, etc).
+ </para>
+ <para>
+ Now the JobExecutor comes in to play, which is in fact a manager
+ for several subcomponents:
+
+ <itemizedlist>
+ <listitem>
+ A <emphasis role="bold">shared BlockingQueue</emphasis>,
+ which is used to temporary store job identifiers of jobs which
+ are executable (eg duedate is passed).
+ </listitem>
+ <listitem>
+ Every JobExecutor has one <emphasis role="bold">DispatcherThread.</emphasis>
+ This thread will query the database for 'acquirable jobs' (eg timers
+ which duedate is passed), using a dedicated command through the CommandService.
+ Since the dispatcher uses the CommandService, the command is
+ automatically made transactional and wrapped by the configured
+ interceptors. As long as jobs are available the dispatcher will put
+ job identifiers on the shared queue, until the queue is either full
+ (the thread will automatically be blocked by the JVM until a slot is
+ free) or until no new jobs can be found in the database. If the latter
+ case, the dispatcher will wait for a configured time (ie the 'idle
+ time').
+ </listitem>
+ <listitem>
+ The JobExecutor also maintains a pool of
+ <emphasis role="bold">JobExecutorThreads</emphasis>. The number of
+ JobExecutorThreads can be configured and influences the size of the
+ shared queue. Every one of the JobExecutorThreads will try to take a
+ jobId from the queue. The shared queue implementation is guaranteed to
+ block the JobexecutorThread until a queue slot is filled and the new
+ job id will be passed to exactly one waiting JobexecutorThread.
+ After taking a job id from the queue, the job is transactionally
+ executed using a dedicated command through the CommandService. This
+ means that the job logic will completely be executed on the
+ JobExecutorThread, instead of the default calling thread. This also
+ means that the order in which the jobs are executed is unknown since
+ there could be multiple competing JobExecutorThreads, but it
+ is certain that only one job per transaction will be done (unless using
+ 'exclusive jobs' - in this case all exclusive jobs are sequentially
+ executed).
+ </listitem>
+ </itemizedlist>
+ </para>
+
+ </section>
+
+ <section id="configuration">
+ <title>Configuration</title>
+ <para>
+ Enabling the jobExecutor is very easy by adding the following line to the
+ jbpm.cfg.xml file (using default settings):
+ </para>
+ <programlisting>
+ <import resource="jbpm.jobexecutor.cfg.xml" />
+ </programlisting>
+ <para>
+ Additional attributes can be set to fine-tune the JobExecutor:
+ <itemizedlist>
+ <listitem>
+ <emphasis role="bold">threads:</emphasis> defines the number of
+ JobexecutorThreads (default 3 threads)
+ </listitem>
+ <listitem>
+ <emphasis role="bold">idle:</emphasis> number of milliseconds the dispatcher
+ component waits after no new jobs were found in the database (default 5 seconds)
+ </listitem>
+ <listitem>
+ <emphasis role="bold">idle-max:</emphasis> each time an exception occurs,
+ the idle period will be doubled until the 'idle-max' is reached
+ (back-off mechanism used to avoid a constant load on a failing database)
+ </listitem>
+ <listitem>
+ <emphasis role="bold">lock-millis:</emphasis> Number of milliseconds
+ that a job will be locked after being acquired by the dispatcher.
+ This prevents starvation in case one of more JobExecutorThreads would die
+ (eg when used in a cluster).
+ </listitem>
+ </itemizedlist>
+ <programlisting>
+
+ <process-engine-context>
+
+ <job-executor threads="4" idle="15000" idle-max="60000" lock-millis="3600000" />
+
+ </process-engine-context>
+ </programlisting>
+ </para>
+ </section>
+
+</chapter>
Copied: jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch12-AdvancedEmail.xml (from rev 5215, jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch11-AdvancedEmail.xml)
===================================================================
--- jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch12-AdvancedEmail.xml (rev 0)
+++ jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch12-AdvancedEmail.xml 2009-07-04 08:19:36 UTC (rev 5220)
@@ -0,0 +1,196 @@
+<chapter id="mailsupport">
+ <title>Advanced Mail Support</title>
+ <para>jBPM 4 takes advantage of the JavaMail API to make high-level email
+ services available to business process authors.</para>
+
+ <section id="mailproducers">
+ <title>Producers</title>
+ <para>Producers are responsible for creating email messages within jBPM. All mail producers
+ implement the <literal>org.jbpm.pvm.internal.email.spi.MailProducer</literal> interface.
+ A default mail producer is available out of the box to address typical email needs.</para>
+
+ <section id="defaultmailproducer">
+ <title>Default Producer</title>
+ <para>The default mail producer is capable of creating email messages with text,
+ HTML and attachments from a template. Templates can be provided inline or
+ in the process-engine-context section of the jBPM configuration. Templates
+ may contain expressions which are evaluated through the script manager.
+ </para>
+ <para>The following listing presents a mail activity with an inline template.</para>
+ <programlisting><![CDATA[<mail name="rectify" language="juel"> (1)
+ <from addresses='winston@minitrue' /> (2)
+ <to addresses='julia@minitrue, obrien@miniluv'/> (3)
+ <cc users='bigbrother'/>
+ <bcc groups='thinkpol, innerparty'/>
+ <subject>Part ${part} Chapter ${chapter}</subject> (4)
+ <text>times ${date} reporting bb dayorder doubleplusungood (5)
+ refs ${unpersons} rewrite fullwise upsub antefiling</text>
+ <html><table><tr><td>times</td><td>${date}</td> (6)
+ <td>reporting bb dayorder doubleplusungood
+ refs ${unpersons} rewrite fullwise upsub antefiling</td>
+ </tr></table></html>
+ <attachments> (7)
+ <attachment url='http://www.george-orwell.org/1984/3.html'/>
+ <attachment resource='org/example/pic.jpg'/>
+ <attachment file='${user.home}/.face'/>
+ </attachments>
+</mail>]]></programlisting>
+ <orderedlist>
+ <listitem><para>Expressions within the template are written in the scripting language
+ indicated here. If not specified, the default expression language will be assumed.
+ </para></listitem>
+ <listitem><para>List of message senders. Senders are either identified directly by
+ their email addresses or appointed by means of the identity model.</para></listitem>
+ <listitem><para>Lists of message recipients, categorized as follows: <emphasis>To</emphasis>
+ (primary), <emphasis>CC</emphasis> (carbon copy) and <emphasis>BCC</emphasis> (blind
+ carbon copy). Like senders, recipients are directly identified by their email addresses
+ or appointed by means of the identity model.</para></listitem>
+ <listitem><para>Character data contained in element <literal>subject</literal>
+ are used as the message subject.</para></listitem>
+ <listitem><para>Character data contained in element <literal>text</literal>
+ are used as the plain text content of the message.</para></listitem>
+ <listitem><para>Nodes contained in element <literal>html</literal>
+ are used as the HTML content of the message.</para></listitem>
+ <listitem><para>Attachments can be specified as absolute URLs,
+ classpath resources or local files.</para></listitem>
+ </orderedlist>
+ <para>Note that every section of the template is amenable to expression evaluation.</para>
+ </section>
+ <para>For complex emails or custom generation of attachments, see: <link
+ linkend="customemails">Extension Points: Custom Emails</link>.</para>
+ </section>
+
+ <section id="mailtemplates">
+ <title>Templates</title>
+ <para>Mail templates are available to externalize commonly used messages from process definitions.
+ Templates are placed in the process-engine-context section of your configuration file. All elements
+ available to inline templates, as described in the <link linkend="defaultmailproducer">previous
+ section</link> are available to external templates. Consider the fragment below.</para>
+ <programlisting><![CDATA[<jbpm-configuration>
+<process-engine-context>
+ <mail-template name="rectify-template">
+ <!-- same elements as inline template -->
+ </mail-template>
+</process-engine-context>
+</jbpm-configuration>]]></programlisting>
+ <para>Each template must have an unique name. Mail activities may reference the template
+ through the <literal>template</literal> attribute, as follows.</para>
+ <programlisting><![CDATA[<mail name="rectify" template="rectify-template />]]></programlisting>
+ </section>
+
+ <section id="mailservers">
+ <title>Servers</title>
+ <para>Mail servers are declared in the configuration file. The <literal>mail-server</literal>
+ element describes an SMTP mail server capable of sending email messages.
+ Because jBPM uses JavaMail to send mail, all properties supported by JavaMail are also
+ exposed to jBPM. Within the <literal>session-properties</literal> child element,
+ the SMTP properties must be provided as shown in the example below.</para>
+ <para>See the Sun JavaMail API for more information on supported properties:
+ <ulink url="http://java.sun.com/products/javamail/javadocs/com/sun/mail/smtp/package-...">
+ Sun SMTP Properties</ulink>.</para>
+ <programlisting><![CDATA[<jbpm-configuration>
+<transaction-context>
+ <mail-session>
+ <mail-server>
+ <session-properties>
+ <property name="mail.smtp.host" value="localhost" />
+ <property name="mail.smtp.port" value="2525" />
+ <property name="mail.from" value="noreply(a)jbpm.org" />
+ </session-properties>
+ </mail-server>
+ </mail-session>
+</transaction-context>
+</jbpm-configuration>]]></programlisting>
+ <para>If the "From" attribute is not present in an outgoing message, the value of the
+ <literal>mail.from</literal> property will be used instead.</para>
+
+ <section id="multiplemailservers">
+ <title>Multiple Servers</title>
+ <para>Multiple SMTP server support has been added to jBPM 4 to accommodate a wider
+ variety of organizational server structures. For example, this is useful for companies
+ that have both internal and external SMTP servers.</para>
+ <para>To setup multiple SMTP mail servers, declare multiple mail servers within the
+ configuration file, as described below. The tag <literal>address-filter</literal> exists
+ to define which domains are serviced by each mail server. The address filter consists
+ of regular expressions that determine whether an address will be processed by a given
+ server.</para>
+ <para>See the Sun Pattern API for more information on supported regular expressions:
+ <ulink url="http://java.sun.com/j2se/1.5.0/docs/api/java/util/regex/Pattern.html">
+ Sun Regex Patterns</ulink>.</para>
+ <programlisting><![CDATA[<jbpm-configuration>
+<transaction-context>
+ <mail-session>
+ <mail-server>
+ <address-filter>
+ <include>.+(a)jbpm.org</include>
+ </address-filter>
+ <session-properties>
+ <property name="mail.smtp.host" value="int.smtp.jbpm.org" />
+ <property name="mail.from" value="noreply(a)jbpm.org" />
+ </session-properties>
+ </mail-server>
+ <mail-server>
+ <address-filter>
+ <exclude>.+(a)jbpm.org</exclude>
+ </address-filter>
+ <session-properties>
+ <property name="mail.smtp.host" value="ext.smtp.jbpm.org" />
+ <property name="mail.from" value="noreply(a)jbpm.org" />
+ </session-properties>
+ </mail-server>
+ </mail-session>
+</transaction-context>
+</jbpm-configuration>]]></programlisting>
+ <para>Address filters follow the logic below to accept an address.</para>
+ <itemizedlist>
+ <listitem><para>Address is accepted if it is <emphasis>included</emphasis> and
+ <emphasis>not excluded</emphasis>.</para></listitem>
+ <listitem><para>Absence of includes implies the address is
+ <emphasis>included</emphasis>.</para></listitem>
+ <listitem><para>Absence of excludes implies the address is
+ <emphasis>not excluded</emphasis>.</para></listitem>
+ </itemizedlist>
+ </section>
+ </section>
+
+ <section id="extensibility">
+ <title>Extension Points</title>
+
+ <section id="customproducers">
+ <title>Custom Producers</title>
+ <para>jBPM 4 allows the creation of your own Mail Producers to address an organization's
+ specific email needs. To do so, users must implement the
+ <literal>org.jbpm.pvm.internal.email.spi.MailProducer</literal> interface. The method
+ <literal>produce</literal> will return one or more <literal>Message</literal> objects,
+ which will be sent through the <literal>MailSession</literal>.</para>
+
+ <section id="custom attachments">
+ <title>Example: Custom Attachments</title>
+ <para>Generation of custom attachments at runtime can be easily implemented in jBPM 4.
+ By extending the default mail producer, or implementing your own with the
+ <literal>MailProducer</literal> interface, attachments can be generated and
+ added to email messages at runtime.</para>
+ <para>The following is an example of how to extend <literal>MailProducerImpl</literal>
+ to add an extra attachment to every outgoing mail.</para>
+ <programlisting><![CDATA[public class CustomMailProducer extends MailProducerImpl {
+
+ protected void addAttachments(Execution execution, Multipart multipart) {
+ // have default mail producer create attachments from template
+ super.addAttachments(execution, multipart);
+
+ // create a body part to carry the content
+ BodyPart attachmentPart = new MimeBodyPart();
+
+ // set content provided by an arbitrary data handler
+ attachmentPart.setDataHandler(...);
+
+ // attach content
+ multipart.addBodyPart(attachmentPart);
+ }
+}]]></programlisting>
+ </section>
+ </section>
+
+ </section>
+
+</chapter>
\ No newline at end of file
Deleted: jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch12-SoftwareLogging.xml
===================================================================
--- jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch12-SoftwareLogging.xml 2009-07-04 03:34:11 UTC (rev 5219)
+++ jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch12-SoftwareLogging.xml 2009-07-04 08:19:36 UTC (rev 5220)
@@ -1,99 +0,0 @@
-<chapter id="softwarelogging">
- <title>Software logging</title>
-
- <section>
- <title>Configuration</title>
- <para>PVM can use JDK logging (java.util.logging) or log4j. When the first message is
- logged, PVM logging will make the selection with following procedure:
- <orderedlist>
- <listitem>If a <literal>logging.properties</literal> resource is found
- on the classpath (using the context classloader), then JDK logging will
- be used and that file will be used to initialize the JDK logging.
- </listitem>
- <listitem>If log4j is found on the classpath, then log4j will be used.
- The check for log4j will be done by checking availability of class
- <literal>org.apache.log4j.LogManager</literal> with the context classloader.
- </listitem>
- <listitem>If none of the above, JDK logging will be used.</listitem>
- </orderedlist>
- </para>
- </section>
-
- <section>
- <title>Categories</title>
- <para>The PVM classes use their class name as the category for the logger.
- </para>
- <para>To have a basic understanding of what the PVM classes are doing,
- turning on the <literal>debug</literal> level is great. Level
- <literal>trace</literal> might be spitting out too much for that
- purpose.
- </para>
- </section>
-
- <section>
- <title>JDK logging</title>
- <para>In JDK logging, <literal>debug</literal>maps to <literal>fine</literal>
- and <literal>trace</literal> maps to <literal>finest</literal>.
- Level <literal>finer</literal> is not used.
- </para>
- <para><literal>org.jbpm.pvm.internal.log.LogFormatter</literal> is part of
- the pvm library and it can create a nice one-line output for log messages.
- It also has a neat feature that creates a unique indentation per thread.
- To configure it, this is a typical <literal>logging.properties</literal>
- </para>
- <programlisting>handlers = java.util.logging.ConsoleHandler
-java.util.logging.ConsoleHandler.level = FINEST
-java.util.logging.ConsoleHandler.formatter = org.jbpm.pvm.internal.log.LogFormatter
-
-# For example, set the com.xyz.foo logger to only log SEVERE messages:
-# com.xyz.foo.level = SEVERE
-
-.level = SEVERE
-org.jbpm.level=FINE
-org.jbpm.tx.level=FINE
-org.jbpm.pvm.internal.wire.level=FINE</programlisting>
-
-<!--
- <para>For production usage, jBPM also includes an error triggered log handler. This is
- a log handler that will only keep the most recent log messages in
- memory and these will only be flushed to a file in case an error occurs.
- </para>
- <para>to configure it, add <literal>org.jbpm.util.ErrorTriggeredFileHandler</literal>
- to the handlers in the logging properties like this:
- </para>
- <programlisting>handlers = java.util.logging.ConsoleHandler org.jbpm.util.ErrorTriggeredFileHandler</programlisting>
- <para>Next snippet shows how in the same logging.properties, the error
- triggered file handler can be configured. The given values are the default
- values.
- </para>
- <programlisting>org.jbpm.util.ErrorTriggeredFileHandler.size = 500
-org.jbpm.util.ErrorTriggeredFileHandler.push = SEVERE
-org.jbpm.util.ErrorTriggeredFileHandler.pattern = %h/jbpm%u.log</programlisting>
- <para>Alternatively to using the org.jbpm.util.ErrorTriggeredFileHandler, the
- JDK handlers FileHandler and MemoryHandler can used in combination to get
- similar results with a bit more configuration.
- </para>
-
--->
- </section>
-
- <section>
- <title>Debugging persistence</title>
- <para>When testing the persistence, following logging configurations can be
- valuable. Category <literal>org.hibernate.SQL</literal> shows the SQL statement that is executed
- and category <literal>org.hibernate.type</literal> shows the values of the parameters that are
- set in the queries.
- </para>
- <programlisting>org.hibernate.SQL.level=FINEST
-org.hibernate.type.level=FINEST</programlisting>
- <para>And in case you get a failed batch as a cause in a hibernate exception,
- you might want to set the batch size to 0 like this in the hibernate properties:
- </para>
- <programlisting>hibernate.jdbc.batch_size = 0</programlisting>
- <para>Also in the hibernate properties, the following properties allow for
- detailed logs of the SQL that hibernate spits out:</para>
- <programlisting>hibernate.show_sql = true
-hibernate.format_sql = true
-hibernate.use_sql_comments = true</programlisting>
- </section>
-</chapter>
\ No newline at end of file
Deleted: jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch13-History.xml
===================================================================
--- jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch13-History.xml 2009-07-04 03:34:11 UTC (rev 5219)
+++ jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch13-History.xml 2009-07-04 08:19:36 UTC (rev 5220)
@@ -1,42 +0,0 @@
-<chapter id="history">
- <title>History</title>
-
- <section id="overview">
- <title>Overview</title>
-
- <para>HistoryEvents are fired during process execution.
- </para>
-
- <para>We maintain history information on 2 levels: process instance and activity instance.
- </para>
-
- <para>Process instance start and process instance end generate history events are fired directly
- from within the implementation.
- </para>
-
- <para>ActivityBehaviour implementations are responsible for calling the historyXxx methods that
- are exposed on the ActivityExecution
- </para>
-
- <para>All the HistoryEvents are delegated to a HistorySession. The default HistorySessionImpl
- will invoke the process() method on the history events themselves.
- </para>
-
- <para>The HistoryEvents are temporary events. In the process method, they build up the information
- in the history model. There is a HistoryProcessInstance and there is a whole class hierarchy starting with HistoryActivityInstance.
- </para>
-
- <para>In the HistoryEvent.process methods, the history events create model entities or merge
- information into the model entities. For instance, a ProcessInstanceStart history event will
- create a HistoryProcessInstance entity/record. And the ProcessInstanceEnd will set the endTime
- property in the existing HistoryProcessInstance entity/record.
- </para>
-
- <para>Similar pattern for the activities. But for automatic activities, there is an optimisation
- so that only 1 event is created and all the information is stored in one single insert (as all
- this happens inside 1 transaction).
- </para>
-
- </section>
-
-</chapter>
\ No newline at end of file
Copied: jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch13-SoftwareLogging.xml (from rev 5215, jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch12-SoftwareLogging.xml)
===================================================================
--- jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch13-SoftwareLogging.xml (rev 0)
+++ jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch13-SoftwareLogging.xml 2009-07-04 08:19:36 UTC (rev 5220)
@@ -0,0 +1,99 @@
+<chapter id="softwarelogging">
+ <title>Software logging</title>
+
+ <section>
+ <title>Configuration</title>
+ <para>PVM can use JDK logging (java.util.logging) or log4j. When the first message is
+ logged, PVM logging will make the selection with following procedure:
+ <orderedlist>
+ <listitem>If a <literal>logging.properties</literal> resource is found
+ on the classpath (using the context classloader), then JDK logging will
+ be used and that file will be used to initialize the JDK logging.
+ </listitem>
+ <listitem>If log4j is found on the classpath, then log4j will be used.
+ The check for log4j will be done by checking availability of class
+ <literal>org.apache.log4j.LogManager</literal> with the context classloader.
+ </listitem>
+ <listitem>If none of the above, JDK logging will be used.</listitem>
+ </orderedlist>
+ </para>
+ </section>
+
+ <section>
+ <title>Categories</title>
+ <para>The PVM classes use their class name as the category for the logger.
+ </para>
+ <para>To have a basic understanding of what the PVM classes are doing,
+ turning on the <literal>debug</literal> level is great. Level
+ <literal>trace</literal> might be spitting out too much for that
+ purpose.
+ </para>
+ </section>
+
+ <section>
+ <title>JDK logging</title>
+ <para>In JDK logging, <literal>debug</literal>maps to <literal>fine</literal>
+ and <literal>trace</literal> maps to <literal>finest</literal>.
+ Level <literal>finer</literal> is not used.
+ </para>
+ <para><literal>org.jbpm.pvm.internal.log.LogFormatter</literal> is part of
+ the pvm library and it can create a nice one-line output for log messages.
+ It also has a neat feature that creates a unique indentation per thread.
+ To configure it, this is a typical <literal>logging.properties</literal>
+ </para>
+ <programlisting>handlers = java.util.logging.ConsoleHandler
+java.util.logging.ConsoleHandler.level = FINEST
+java.util.logging.ConsoleHandler.formatter = org.jbpm.pvm.internal.log.LogFormatter
+
+# For example, set the com.xyz.foo logger to only log SEVERE messages:
+# com.xyz.foo.level = SEVERE
+
+.level = SEVERE
+org.jbpm.level=FINE
+org.jbpm.tx.level=FINE
+org.jbpm.pvm.internal.wire.level=FINE</programlisting>
+
+<!--
+ <para>For production usage, jBPM also includes an error triggered log handler. This is
+ a log handler that will only keep the most recent log messages in
+ memory and these will only be flushed to a file in case an error occurs.
+ </para>
+ <para>to configure it, add <literal>org.jbpm.util.ErrorTriggeredFileHandler</literal>
+ to the handlers in the logging properties like this:
+ </para>
+ <programlisting>handlers = java.util.logging.ConsoleHandler org.jbpm.util.ErrorTriggeredFileHandler</programlisting>
+ <para>Next snippet shows how in the same logging.properties, the error
+ triggered file handler can be configured. The given values are the default
+ values.
+ </para>
+ <programlisting>org.jbpm.util.ErrorTriggeredFileHandler.size = 500
+org.jbpm.util.ErrorTriggeredFileHandler.push = SEVERE
+org.jbpm.util.ErrorTriggeredFileHandler.pattern = %h/jbpm%u.log</programlisting>
+ <para>Alternatively to using the org.jbpm.util.ErrorTriggeredFileHandler, the
+ JDK handlers FileHandler and MemoryHandler can used in combination to get
+ similar results with a bit more configuration.
+ </para>
+
+-->
+ </section>
+
+ <section>
+ <title>Debugging persistence</title>
+ <para>When testing the persistence, following logging configurations can be
+ valuable. Category <literal>org.hibernate.SQL</literal> shows the SQL statement that is executed
+ and category <literal>org.hibernate.type</literal> shows the values of the parameters that are
+ set in the queries.
+ </para>
+ <programlisting>org.hibernate.SQL.level=FINEST
+org.hibernate.type.level=FINEST</programlisting>
+ <para>And in case you get a failed batch as a cause in a hibernate exception,
+ you might want to set the batch size to 0 like this in the hibernate properties:
+ </para>
+ <programlisting>hibernate.jdbc.batch_size = 0</programlisting>
+ <para>Also in the hibernate properties, the following properties allow for
+ detailed logs of the SQL that hibernate spits out:</para>
+ <programlisting>hibernate.show_sql = true
+hibernate.format_sql = true
+hibernate.use_sql_comments = true</programlisting>
+ </section>
+</chapter>
\ No newline at end of file
Copied: jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch14-History.xml (from rev 5215, jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch13-History.xml)
===================================================================
--- jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch14-History.xml (rev 0)
+++ jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch14-History.xml 2009-07-04 08:19:36 UTC (rev 5220)
@@ -0,0 +1,42 @@
+<chapter id="history">
+ <title>History</title>
+
+ <section id="overview">
+ <title>Overview</title>
+
+ <para>HistoryEvents are fired during process execution.
+ </para>
+
+ <para>We maintain history information on 2 levels: process instance and activity instance.
+ </para>
+
+ <para>Process instance start and process instance end generate history events are fired directly
+ from within the implementation.
+ </para>
+
+ <para>ActivityBehaviour implementations are responsible for calling the historyXxx methods that
+ are exposed on the ActivityExecution
+ </para>
+
+ <para>All the HistoryEvents are delegated to a HistorySession. The default HistorySessionImpl
+ will invoke the process() method on the history events themselves.
+ </para>
+
+ <para>The HistoryEvents are temporary events. In the process method, they build up the information
+ in the history model. There is a HistoryProcessInstance and there is a whole class hierarchy starting with HistoryActivityInstance.
+ </para>
+
+ <para>In the HistoryEvent.process methods, the history events create model entities or merge
+ information into the model entities. For instance, a ProcessInstanceStart history event will
+ create a HistoryProcessInstance entity/record. And the ProcessInstanceEnd will set the endTime
+ property in the existing HistoryProcessInstance entity/record.
+ </para>
+
+ <para>Similar pattern for the activities. But for automatic activities, there is an optimisation
+ so that only 1 event is created and all the information is stored in one single insert (as all
+ this happens inside 1 transaction).
+ </para>
+
+ </section>
+
+</chapter>
\ No newline at end of file
Property changes on: jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch14-History.xml
___________________________________________________________________
Name: svn:mergeinfo
+
Deleted: jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch14-JBossIntegration.xml
===================================================================
--- jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch14-JBossIntegration.xml 2009-07-04 03:34:11 UTC (rev 5219)
+++ jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch14-JBossIntegration.xml 2009-07-04 08:19:36 UTC (rev 5220)
@@ -1,140 +0,0 @@
-<chapter id="jbossintegration">
- <title>JBoss Integration</title>
-
- <para>
- jBPM provides integration with JBoss 4.2.x and JBoss 5.0.0.GA.
- As part of the <link linkend="runningtheinstaller">installation</link>, the ProcessEngine and a deployer for jBPM archives
- will be installed as a JBoss service.
- </para>
-
- <para>
- After a successful installation you should see that the ProcessEngine
- has been started and bound to JNDI:
- </para>
-
- <programlisting>
- [...]
- 14:12:09,301 INFO [JBPMService] jBPM 4 - Integration JBoss 4
- 14:12:09,301 INFO [JBPMService] 4.0.0.Beta1
- 14:12:09,301 INFO [JBPMService] ProcessEngine bound to: java:/ProcessEngine
- </programlisting>
-
- <section>
- <title>Packaging process archives</title>
- <para>
- When jBPM is deployed on a JBoss instance, process deployments are treated like
- any other deployment artifact (i.e. *.war, *.ear) and processed by the JBPMDeployer.
- In order to deploy a process archive simply create a *.jpdl archive (zip file) that contains
- the process definition (*.jpdl.xml) and all required resources to execute the process (i.e. classes, property files):
- </para>
- <programlisting>
- Bonanova:Desktop hbraun$ jar -tf OrderProcess.jpdl
-
- META-INF/MANIFEST.MF
- OrderProcess.jpdl.xml
- org/mycompany/order/*.class
- </programlisting>
- </section>
-
- <section>
- <title>Deploying processes archives to a JBoss instance</title>
- <para>
- In order to deploy a process archive simply copy it to $JBOSS_HOME/server/<config>/deploy:
- </para>
-
- <programlisting>
- (1) cp OrderProcess.jpdl $JBOSS_HOME/server/default/deploy
-
- (2) less $JBOSS_HOME/server/default/log
- [...]
- 2009-04-08 14:12:21,947 INFO [org.jbpm.integration.jboss4.JBPMDeployer]
- Deploy file:/Users/hbraun/dev/prj/jboss/tags/JBoss_4_2_2_GA
- /build/output/jboss-4.2.2.GA/server/default/deploy/OrderProcess.jpdl
- </programlisting>
-
- <para>
- In order to remove a process simply remove the process archive from the deploy directory.
- </para>
- </section>
-
- <section>
- <title>Process deployments and versioning</title>
- <para>
- TBD: A prelimenary explanation cn be found <ulink url="http://relative-order.blogspot.com/2009/03/rfc-process-deployment-use-cas...">here</ulink>
- </para>
- </section>
-
- <section>
- <title>ProcessEngine and J2EE/JEE programming models</title>
- <para>
- As described above the ProcessEngine will be installed as JBoss service and bound to JNDI.
- This means that any EE component (i.e. servlet, ejb) can access it doing a JNDI lookup:
- </para>
-
- <programlisting>
- private ProcessEngine processEngine;
- [...]
-
- try
- {
- InitialContext ctx = new InitialContext();
- this.processEngine = (ProcessEngine)ctx.lookup("java:/ProcessEngine");
- }
- catch (Exception e)
- {
- throw new RuntimeException("Failed to lookup process engine");
- }
- </programlisting>
-
- <para>
- Once you obtained an instance of the ProcessEngine you can invoke on it
- as described in <link linkend="services">chapter services</link>
- </para>
-
- <programlisting>
- UserTransaction tx = (UserTransaction)ctx.lookup("UserTransaction"); (1)
- Environment env = ((EnvironmentFactory)processEngine).openEnvironment();
-
- try
- {
-
- ExecutionService execService = (ExecutionService)
- this.processEngine.get(ExecutionService.class);
-
- // begin transaction
- tx.begin();
-
- // invoke on process engine
- executionService.signalExecutionById("ICL.82436");
-
- // commit transaction
- tx.commit();
-
- }
- catch (Exception e)
- {
- if(tx!=null)
- {
- try
- {
- tx.rollback();
- }
- catch (SystemException e1) {}
- }
-
- throw new RuntimeException("...", e);
-
- }
- finally
- {
- env.close();
- }
- </programlisting>
-
- <para>
- (1) Wrapping the call in a UserTransaction is not necessary if the invocation comes a
- CMT component, i.e. an EJB.
- </para>
- </section>
-
-</chapter>
Copied: jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch15-JBossIntegration.xml (from rev 5215, jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch14-JBossIntegration.xml)
===================================================================
--- jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch15-JBossIntegration.xml (rev 0)
+++ jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch15-JBossIntegration.xml 2009-07-04 08:19:36 UTC (rev 5220)
@@ -0,0 +1,140 @@
+<chapter id="jbossintegration">
+ <title>JBoss Integration</title>
+
+ <para>
+ jBPM provides integration with JBoss 4.2.x and JBoss 5.0.0.GA.
+ As part of the <link linkend="runningtheinstaller">installation</link>, the ProcessEngine and a deployer for jBPM archives
+ will be installed as a JBoss service.
+ </para>
+
+ <para>
+ After a successful installation you should see that the ProcessEngine
+ has been started and bound to JNDI:
+ </para>
+
+ <programlisting>
+ [...]
+ 14:12:09,301 INFO [JBPMService] jBPM 4 - Integration JBoss 4
+ 14:12:09,301 INFO [JBPMService] 4.0.0.Beta1
+ 14:12:09,301 INFO [JBPMService] ProcessEngine bound to: java:/ProcessEngine
+ </programlisting>
+
+ <section>
+ <title>Packaging process archives</title>
+ <para>
+ When jBPM is deployed on a JBoss instance, process deployments are treated like
+ any other deployment artifact (i.e. *.war, *.ear) and processed by the JBPMDeployer.
+ In order to deploy a process archive simply create a *.jpdl archive (zip file) that contains
+ the process definition (*.jpdl.xml) and all required resources to execute the process (i.e. classes, property files):
+ </para>
+ <programlisting>
+ Bonanova:Desktop hbraun$ jar -tf OrderProcess.jpdl
+
+ META-INF/MANIFEST.MF
+ OrderProcess.jpdl.xml
+ org/mycompany/order/*.class
+ </programlisting>
+ </section>
+
+ <section>
+ <title>Deploying processes archives to a JBoss instance</title>
+ <para>
+ In order to deploy a process archive simply copy it to $JBOSS_HOME/server/<config>/deploy:
+ </para>
+
+ <programlisting>
+ (1) cp OrderProcess.jpdl $JBOSS_HOME/server/default/deploy
+
+ (2) less $JBOSS_HOME/server/default/log
+ [...]
+ 2009-04-08 14:12:21,947 INFO [org.jbpm.integration.jboss4.JBPMDeployer]
+ Deploy file:/Users/hbraun/dev/prj/jboss/tags/JBoss_4_2_2_GA
+ /build/output/jboss-4.2.2.GA/server/default/deploy/OrderProcess.jpdl
+ </programlisting>
+
+ <para>
+ In order to remove a process simply remove the process archive from the deploy directory.
+ </para>
+ </section>
+
+ <section>
+ <title>Process deployments and versioning</title>
+ <para>
+ TBD: A prelimenary explanation cn be found <ulink url="http://relative-order.blogspot.com/2009/03/rfc-process-deployment-use-cas...">here</ulink>
+ </para>
+ </section>
+
+ <section>
+ <title>ProcessEngine and J2EE/JEE programming models</title>
+ <para>
+ As described above the ProcessEngine will be installed as JBoss service and bound to JNDI.
+ This means that any EE component (i.e. servlet, ejb) can access it doing a JNDI lookup:
+ </para>
+
+ <programlisting>
+ private ProcessEngine processEngine;
+ [...]
+
+ try
+ {
+ InitialContext ctx = new InitialContext();
+ this.processEngine = (ProcessEngine)ctx.lookup("java:/ProcessEngine");
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException("Failed to lookup process engine");
+ }
+ </programlisting>
+
+ <para>
+ Once you obtained an instance of the ProcessEngine you can invoke on it
+ as described in <link linkend="services">chapter services</link>
+ </para>
+
+ <programlisting>
+ UserTransaction tx = (UserTransaction)ctx.lookup("UserTransaction"); (1)
+ Environment env = ((EnvironmentFactory)processEngine).openEnvironment();
+
+ try
+ {
+
+ ExecutionService execService = (ExecutionService)
+ this.processEngine.get(ExecutionService.class);
+
+ // begin transaction
+ tx.begin();
+
+ // invoke on process engine
+ executionService.signalExecutionById("ICL.82436");
+
+ // commit transaction
+ tx.commit();
+
+ }
+ catch (Exception e)
+ {
+ if(tx!=null)
+ {
+ try
+ {
+ tx.rollback();
+ }
+ catch (SystemException e1) {}
+ }
+
+ throw new RuntimeException("...", e);
+
+ }
+ finally
+ {
+ env.close();
+ }
+ </programlisting>
+
+ <para>
+ (1) Wrapping the call in a UserTransaction is not necessary if the invocation comes a
+ CMT component, i.e. an EJB.
+ </para>
+ </section>
+
+</chapter>
Deleted: jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch15-SpringIntegration.xml
===================================================================
--- jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch15-SpringIntegration.xml 2009-07-04 03:34:11 UTC (rev 5219)
+++ jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch15-SpringIntegration.xml 2009-07-04 08:19:36 UTC (rev 5220)
@@ -1,137 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<chapter id="springIntegration">
- <title>Spring Integration</title>
-
- <para>
- The embeddability of the jBPM engine in different environments has always
- been one of its core strengths, but often extra libraries to do the integration
- were required. Since jBPM4 however, it is now possible to natively
- integrate jBPM with <ulink url="http://www.springsource.org/about">Spring</ulink>.
- This section will explain which steps are required for such an integration.
- </para>
-
- <para>
- The Spring integration has started out as a community effort by
- <ulink url="http://www.inze.be/andries/">Andries Inzé</ulink>.
- Do note that Spring integration currently is in 'incubation', before
- it is moved to the user guide.
- </para>
-
- <section id="spring_overview">
- <title>Overview</title>
- <para>
- The default jBPM behaviour is to open a transaction for each operation
- that is called on the service API. In a typical Spring setup, applications are
- accessed from the web tier and enter a transactional boundary by invoking
- operations on service beans. These service beans will then access the jBPM services.
- All these operations run typically in a single transaction (ie one transaction
- per request from the browser), which invalidates the standard jBPM
- transaction handling approach. Instead of starting and committing
- a transaction for every service operation, the existing transaction
- should be used (or a new one started if none exists).
- </para>
- </section>
-
- <section id="spring_configuration">
- <title>Configuration</title>
- <para>
- Replace the standard-transaction-interceptor with the
- spring-transaction-interceptor. The hibernate session needs the attribute current=”true”.
- This forces jBPM to search for the current session,
- which will be provided by Spring.
- <programlisting>
- <process-engine-context>
- <command-service>
- <emphasis role="bold"><spring-transaction-interceptor /></emphasis>
- ...
- </command-service>
- ...
- </process-engine-context>
- <transaction-context>
- ...
- <emphasis role="bold"><hibernate-session current="true"/></emphasis>
- </transaction-context>
- </programlisting>
- </para>
-
- <para>
- The Spring integration provides a special context, which is added to
- the set of context where the jBPM engine will look for beans.
- Using this SpringContext, it is now possible to retrieve beans from the
- Spring Application Context. For the Spring context to be known, a
- SpringConfiguration must be created. This class extends the JbpmConfiguration
- but will add itself as a context. The single constructor take the location of the jBPM configuration.
-
- <programlisting>
- <bean id="jbpmConfiguration" class="org.jbpm.pvm.internal.cfg.SpringConfiguration">
- <constructor-arg value="be/inze/spring/demo/jbpm.cfg.xml" />
- </bean>
- </programlisting>
- </para>
-
- <para>
- The jBPM services can also be defined in the Spring applicationContext, as following:
- <programlisting>
-<bean id="processEngine" factory-bean="jbpmConfiguration" factory-method="buildProcessEngine" />
-<bean id="repositoryService" factory-bean="processEngine" factory-method="getRepositoryService" />
-<bean id="executionService" factory-bean="processEngine" factory-method="getExecutionService" />
- </programlisting>
- </para>
-
- <para>
- For accessing Spring beans from withing a process, we need to register
- the Spring applicationContext with the scripting-manager.
-
- <programlisting>
- <script-manager default-expression-language="juel"
- default-script-language="juel"
- read-contexts="execution, environment, process-engine, <emphasis role="bold">spring</emphasis>"
- write-context="">
- <script-language name="juel"
- factory="org.jbpm.pvm.internal.script.JuelScriptEngineFactory" />
- </script-manager>
- </programlisting>
- </para>
- </section>
-
- <section id="spring_usage">
- <title>Usage</title>
-
- <para>
- The previous section already showed how the jBPM services can be made
- accessible for other Spring services. The other use case is calling
- Spring beans from within a process. This can be done by using
- an expression which resolves to the name of a Spring bean.
-
- <programlisting>
-<java name="echo" expr="#{echoService}" method="sayHello" >
- <transition name="to accept" to="join1"/>
- </java>
- </programlisting>
-
- The scripting engine will look into all contexts from the bean named echoService.
- If you configured the ScriptManager as above, Spring will be the last context to search for.
- You can also add a Spring bean to the Spring Application context
- (eg IdentitySessionImpl with id <emphasis role="italic">identitySession</emphasis>)
- and use it in the jBPM config (eg by adding <env class="identitySession" />)
- </para>
-
- </section>
-
- <section id="spring_testing">
- <title>Testing</title>
-
- <para>
- Use the <emphasis role="bold">AbstractTransactionalJbpmTestCase</emphasis>
- to test a process in isolation (ie without impact on the database).
- This class extends from
- the <emphasis role="italic">AbstractTransactionalDataSourceSpringContextTests</emphasis>
- class, which means that testing a process comes down to exactly the same
- approach as testing a DAO.
- </para>
-
- </section>
-
-
-
-</chapter>
Deleted: jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch16-Jpdl3Migration.xml
===================================================================
--- jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch16-Jpdl3Migration.xml 2009-07-04 03:34:11 UTC (rev 5219)
+++ jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch16-Jpdl3Migration.xml 2009-07-04 08:19:36 UTC (rev 5220)
@@ -1,84 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<chapter id="jpdl3Migration">
- <title>JPDL3 migration</title>
-
- <para>
- In many cases, a lot of work has been put in the design of JPDL3 process
- definitions. To avoid a complete manual translation of these processes to the
- JPDL4 format, the jBPM distribution contains a subdirectory called
- <emphasis role="bold">migration</emphasis>, which contains a command-line
- tool for converting JPDL3 process definition files to JPDL process XML files.
- </para>
-
- <para>
- The tool itself uses only dom4j to do the translation between
- the two formats and should be easy extensible (the source code is also in
- the same directory). The design of the tool is deliberately kept very simple
- (ie most of the logic can be found in the <emphasis role="bold">Jpdl3Converter</emphasis> class).
- Note that this tool is experimental and tested only a small set of JPDL3
- process files.
- </para>
-
- <section id="migration_overview">
- <title>Overview</title>
- <para>
- The jPDL Conversion tool takes a jpdl3 process file as input, and
- converts it to a jpdl4 process file.
- </para>
- <para>
- Syntax:
- <programlisting>java org.jbpm.jpdl.internal.convert.JpdlConverterTool -v -o <outputfile> <processfile></programlisting>
- </para>
- </section>
-
- <section id="migration_arguments">
- <title>Arguments</title>
- <itemizedlist>
- <listitem>
- <emphasis role="bold">-v (verbose):</emphasis> The tool will print the detail
- messages while converting the process file. When this argument is used,
- it will also print the error stacktrace if exceptions are thrown.
- </listitem>
- <listitem>
- <emphasis role="bold">-o (output)</emphasis> Specifies the output file name.
- By default, the tool will generate a file name ending in 'converted.jpdl.xml'
- using as a base file name the name derived from the input process file.
- The output-filename can be an absolute file name path or a relative file name path.
- </listitem>
- </itemizedlist>
- </section>
-
- <section id="migration_examples">
- <title>Usage examples</title>
- <programlisting>
- java -jar jpdl-migration-XX.jar simple.jpdl.xml
- java -jar jpdl-migration-XX.jar -v simple.jpdl.xml
- java -jar jpdl-migration-XX.jar -o /home/scott/simple.converted.xml simple.jpdl.xml
- </programlisting>
- </section>
-
- <section id="migration_integration">
- <title>Advanced</title>
- <para>
- The conversion tool can easily be integrated with regular Java code
- (or with Maven or Ant). The following code example shows how to call the
- internal api to convert the process file:
- <programlisting>
- URL url = new URL("simple.jpdl");
- Jpdl3Converter jpdlConverter = new Jpdl3Converter(url);
- Document jpdl4Doc = jpdlConverter.readAndConvert();
-
- for (Problem problem : jpdlConverter.problems) {
- //do something to handle the problem
- }
-
- Writer fileWriter = new FileWriter(outputFile);
- OutputFormat format = OutputFormat.createPrettyPrint();
- XMLWriter writer = new XMLWriter( fileWriter, format );
- writer.write(jpdl4Doc);
- writer.close();
- </programlisting>
- </para>
- </section>
-
-</chapter>
Copied: jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch16-SpringIntegration.xml (from rev 5215, jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch15-SpringIntegration.xml)
===================================================================
--- jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch16-SpringIntegration.xml (rev 0)
+++ jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch16-SpringIntegration.xml 2009-07-04 08:19:36 UTC (rev 5220)
@@ -0,0 +1,137 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<chapter id="springIntegration">
+ <title>Spring Integration</title>
+
+ <para>
+ The embeddability of the jBPM engine in different environments has always
+ been one of its core strengths, but often extra libraries to do the integration
+ were required. Since jBPM4 however, it is now possible to natively
+ integrate jBPM with <ulink url="http://www.springsource.org/about">Spring</ulink>.
+ This section will explain which steps are required for such an integration.
+ </para>
+
+ <para>
+ The Spring integration has started out as a community effort by
+ <ulink url="http://www.inze.be/andries/">Andries Inzé</ulink>.
+ Do note that Spring integration currently is in 'incubation', before
+ it is moved to the user guide.
+ </para>
+
+ <section id="spring_overview">
+ <title>Overview</title>
+ <para>
+ The default jBPM behaviour is to open a transaction for each operation
+ that is called on the service API. In a typical Spring setup, applications are
+ accessed from the web tier and enter a transactional boundary by invoking
+ operations on service beans. These service beans will then access the jBPM services.
+ All these operations run typically in a single transaction (ie one transaction
+ per request from the browser), which invalidates the standard jBPM
+ transaction handling approach. Instead of starting and committing
+ a transaction for every service operation, the existing transaction
+ should be used (or a new one started if none exists).
+ </para>
+ </section>
+
+ <section id="spring_configuration">
+ <title>Configuration</title>
+ <para>
+ Replace the standard-transaction-interceptor with the
+ spring-transaction-interceptor. The hibernate session needs the attribute current=”true”.
+ This forces jBPM to search for the current session,
+ which will be provided by Spring.
+ <programlisting>
+ <process-engine-context>
+ <command-service>
+ <emphasis role="bold"><spring-transaction-interceptor /></emphasis>
+ ...
+ </command-service>
+ ...
+ </process-engine-context>
+ <transaction-context>
+ ...
+ <emphasis role="bold"><hibernate-session current="true"/></emphasis>
+ </transaction-context>
+ </programlisting>
+ </para>
+
+ <para>
+ The Spring integration provides a special context, which is added to
+ the set of context where the jBPM engine will look for beans.
+ Using this SpringContext, it is now possible to retrieve beans from the
+ Spring Application Context. For the Spring context to be known, a
+ SpringConfiguration must be created. This class extends the JbpmConfiguration
+ but will add itself as a context. The single constructor take the location of the jBPM configuration.
+
+ <programlisting>
+ <bean id="jbpmConfiguration" class="org.jbpm.pvm.internal.cfg.SpringConfiguration">
+ <constructor-arg value="be/inze/spring/demo/jbpm.cfg.xml" />
+ </bean>
+ </programlisting>
+ </para>
+
+ <para>
+ The jBPM services can also be defined in the Spring applicationContext, as following:
+ <programlisting>
+<bean id="processEngine" factory-bean="jbpmConfiguration" factory-method="buildProcessEngine" />
+<bean id="repositoryService" factory-bean="processEngine" factory-method="getRepositoryService" />
+<bean id="executionService" factory-bean="processEngine" factory-method="getExecutionService" />
+ </programlisting>
+ </para>
+
+ <para>
+ For accessing Spring beans from withing a process, we need to register
+ the Spring applicationContext with the scripting-manager.
+
+ <programlisting>
+ <script-manager default-expression-language="juel"
+ default-script-language="juel"
+ read-contexts="execution, environment, process-engine, <emphasis role="bold">spring</emphasis>"
+ write-context="">
+ <script-language name="juel"
+ factory="org.jbpm.pvm.internal.script.JuelScriptEngineFactory" />
+ </script-manager>
+ </programlisting>
+ </para>
+ </section>
+
+ <section id="spring_usage">
+ <title>Usage</title>
+
+ <para>
+ The previous section already showed how the jBPM services can be made
+ accessible for other Spring services. The other use case is calling
+ Spring beans from within a process. This can be done by using
+ an expression which resolves to the name of a Spring bean.
+
+ <programlisting>
+<java name="echo" expr="#{echoService}" method="sayHello" >
+ <transition name="to accept" to="join1"/>
+ </java>
+ </programlisting>
+
+ The scripting engine will look into all contexts from the bean named echoService.
+ If you configured the ScriptManager as above, Spring will be the last context to search for.
+ You can also add a Spring bean to the Spring Application context
+ (eg IdentitySessionImpl with id <emphasis role="italic">identitySession</emphasis>)
+ and use it in the jBPM config (eg by adding <env class="identitySession" />)
+ </para>
+
+ </section>
+
+ <section id="spring_testing">
+ <title>Testing</title>
+
+ <para>
+ Use the <emphasis role="bold">AbstractTransactionalJbpmTestCase</emphasis>
+ to test a process in isolation (ie without impact on the database).
+ This class extends from
+ the <emphasis role="italic">AbstractTransactionalDataSourceSpringContextTests</emphasis>
+ class, which means that testing a process comes down to exactly the same
+ approach as testing a DAO.
+ </para>
+
+ </section>
+
+
+
+</chapter>
Modified: jbpm4/trunk/modules/jpdl/src/main/java/org/jbpm/jpdl/internal/xml/JpdlParser.java
===================================================================
--- jbpm4/trunk/modules/jpdl/src/main/java/org/jbpm/jpdl/internal/xml/JpdlParser.java 2009-07-04 03:34:11 UTC (rev 5219)
+++ jbpm4/trunk/modules/jpdl/src/main/java/org/jbpm/jpdl/internal/xml/JpdlParser.java 2009-07-04 08:19:36 UTC (rev 5220)
@@ -371,6 +371,10 @@
EventListener eventListener = (EventListener) eventBinding.parse(eventListenerElement, parse, this);
EventListenerReference eventListenerReference = event.createEventListenerReference(eventListener);
+ if (XmlUtil.attributeBoolean(eventListenerElement, "propagation", false, parse, false)) {
+ eventListenerReference.setPropagationEnabled(true);
+ }
+
continuationText = XmlUtil.attribute(eventListenerElement, "continue");
if (continuationText!=null) {
if (observableElement instanceof ActivityImpl) {
Modified: jbpm4/trunk/modules/test-db/src/test/java/org/jbpm/test/eventlistener/EventListenerTest.java
===================================================================
--- jbpm4/trunk/modules/test-db/src/test/java/org/jbpm/test/eventlistener/EventListenerTest.java 2009-07-04 03:34:11 UTC (rev 5219)
+++ jbpm4/trunk/modules/test-db/src/test/java/org/jbpm/test/eventlistener/EventListenerTest.java 2009-07-04 08:19:36 UTC (rev 5220)
@@ -26,7 +26,6 @@
import java.util.List;
import java.util.Map;
-import org.jbpm.api.Execution;
import org.jbpm.api.ProcessInstance;
import org.jbpm.api.listener.EventListener;
import org.jbpm.api.listener.EventListenerExecution;
@@ -61,8 +60,54 @@
String processInstanceId = executionService.startProcessInstanceByKey("ICL").getId();
assertEquals("true", executionService.getVariable(processInstanceId, "isInvoked"));
+
+ executionService.setVariable(processInstanceId, "isInvoked", "false");
+
+ executionService.signalExecutionById(processInstanceId);
+
+ assertEquals("false", executionService.getVariable(processInstanceId, "isInvoked"));
}
+ public static class PropagationEnabledListener implements EventListener {
+ private static final long serialVersionUID = 1L;
+ public void notify(EventListenerExecution execution) {
+ Integer invocations = (Integer) execution.getVariable("invocations");
+ if (invocations==null) {
+ execution.setVariable("invocations", 1);
+ } else {
+ execution.setVariable("invocations", invocations+1);
+ }
+ }
+ }
+
+ public void testProcessStartListenerPropagation() {
+ deployJpdlXmlString(
+ "<process name='Insurance claim' key='ICL'>" +
+ " <on event='start'>" +
+ " <event-listener propagation='enabled' class='"+PropagationEnabledListener.class.getName()+"' />" +
+ " </on>" +
+ " <start>" +
+ " <transition to='a' />" +
+ " </start>" +
+ " <state name='a'>" +
+ " <transition to='b' />" +
+ " </state>" +
+ " <state name='b' />" +
+ "</process>"
+ );
+
+ String processInstanceId = executionService.startProcessInstanceByKey("ICL").getId();
+
+ // the PropagationEnabledListener is invoked once for the start event
+ // of the process and once for the start event of activity a
+ assertEquals(2, executionService.getVariable(processInstanceId, "invocations"));
+
+ executionService.signalExecutionById(processInstanceId);
+
+ // the listener is invoked once more for the start of activity b
+ assertEquals(3, executionService.getVariable(processInstanceId, "invocations"));
+ }
+
public static class ActivityStartListener implements EventListener {
private static final long serialVersionUID = 1L;
public void notify(EventListenerExecution execution) {
Modified: jbpm4/trunk/modules/userguide/src/main/docbook/en/modules/ch06-Jpdl.xml
===================================================================
--- jbpm4/trunk/modules/userguide/src/main/docbook/en/modules/ch06-Jpdl.xml 2009-07-04 03:34:11 UTC (rev 5219)
+++ jbpm4/trunk/modules/userguide/src/main/docbook/en/modules/ch06-Jpdl.xml 2009-07-04 08:19:36 UTC (rev 5220)
@@ -2479,12 +2479,48 @@
</tbody>
</tgroup>
</table>
- <para>Let's look at an example process with event listeners:</para>
- <figure id="process.eventlistener">
- <title>The event listener example process</title>
- <mediaobject><imageobject><imagedata align="center" fileref="images/process.eventlistener.png"/></imageobject></mediaobject>
- </figure>
- <programlisting><process name="EventListener" xmlns="http://jbpm.org/4.0/jpdl">
+ <table><title>event listener attributes:</title>
+ <tgroup cols="5" rowsep="1" colsep="1">
+ <thead>
+ <row>
+ <entry>Attribute</entry>
+ <entry>Type</entry>
+ <entry>Default</entry>
+ <entry>Required?</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry><literal>propagation</literal></entry>
+ <entry>{enabled | disabled | true | false | on | off}</entry>
+ <entry>disabled</entry>
+ <entry>optional</entry>
+ <entry>indicates if the event listener should also be invoked for
+ propagating events.
+ </entry>
+ </row>
+ <row>
+ <entry><literal>continue</literal></entry>
+ <entry>{sync | async | exclusive}</entry>
+ <entry>sync</entry>
+ <entry>optional</entry>
+ <entry>indicates if the execution should be continued asynchronously
+ right before the event listener is executed. @see also
+ <xref linkend="asynchronouscontinuations"/>
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ <section>
+ <title>Event listener example</title>
+ <para>Let's look at an example process with event listeners:</para>
+ <figure id="process.eventlistener">
+ <title>The event listener example process</title>
+ <mediaobject><imageobject><imagedata align="center" fileref="images/process.eventlistener.png"/></imageobject></mediaobject>
+ </figure>
+ <programlisting><process name="EventListener" xmlns="http://jbpm.org/4.0/jpdl">
<on event="start">
<event-listener class="org.jbpm.examples.eventlistener.LogListener">
@@ -2517,10 +2553,10 @@
<state name="park"/>
</process></programlisting>
- <para><literal>LogListener</literal> will maintain a list of logs in a static member
- field:</para>
- <programlisting>public class <emphasis role="bold">LogListener</emphasis> implements EventListener {
-
+ <para><literal>LogListener</literal> will maintain a list of logs in a static member
+ field:</para>
+ <programlisting>public class <emphasis role="bold">LogListener</emphasis> implements EventListener {
+
// value gets injected from process definition
String msg;
@@ -2536,17 +2572,29 @@
execution.setVariable("logs", logs);
}
}</programlisting>
- <para>Next, we start a new process instance.</para>
- <programlisting>ProcessInstance processInstance = executionService.startProcessInstanceByKey("EventListener");</programlisting>
- <para>Then the process instance executes up to the wait activity. So we provide a signal
- and that will cause it to execute till the end.</para>
- <programlisting>Execution execution = processInstance.findActiveExecutionIn("wait");
+ <para>Next, we start a new process instance.</para>
+ <programlisting>ProcessInstance processInstance = executionService.startProcessInstanceByKey("EventListener");</programlisting>
+ <para>Then the process instance executes up to the wait activity. So we provide a signal
+ and that will cause it to execute till the end.</para>
+ <programlisting>Execution execution = processInstance.findActiveExecutionIn("wait");
executionService.signalExecutionById(execution.getId());</programlisting>
- <para>The list of log messages will now look like this:</para>
- <programlisting>[start on process definition,
+ <para>The list of log messages will now look like this:</para>
+ <programlisting>[start on process definition,
start on activity wait,
end on activity wait,
take transition]</programlisting>
+ </section>
+ <section>
+ <title>Event propagation</title>
+ <para>Events are propagated from activities and transitions to outer activities and
+ eventually to the process definition.
+ </para>
+ <para>By default, event listeners are only invoked
+ for events that are fired on the elements on which the event listeners are subscribed.
+ But by specifying <literal>propagation="enabled"</literal>, the event
+ listener will also be invoked for all events that are fired on contained elements.
+ </para>
+ </section>
</section>
<section id="asynchronouscontinuations">
16 years, 10 months
JBoss JBPM SVN: r5219 - jbpm3/branches/jbpm-3.2-soa/modules/core/src/test/java/org/jbpm/msg/command.
by do-not-reply@jboss.org
Author: alex.guizar(a)jboss.com
Date: 2009-07-03 23:34:11 -0400 (Fri, 03 Jul 2009)
New Revision: 5219
Modified:
jbpm3/branches/jbpm-3.2-soa/modules/core/src/test/java/org/jbpm/msg/command/AsyncExecutionDbTest.java
Log:
make AsyncExecutionDbTest resistant to stale state exceptions
Modified: jbpm3/branches/jbpm-3.2-soa/modules/core/src/test/java/org/jbpm/msg/command/AsyncExecutionDbTest.java
===================================================================
--- jbpm3/branches/jbpm-3.2-soa/modules/core/src/test/java/org/jbpm/msg/command/AsyncExecutionDbTest.java 2009-07-04 02:08:39 UTC (rev 5218)
+++ jbpm3/branches/jbpm-3.2-soa/modules/core/src/test/java/org/jbpm/msg/command/AsyncExecutionDbTest.java 2009-07-04 03:34:11 UTC (rev 5219)
@@ -21,169 +21,146 @@
*/
package org.jbpm.msg.command;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
+import org.jbpm.context.exe.ContextInstance;
import org.jbpm.db.AbstractDbTestCase;
import org.jbpm.graph.def.ActionHandler;
-import org.jbpm.graph.def.Node;
import org.jbpm.graph.def.ProcessDefinition;
import org.jbpm.graph.exe.ExecutionContext;
import org.jbpm.graph.exe.ProcessInstance;
public class AsyncExecutionDbTest extends AbstractDbTestCase {
- static List recordedNodes = new ArrayList();
-
private static int TIMEOUT = 60 * 1000;
public static class RecordNode implements ActionHandler {
-
private static final long serialVersionUID = 1L;
public void execute(ExecutionContext executionContext) throws Exception {
- Node node = executionContext.getNode();
- recordedNodes.add(node.getName());
- node.leave(executionContext);
+ Integer count = (Integer) executionContext.getVariable("count");
+ count = new Integer(count != null ? count.intValue() + 1 : 1);
+ executionContext.setVariable("count", count);
+ executionContext.setVariable(executionContext.getNode().getName(), count);
+ executionContext.leaveNode();
}
}
public void testAsyncExecution() throws Exception {
+ ProcessDefinition processDefinition = ProcessDefinition.parseXmlString("<process-definition name='async exec'>" +
+ " <start-state>" +
+ " <transition to='one' />" +
+ " </start-state>" +
+ " <node async='true' name='one'>" +
+ " <action class='" +
+ RecordNode.class.getName() +
+ "' />" +
+ " <transition to='two' />" +
+ " </node>" +
+ " <node async='exclusive' name='two'>" +
+ " <action class='" +
+ RecordNode.class.getName() +
+ "' />" +
+ " <transition to='three' />" +
+ " </node>" +
+ " <node async='true' name='three'>" +
+ " <action class='" +
+ RecordNode.class.getName() +
+ "' />" +
+ " <transition to='end' />" +
+ " </node>" +
+ " <end-state name='end' />" +
+ "</process-definition>");
+ jbpmContext.deployProcessDefinition(processDefinition);
- ProcessDefinition processDefinition = ProcessDefinition.parseXmlString("<process-definition>"
- + " <start-state>"
- + " <transition to='one' />"
- + " </start-state>"
- + " <node async='true' name='one'>"
- + " <action class='org.jbpm.msg.command.AsyncExecutionDbTest$RecordNode' />"
- + " <transition to='two' />"
- + " </node>"
- + " <node async='exclusive' name='two'>"
- + " <action class='org.jbpm.msg.command.AsyncExecutionDbTest$RecordNode' />"
- + " <transition to='three' />"
- + " </node>"
- + " <node async='true' name='three'>"
- + " <action class='org.jbpm.msg.command.AsyncExecutionDbTest$RecordNode' />"
- + " <transition to='end' />"
- + " </node>"
- + " <end-state name='end' />"
- + "</process-definition>");
- processDefinition = saveAndReload(processDefinition);
+ newTransaction();
try {
ProcessInstance processInstance = new ProcessInstance(processDefinition);
processInstance.signal();
jbpmContext.save(processInstance);
- assertEquals(processDefinition.getNode("one"), processInstance.getRootToken().getNode());
+ assertEquals("one", processInstance.getRootToken().getNode().getName());
assertEquals(1, getNbrOfJobsAvailable());
processJobs(TIMEOUT);
- assertEquals(0, getNbrOfJobsAvailable());
-
- List expectedNodes = new ArrayList();
- expectedNodes.add("one");
- expectedNodes.add("two");
- expectedNodes.add("three");
-
- assertEquals(expectedNodes, recordedNodes);
-
- processDefinition = graphSession.loadProcessDefinition(processDefinition.getId());
- processInstance = graphSession.loadProcessInstance(processInstance.getId());
+ processInstance = jbpmContext.loadProcessInstance(processInstance.getId());
assertTrue(processInstance.hasEnded());
- assertEquals(processDefinition.getNode("end"), processInstance.getRootToken().getNode());
+
+ ContextInstance contextInstance = processInstance.getContextInstance();
+ String[] nodes = { "one", "two", "three" };
+ for (int i = 0; i < nodes.length; i++) {
+ Integer value = (Integer) contextInstance.getVariable(nodes[i]);
+ assertEquals(i + 1, value.intValue());
+ }
}
finally {
jbpmContext.getGraphSession().deleteProcessDefinition(processDefinition.getId());
}
-
}
- static Set recordedActionNumbers = new HashSet();
-
public static class RecordAction implements ActionHandler {
-
private static final long serialVersionUID = 1L;
- String nbr;
public void execute(ExecutionContext executionContext) throws Exception {
- recordedActionNumbers.add(nbr);
+ executionContext.setVariable(executionContext.getAction().getName(), Boolean.TRUE);
}
}
public void testAsyncAction() throws Exception {
- ProcessDefinition processDefinition = ProcessDefinition.parseXmlString("<process-definition>"
+ ProcessDefinition processDefinition = ProcessDefinition.parseXmlString("<process-definition name='async action'>"
+ " <event type='process-start'>"
- + " <action async='true' class='"
- + RecordAction.class.getName()
- + "'>"
- + " <nbr>1</nbr>"
- + " </action>"
- + " <action async='exclusive' class='"
- + RecordAction.class.getName()
- + "'>"
- + " <nbr>2</nbr>"
- + " </action>"
- + " </event>"
- + " <start-state>"
- + " <transition to='one'>"
- + " <action async='true' class='"
- + RecordAction.class.getName()
- + "'>"
- + " <nbr>3</nbr>"
- + " </action>"
- + " <action async='exclusive' class='"
- + RecordAction.class.getName()
- + "'>"
- + " <nbr>4</nbr>"
- + " </action>"
- + " </transition>"
- + " </start-state>"
- + " <node name='one'>"
- + " <event type='node-enter'>"
- + " <action async='true' class='"
- + RecordAction.class.getName()
- + "'>"
- + " <nbr>5</nbr>"
- + " </action>"
- + " <action async='exclusive' class='"
- + RecordAction.class.getName()
- + "'>"
- + " <nbr>6</nbr>"
- + " </action>"
- + " </event>"
- + " <transition to='end' />"
- + " </node>"
- + " <end-state name='end' />"
- + "</process-definition>");
- processDefinition = saveAndReload(processDefinition);
+ + " <action name='sa' async='true' class='" +
+ RecordAction.class.getName() +
+ "'/>" +
+ " <action name='se' async='exclusive' class='" +
+ RecordAction.class.getName() +
+ "'/>" +
+ " </event>" +
+ " <start-state>" +
+ " <transition to='one'>" +
+ " <action name='ta' async='true' class='" +
+ RecordAction.class.getName() +
+ "'/>" +
+ " <action name='te' async='exclusive' class='" +
+ RecordAction.class.getName() +
+ "'/>" +
+ " </transition>" +
+ " </start-state>" +
+ " <node name='one'>" +
+ " <event type='node-enter'>" +
+ " <action name='na' async='true' class='" +
+ RecordAction.class.getName() +
+ "'/>" +
+ " <action name='ne' async='exclusive' class='" +
+ RecordAction.class.getName() +
+ "'/>" +
+ " </event>" +
+ " <transition to='end' />" +
+ " </node>" +
+ " <end-state name='end' />" +
+ "</process-definition>");
+ jbpmContext.deployProcessDefinition(processDefinition);
+
+ newTransaction();
try {
ProcessInstance processInstance = new ProcessInstance(processDefinition);
processInstance.signal();
jbpmContext.save(processInstance);
- assertEquals(processDefinition.getNode("end"), processInstance.getRootToken().getNode());
+
+ assertEquals("end", processInstance.getRootToken().getNode().getName());
assertEquals(6, getNbrOfJobsAvailable());
- assertEquals(0, recordedActionNumbers.size());
processJobs(TIMEOUT);
- assertEquals(0, getNbrOfJobsAvailable());
+ processInstance = jbpmContext.loadProcessInstance(processInstance.getId());
- HashSet expected = new HashSet();
- expected.add("1");
- expected.add("2");
- expected.add("3");
- expected.add("4");
- expected.add("5");
- expected.add("6");
-
- assertEquals(expected, recordedActionNumbers);
+ ContextInstance contextInstance = processInstance.getContextInstance();
+ String[] actions = { "sa", "se", "ta", "te", "na", "ne" };
+ for (int i = 0; i < actions.length; i++) {
+ assertEquals(Boolean.TRUE, contextInstance.getVariable(actions[i]));
+ }
}
finally {
jbpmContext.getGraphSession().deleteProcessDefinition(processDefinition.getId());
}
-
}
}
16 years, 10 months
JBoss JBPM SVN: r5218 - jbpm3/branches/jbpm-3.2-soa/hudson.
by do-not-reply@jboss.org
Author: alex.guizar(a)jboss.com
Date: 2009-07-03 22:08:39 -0400 (Fri, 03 Jul 2009)
New Revision: 5218
Modified:
jbpm3/branches/jbpm-3.2-soa/hudson/profiles.xml.redhat.qa
Log:
fix sybase password in redhat profile
Modified: jbpm3/branches/jbpm-3.2-soa/hudson/profiles.xml.redhat.qa
===================================================================
--- jbpm3/branches/jbpm-3.2-soa/hudson/profiles.xml.redhat.qa 2009-07-03 12:34:25 UTC (rev 5217)
+++ jbpm3/branches/jbpm-3.2-soa/hudson/profiles.xml.redhat.qa 2009-07-04 02:08:39 UTC (rev 5218)
@@ -23,7 +23,7 @@
<jdbc.sybase.database>jbpm3</jdbc.sybase.database>
<jdbc.sybase.url>jdbc:sybase:Tds:${jdbc.sybase.server}:${jdbc.sybase.port}/${jdbc.sybase.database}</jdbc.sybase.url>
<jdbc.sybase.username>jbpm3</jdbc.sybase.username>
- <jdbc.sybase.password>jbpm3</jdbc.sybase.password>
+ <jdbc.sybase.password>jbpm3jbpm3</jdbc.sybase.password>
<jdbc.sybase.driver>com.sybase.jdbc3.jdbc.SybDriver</jdbc.sybase.driver>
<jdbc.sybase.datasource>com.sybase.jdbc3.jdbc.SybXADataSource</jdbc.sybase.datasource>
16 years, 10 months
JBoss JBPM SVN: r5217 - jbpm4/trunk/modules/test-db.
by do-not-reply@jboss.org
Author: heiko.braun(a)jboss.com
Date: 2009-07-03 08:34:25 -0400 (Fri, 03 Jul 2009)
New Revision: 5217
Modified:
jbpm4/trunk/modules/test-db/pom.xml
Log:
Enable report SQL test
Modified: jbpm4/trunk/modules/test-db/pom.xml
===================================================================
--- jbpm4/trunk/modules/test-db/pom.xml 2009-07-03 12:33:56 UTC (rev 5216)
+++ jbpm4/trunk/modules/test-db/pom.xml 2009-07-03 12:34:25 UTC (rev 5217)
@@ -207,7 +207,7 @@
<trimStackTrace>false</trimStackTrace>
<excludes>
<!-- doesn't run for the moment -->
- <exclude>reporting/SQLStmtTest.java</exclude>
+ <!--exclude>reporting/SQLStmtTest.java</exclude-->
</excludes>
</configuration>
</plugin>
@@ -217,4 +217,4 @@
</profiles>
-</project>
\ No newline at end of file
+</project>
16 years, 10 months
JBoss JBPM SVN: r5216 - jbpm4/trunk/modules/integration/report/src/main/resources.
by do-not-reply@jboss.org
Author: heiko.braun(a)jboss.com
Date: 2009-07-03 08:33:56 -0400 (Fri, 03 Jul 2009)
New Revision: 5216
Modified:
jbpm4/trunk/modules/integration/report/src/main/resources/overall_activity.rptdesign
Log:
fix JBPM-2359: reporting on oracle
Modified: jbpm4/trunk/modules/integration/report/src/main/resources/overall_activity.rptdesign
===================================================================
--- jbpm4/trunk/modules/integration/report/src/main/resources/overall_activity.rptdesign 2009-07-03 12:21:36 UTC (rev 5215)
+++ jbpm4/trunk/modules/integration/report/src/main/resources/overall_activity.rptdesign 2009-07-03 12:33:56 UTC (rev 5216)
@@ -26,6 +26,17 @@
</structure>
</list-property>
</structure>
+ <structure>
+ <property name="name">index</property>
+ <property name="dataType">integer</property>
+ <property name="aggregateFunction">RUNNINGCOUNT</property>
+ <list-property name="arguments">
+ <structure>
+ <property name="name">Expression</property>
+ <expression name="value">row["dpl"]</expression>
+ </structure>
+ </list-property>
+ </structure>
</list-property>
<list-property name="columnHints">
<structure>
@@ -37,6 +48,15 @@
<property name="displayName">processId</property>
</structure>
</list-property>
+ <list-property name="filter">
+ <structure>
+ <property name="operator">le</property>
+ <expression name="expr">row["index"]</expression>
+ <simple-property-list name="value1">
+ <value>10</value>
+ </simple-property-list>
+ </structure>
+ </list-property>
<structure name="cachedMetaData">
<list-property name="resultSet">
<structure>
@@ -54,6 +74,11 @@
<property name="name">total_records</property>
<property name="dataType">integer</property>
</structure>
+ <structure>
+ <property name="position">4</property>
+ <property name="name">index</property>
+ <property name="dataType">integer</property>
+ </structure>
</list-property>
</structure>
<property name="dataSource">MySQL</property>
@@ -76,8 +101,7 @@
<property name="queryText">SELECT d.DBID_ as "dpl", p.STRINGVAL_ as "processId" FROM JBPM4_DEPLOYMENT d, JBPM4_DEPLOYPROP p
WHERE p.KEY_='pdid'
AND d.DBID_=p.DEPLOYMENT_
- GROUP BY "dpl","processId"
- LIMIT 10</property>
+ GROUP BY d.DBID_,p.STRINGVAL_</property>
<xml-property name="designerValues"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
<model:DesignValues xmlns:design="http://www.eclipse.org/datatools/connectivity/oda/design" xmlns:model="http://www.eclipse.org/birt/report/model/adapter/odaModel">
<Version>1.0</Version>
@@ -323,12 +347,21 @@
<property name="displayName">PROCDEFID_</property>
</structure>
</list-property>
+ <list-property name="filter">
+ <structure>
+ <property name="operator">le</property>
+ <expression name="expr">row["index"]</expression>
+ <simple-property-list name="value1">
+ <value>15</value>
+ </simple-property-list>
+ </structure>
+ </list-property>
<structure name="cachedMetaData">
<list-property name="resultSet">
<structure>
<property name="position">1</property>
<property name="name">numExecutions</property>
- <property name="dataType">integer</property>
+ <property name="dataType">decimal</property>
</structure>
<structure>
<property name="position">2</property>
@@ -348,8 +381,8 @@
<property name="position">1</property>
<property name="name">numExecutions</property>
<property name="nativeName">numExecutions</property>
- <property name="dataType">integer</property>
- <property name="nativeDataType">4</property>
+ <property name="dataType">decimal</property>
+ <property name="nativeDataType">-5</property>
</structure>
<structure>
<property name="position">2</property>
@@ -362,8 +395,7 @@
<property name="queryText">SELECT count(PROCDEFID_) as "numExecutions", PROCDEFID_
FROM JBPM4_HIST_PROCINST J
GROUP BY PROCDEFID_
- ORDER BY "numExecutions" DESC
- limit 15</property>
+ ORDER BY "numExecutions" DESC</property>
<xml-property name="designerValues"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
<model:DesignValues xmlns:design="http://www.eclipse.org/datatools/connectivity/oda/design" xmlns:model="http://www.eclipse.org/birt/report/model/adapter/odaModel">
<Version>1.0</Version>
16 years, 10 months
JBoss JBPM SVN: r5215 - in jbpm4/trunk/modules: devguide/src/main/docbook/en/modules and 2 other directories.
by do-not-reply@jboss.org
Author: jbarrez
Date: 2009-07-03 08:21:36 -0400 (Fri, 03 Jul 2009)
New Revision: 5215
Added:
jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch11-AdvancedEmail.xml
jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch12-SoftwareLogging.xml
jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch13-History.xml
jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch14-JBossIntegration.xml
jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch15-SpringIntegration.xml
jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch16-Jpdl3Migration.xml
Removed:
jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch11-SoftwareLogging.xml
jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch12-History.xml
jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch13-JBossIntegration.xml
jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch14-SpringIntegration.xml
jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch15-Jpdl3Migration.xml
Modified:
jbpm4/trunk/modules/devguide/src/main/docbook/en/master.xml
jbpm4/trunk/modules/userguide/src/main/docbook/en/master.xml
jbpm4/trunk/modules/userguide/src/main/docbook/en/modules/ch06-Jpdl.xml
Log:
JBPM-2364: move advanced mail support to devguide. Added example to mail activity in user guide.
Modified: jbpm4/trunk/modules/devguide/src/main/docbook/en/master.xml
===================================================================
--- jbpm4/trunk/modules/devguide/src/main/docbook/en/master.xml 2009-07-03 11:46:43 UTC (rev 5214)
+++ jbpm4/trunk/modules/devguide/src/main/docbook/en/master.xml 2009-07-03 12:21:36 UTC (rev 5215)
@@ -11,11 +11,12 @@
<!ENTITY ch08-Configuration SYSTEM "modules/ch08-Configuration.xml">
<!ENTITY ch09-Persistence SYSTEM "modules/ch09-Persistence.xml">
<!ENTITY ch10-JobExecutor SYSTEM "modules/ch10-JobExecutor.xml">
- <!ENTITY ch11-SoftwareLogging SYSTEM "modules/ch11-SoftwareLogging.xml">
- <!ENTITY ch12-History SYSTEM "modules/ch12-History.xml">
- <!ENTITY ch13-JBossIntegration SYSTEM "modules/ch13-JBossIntegration.xml">
- <!ENTITY ch14-SpringIntegration SYSTEM "modules/ch14-SpringIntegration.xml">
- <!ENTITY ch15-Jpdl3Migration SYSTEM "modules/ch15-Jpdl3Migration.xml">
+ <!ENTITY ch11-AdvancedEmail SYSTEM "modules/ch11-AdvancedEmail.xml">
+ <!ENTITY ch12-SoftwareLogging SYSTEM "modules/ch12-SoftwareLogging.xml">
+ <!ENTITY ch13-History SYSTEM "modules/ch13-History.xml">
+ <!ENTITY ch14-JBossIntegration SYSTEM "modules/ch14-JBossIntegration.xml">
+ <!ENTITY ch15-SpringIntegration SYSTEM "modules/ch15-SpringIntegration.xml">
+ <!ENTITY ch16-Jpdl3Migration SYSTEM "modules/ch16-Jpdl3Migration.xml">
]>
<book lang="en">
@@ -36,10 +37,11 @@
&ch08-Configuration;
&ch09-Persistence;
&ch10-JobExecutor;
- &ch11-SoftwareLogging;
- &ch12-History;
- &ch13-JBossIntegration;
- &ch14-SpringIntegration;
- &ch15-Jpdl3Migration;
+ &ch11-AdvancedEmail;
+ &ch12-SoftwareLogging;
+ &ch13-History;
+ &ch14-JBossIntegration;
+ &ch15-SpringIntegration;
+ &ch16-Jpdl3Migration;
</book>
\ No newline at end of file
Added: jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch11-AdvancedEmail.xml
===================================================================
--- jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch11-AdvancedEmail.xml (rev 0)
+++ jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch11-AdvancedEmail.xml 2009-07-03 12:21:36 UTC (rev 5215)
@@ -0,0 +1,196 @@
+<chapter id="mailsupport">
+ <title>Advanced Mail Support</title>
+ <para>jBPM 4 takes advantage of the JavaMail API to make high-level email
+ services available to business process authors.</para>
+
+ <section id="mailproducers">
+ <title>Producers</title>
+ <para>Producers are responsible for creating email messages within jBPM. All mail producers
+ implement the <literal>org.jbpm.pvm.internal.email.spi.MailProducer</literal> interface.
+ A default mail producer is available out of the box to address typical email needs.</para>
+
+ <section id="defaultmailproducer">
+ <title>Default Producer</title>
+ <para>The default mail producer is capable of creating email messages with text,
+ HTML and attachments from a template. Templates can be provided inline or
+ in the process-engine-context section of the jBPM configuration. Templates
+ may contain expressions which are evaluated through the script manager.
+ </para>
+ <para>The following listing presents a mail activity with an inline template.</para>
+ <programlisting><![CDATA[<mail name="rectify" language="juel"> (1)
+ <from addresses='winston@minitrue' /> (2)
+ <to addresses='julia@minitrue, obrien@miniluv'/> (3)
+ <cc users='bigbrother'/>
+ <bcc groups='thinkpol, innerparty'/>
+ <subject>Part ${part} Chapter ${chapter}</subject> (4)
+ <text>times ${date} reporting bb dayorder doubleplusungood (5)
+ refs ${unpersons} rewrite fullwise upsub antefiling</text>
+ <html><table><tr><td>times</td><td>${date}</td> (6)
+ <td>reporting bb dayorder doubleplusungood
+ refs ${unpersons} rewrite fullwise upsub antefiling</td>
+ </tr></table></html>
+ <attachments> (7)
+ <attachment url='http://www.george-orwell.org/1984/3.html'/>
+ <attachment resource='org/example/pic.jpg'/>
+ <attachment file='${user.home}/.face'/>
+ </attachments>
+</mail>]]></programlisting>
+ <orderedlist>
+ <listitem><para>Expressions within the template are written in the scripting language
+ indicated here. If not specified, the default expression language will be assumed.
+ </para></listitem>
+ <listitem><para>List of message senders. Senders are either identified directly by
+ their email addresses or appointed by means of the identity model.</para></listitem>
+ <listitem><para>Lists of message recipients, categorized as follows: <emphasis>To</emphasis>
+ (primary), <emphasis>CC</emphasis> (carbon copy) and <emphasis>BCC</emphasis> (blind
+ carbon copy). Like senders, recipients are directly identified by their email addresses
+ or appointed by means of the identity model.</para></listitem>
+ <listitem><para>Character data contained in element <literal>subject</literal>
+ are used as the message subject.</para></listitem>
+ <listitem><para>Character data contained in element <literal>text</literal>
+ are used as the plain text content of the message.</para></listitem>
+ <listitem><para>Nodes contained in element <literal>html</literal>
+ are used as the HTML content of the message.</para></listitem>
+ <listitem><para>Attachments can be specified as absolute URLs,
+ classpath resources or local files.</para></listitem>
+ </orderedlist>
+ <para>Note that every section of the template is amenable to expression evaluation.</para>
+ </section>
+ <para>For complex emails or custom generation of attachments, see: <link
+ linkend="customemails">Extension Points: Custom Emails</link>.</para>
+ </section>
+
+ <section id="mailtemplates">
+ <title>Templates</title>
+ <para>Mail templates are available to externalize commonly used messages from process definitions.
+ Templates are placed in the process-engine-context section of your configuration file. All elements
+ available to inline templates, as described in the <link linkend="defaultmailproducer">previous
+ section</link> are available to external templates. Consider the fragment below.</para>
+ <programlisting><![CDATA[<jbpm-configuration>
+<process-engine-context>
+ <mail-template name="rectify-template">
+ <!-- same elements as inline template -->
+ </mail-template>
+</process-engine-context>
+</jbpm-configuration>]]></programlisting>
+ <para>Each template must have an unique name. Mail activities may reference the template
+ through the <literal>template</literal> attribute, as follows.</para>
+ <programlisting><![CDATA[<mail name="rectify" template="rectify-template />]]></programlisting>
+ </section>
+
+ <section id="mailservers">
+ <title>Servers</title>
+ <para>Mail servers are declared in the configuration file. The <literal>mail-server</literal>
+ element describes an SMTP mail server capable of sending email messages.
+ Because jBPM uses JavaMail to send mail, all properties supported by JavaMail are also
+ exposed to jBPM. Within the <literal>session-properties</literal> child element,
+ the SMTP properties must be provided as shown in the example below.</para>
+ <para>See the Sun JavaMail API for more information on supported properties:
+ <ulink url="http://java.sun.com/products/javamail/javadocs/com/sun/mail/smtp/package-...">
+ Sun SMTP Properties</ulink>.</para>
+ <programlisting><![CDATA[<jbpm-configuration>
+<transaction-context>
+ <mail-session>
+ <mail-server>
+ <session-properties>
+ <property name="mail.smtp.host" value="localhost" />
+ <property name="mail.smtp.port" value="2525" />
+ <property name="mail.from" value="noreply(a)jbpm.org" />
+ </session-properties>
+ </mail-server>
+ </mail-session>
+</transaction-context>
+</jbpm-configuration>]]></programlisting>
+ <para>If the "From" attribute is not present in an outgoing message, the value of the
+ <literal>mail.from</literal> property will be used instead.</para>
+
+ <section id="multiplemailservers">
+ <title>Multiple Servers</title>
+ <para>Multiple SMTP server support has been added to jBPM 4 to accommodate a wider
+ variety of organizational server structures. For example, this is useful for companies
+ that have both internal and external SMTP servers.</para>
+ <para>To setup multiple SMTP mail servers, declare multiple mail servers within the
+ configuration file, as described below. The tag <literal>address-filter</literal> exists
+ to define which domains are serviced by each mail server. The address filter consists
+ of regular expressions that determine whether an address will be processed by a given
+ server.</para>
+ <para>See the Sun Pattern API for more information on supported regular expressions:
+ <ulink url="http://java.sun.com/j2se/1.5.0/docs/api/java/util/regex/Pattern.html">
+ Sun Regex Patterns</ulink>.</para>
+ <programlisting><![CDATA[<jbpm-configuration>
+<transaction-context>
+ <mail-session>
+ <mail-server>
+ <address-filter>
+ <include>.+(a)jbpm.org</include>
+ </address-filter>
+ <session-properties>
+ <property name="mail.smtp.host" value="int.smtp.jbpm.org" />
+ <property name="mail.from" value="noreply(a)jbpm.org" />
+ </session-properties>
+ </mail-server>
+ <mail-server>
+ <address-filter>
+ <exclude>.+(a)jbpm.org</exclude>
+ </address-filter>
+ <session-properties>
+ <property name="mail.smtp.host" value="ext.smtp.jbpm.org" />
+ <property name="mail.from" value="noreply(a)jbpm.org" />
+ </session-properties>
+ </mail-server>
+ </mail-session>
+</transaction-context>
+</jbpm-configuration>]]></programlisting>
+ <para>Address filters follow the logic below to accept an address.</para>
+ <itemizedlist>
+ <listitem><para>Address is accepted if it is <emphasis>included</emphasis> and
+ <emphasis>not excluded</emphasis>.</para></listitem>
+ <listitem><para>Absence of includes implies the address is
+ <emphasis>included</emphasis>.</para></listitem>
+ <listitem><para>Absence of excludes implies the address is
+ <emphasis>not excluded</emphasis>.</para></listitem>
+ </itemizedlist>
+ </section>
+ </section>
+
+ <section id="extensibility">
+ <title>Extension Points</title>
+
+ <section id="customproducers">
+ <title>Custom Producers</title>
+ <para>jBPM 4 allows the creation of your own Mail Producers to address an organization's
+ specific email needs. To do so, users must implement the
+ <literal>org.jbpm.pvm.internal.email.spi.MailProducer</literal> interface. The method
+ <literal>produce</literal> will return one or more <literal>Message</literal> objects,
+ which will be sent through the <literal>MailSession</literal>.</para>
+
+ <section id="custom attachments">
+ <title>Example: Custom Attachments</title>
+ <para>Generation of custom attachments at runtime can be easily implemented in jBPM 4.
+ By extending the default mail producer, or implementing your own with the
+ <literal>MailProducer</literal> interface, attachments can be generated and
+ added to email messages at runtime.</para>
+ <para>The following is an example of how to extend <literal>MailProducerImpl</literal>
+ to add an extra attachment to every outgoing mail.</para>
+ <programlisting><![CDATA[public class CustomMailProducer extends MailProducerImpl {
+
+ protected void addAttachments(Execution execution, Multipart multipart) {
+ // have default mail producer create attachments from template
+ super.addAttachments(execution, multipart);
+
+ // create a body part to carry the content
+ BodyPart attachmentPart = new MimeBodyPart();
+
+ // set content provided by an arbitrary data handler
+ attachmentPart.setDataHandler(...);
+
+ // attach content
+ multipart.addBodyPart(attachmentPart);
+ }
+}]]></programlisting>
+ </section>
+ </section>
+
+ </section>
+
+</chapter>
\ No newline at end of file
Deleted: jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch11-SoftwareLogging.xml
===================================================================
--- jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch11-SoftwareLogging.xml 2009-07-03 11:46:43 UTC (rev 5214)
+++ jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch11-SoftwareLogging.xml 2009-07-03 12:21:36 UTC (rev 5215)
@@ -1,99 +0,0 @@
-<chapter id="softwarelogging">
- <title>Software logging</title>
-
- <section>
- <title>Configuration</title>
- <para>PVM can use JDK logging (java.util.logging) or log4j. When the first message is
- logged, PVM logging will make the selection with following procedure:
- <orderedlist>
- <listitem>If a <literal>logging.properties</literal> resource is found
- on the classpath (using the context classloader), then JDK logging will
- be used and that file will be used to initialize the JDK logging.
- </listitem>
- <listitem>If log4j is found on the classpath, then log4j will be used.
- The check for log4j will be done by checking availability of class
- <literal>org.apache.log4j.LogManager</literal> with the context classloader.
- </listitem>
- <listitem>If none of the above, JDK logging will be used.</listitem>
- </orderedlist>
- </para>
- </section>
-
- <section>
- <title>Categories</title>
- <para>The PVM classes use their class name as the category for the logger.
- </para>
- <para>To have a basic understanding of what the PVM classes are doing,
- turning on the <literal>debug</literal> level is great. Level
- <literal>trace</literal> might be spitting out too much for that
- purpose.
- </para>
- </section>
-
- <section>
- <title>JDK logging</title>
- <para>In JDK logging, <literal>debug</literal>maps to <literal>fine</literal>
- and <literal>trace</literal> maps to <literal>finest</literal>.
- Level <literal>finer</literal> is not used.
- </para>
- <para><literal>org.jbpm.pvm.internal.log.LogFormatter</literal> is part of
- the pvm library and it can create a nice one-line output for log messages.
- It also has a neat feature that creates a unique indentation per thread.
- To configure it, this is a typical <literal>logging.properties</literal>
- </para>
- <programlisting>handlers = java.util.logging.ConsoleHandler
-java.util.logging.ConsoleHandler.level = FINEST
-java.util.logging.ConsoleHandler.formatter = org.jbpm.pvm.internal.log.LogFormatter
-
-# For example, set the com.xyz.foo logger to only log SEVERE messages:
-# com.xyz.foo.level = SEVERE
-
-.level = SEVERE
-org.jbpm.level=FINE
-org.jbpm.tx.level=FINE
-org.jbpm.pvm.internal.wire.level=FINE</programlisting>
-
-<!--
- <para>For production usage, jBPM also includes an error triggered log handler. This is
- a log handler that will only keep the most recent log messages in
- memory and these will only be flushed to a file in case an error occurs.
- </para>
- <para>to configure it, add <literal>org.jbpm.util.ErrorTriggeredFileHandler</literal>
- to the handlers in the logging properties like this:
- </para>
- <programlisting>handlers = java.util.logging.ConsoleHandler org.jbpm.util.ErrorTriggeredFileHandler</programlisting>
- <para>Next snippet shows how in the same logging.properties, the error
- triggered file handler can be configured. The given values are the default
- values.
- </para>
- <programlisting>org.jbpm.util.ErrorTriggeredFileHandler.size = 500
-org.jbpm.util.ErrorTriggeredFileHandler.push = SEVERE
-org.jbpm.util.ErrorTriggeredFileHandler.pattern = %h/jbpm%u.log</programlisting>
- <para>Alternatively to using the org.jbpm.util.ErrorTriggeredFileHandler, the
- JDK handlers FileHandler and MemoryHandler can used in combination to get
- similar results with a bit more configuration.
- </para>
-
--->
- </section>
-
- <section>
- <title>Debugging persistence</title>
- <para>When testing the persistence, following logging configurations can be
- valuable. Category <literal>org.hibernate.SQL</literal> shows the SQL statement that is executed
- and category <literal>org.hibernate.type</literal> shows the values of the parameters that are
- set in the queries.
- </para>
- <programlisting>org.hibernate.SQL.level=FINEST
-org.hibernate.type.level=FINEST</programlisting>
- <para>And in case you get a failed batch as a cause in a hibernate exception,
- you might want to set the batch size to 0 like this in the hibernate properties:
- </para>
- <programlisting>hibernate.jdbc.batch_size = 0</programlisting>
- <para>Also in the hibernate properties, the following properties allow for
- detailed logs of the SQL that hibernate spits out:</para>
- <programlisting>hibernate.show_sql = true
-hibernate.format_sql = true
-hibernate.use_sql_comments = true</programlisting>
- </section>
-</chapter>
\ No newline at end of file
Deleted: jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch12-History.xml
===================================================================
--- jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch12-History.xml 2009-07-03 11:46:43 UTC (rev 5214)
+++ jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch12-History.xml 2009-07-03 12:21:36 UTC (rev 5215)
@@ -1,42 +0,0 @@
-<chapter id="history">
- <title>History</title>
-
- <section id="overview">
- <title>Overview</title>
-
- <para>HistoryEvents are fired during process execution.
- </para>
-
- <para>We maintain history information on 2 levels: process instance and activity instance.
- </para>
-
- <para>Process instance start and process instance end generate history events are fired directly
- from within the implementation.
- </para>
-
- <para>ActivityBehaviour implementations are responsible for calling the historyXxx methods that
- are exposed on the ActivityExecution
- </para>
-
- <para>All the HistoryEvents are delegated to a HistorySession. The default HistorySessionImpl
- will invoke the process() method on the history events themselves.
- </para>
-
- <para>The HistoryEvents are temporary events. In the process method, they build up the information
- in the history model. There is a HistoryProcessInstance and there is a whole class hierarchy starting with HistoryActivityInstance.
- </para>
-
- <para>In the HistoryEvent.process methods, the history events create model entities or merge
- information into the model entities. For instance, a ProcessInstanceStart history event will
- create a HistoryProcessInstance entity/record. And the ProcessInstanceEnd will set the endTime
- property in the existing HistoryProcessInstance entity/record.
- </para>
-
- <para>Similar pattern for the activities. But for automatic activities, there is an optimisation
- so that only 1 event is created and all the information is stored in one single insert (as all
- this happens inside 1 transaction).
- </para>
-
- </section>
-
-</chapter>
\ No newline at end of file
Copied: jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch12-SoftwareLogging.xml (from rev 5210, jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch11-SoftwareLogging.xml)
===================================================================
--- jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch12-SoftwareLogging.xml (rev 0)
+++ jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch12-SoftwareLogging.xml 2009-07-03 12:21:36 UTC (rev 5215)
@@ -0,0 +1,99 @@
+<chapter id="softwarelogging">
+ <title>Software logging</title>
+
+ <section>
+ <title>Configuration</title>
+ <para>PVM can use JDK logging (java.util.logging) or log4j. When the first message is
+ logged, PVM logging will make the selection with following procedure:
+ <orderedlist>
+ <listitem>If a <literal>logging.properties</literal> resource is found
+ on the classpath (using the context classloader), then JDK logging will
+ be used and that file will be used to initialize the JDK logging.
+ </listitem>
+ <listitem>If log4j is found on the classpath, then log4j will be used.
+ The check for log4j will be done by checking availability of class
+ <literal>org.apache.log4j.LogManager</literal> with the context classloader.
+ </listitem>
+ <listitem>If none of the above, JDK logging will be used.</listitem>
+ </orderedlist>
+ </para>
+ </section>
+
+ <section>
+ <title>Categories</title>
+ <para>The PVM classes use their class name as the category for the logger.
+ </para>
+ <para>To have a basic understanding of what the PVM classes are doing,
+ turning on the <literal>debug</literal> level is great. Level
+ <literal>trace</literal> might be spitting out too much for that
+ purpose.
+ </para>
+ </section>
+
+ <section>
+ <title>JDK logging</title>
+ <para>In JDK logging, <literal>debug</literal>maps to <literal>fine</literal>
+ and <literal>trace</literal> maps to <literal>finest</literal>.
+ Level <literal>finer</literal> is not used.
+ </para>
+ <para><literal>org.jbpm.pvm.internal.log.LogFormatter</literal> is part of
+ the pvm library and it can create a nice one-line output for log messages.
+ It also has a neat feature that creates a unique indentation per thread.
+ To configure it, this is a typical <literal>logging.properties</literal>
+ </para>
+ <programlisting>handlers = java.util.logging.ConsoleHandler
+java.util.logging.ConsoleHandler.level = FINEST
+java.util.logging.ConsoleHandler.formatter = org.jbpm.pvm.internal.log.LogFormatter
+
+# For example, set the com.xyz.foo logger to only log SEVERE messages:
+# com.xyz.foo.level = SEVERE
+
+.level = SEVERE
+org.jbpm.level=FINE
+org.jbpm.tx.level=FINE
+org.jbpm.pvm.internal.wire.level=FINE</programlisting>
+
+<!--
+ <para>For production usage, jBPM also includes an error triggered log handler. This is
+ a log handler that will only keep the most recent log messages in
+ memory and these will only be flushed to a file in case an error occurs.
+ </para>
+ <para>to configure it, add <literal>org.jbpm.util.ErrorTriggeredFileHandler</literal>
+ to the handlers in the logging properties like this:
+ </para>
+ <programlisting>handlers = java.util.logging.ConsoleHandler org.jbpm.util.ErrorTriggeredFileHandler</programlisting>
+ <para>Next snippet shows how in the same logging.properties, the error
+ triggered file handler can be configured. The given values are the default
+ values.
+ </para>
+ <programlisting>org.jbpm.util.ErrorTriggeredFileHandler.size = 500
+org.jbpm.util.ErrorTriggeredFileHandler.push = SEVERE
+org.jbpm.util.ErrorTriggeredFileHandler.pattern = %h/jbpm%u.log</programlisting>
+ <para>Alternatively to using the org.jbpm.util.ErrorTriggeredFileHandler, the
+ JDK handlers FileHandler and MemoryHandler can used in combination to get
+ similar results with a bit more configuration.
+ </para>
+
+-->
+ </section>
+
+ <section>
+ <title>Debugging persistence</title>
+ <para>When testing the persistence, following logging configurations can be
+ valuable. Category <literal>org.hibernate.SQL</literal> shows the SQL statement that is executed
+ and category <literal>org.hibernate.type</literal> shows the values of the parameters that are
+ set in the queries.
+ </para>
+ <programlisting>org.hibernate.SQL.level=FINEST
+org.hibernate.type.level=FINEST</programlisting>
+ <para>And in case you get a failed batch as a cause in a hibernate exception,
+ you might want to set the batch size to 0 like this in the hibernate properties:
+ </para>
+ <programlisting>hibernate.jdbc.batch_size = 0</programlisting>
+ <para>Also in the hibernate properties, the following properties allow for
+ detailed logs of the SQL that hibernate spits out:</para>
+ <programlisting>hibernate.show_sql = true
+hibernate.format_sql = true
+hibernate.use_sql_comments = true</programlisting>
+ </section>
+</chapter>
\ No newline at end of file
Copied: jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch13-History.xml (from rev 5210, jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch12-History.xml)
===================================================================
--- jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch13-History.xml (rev 0)
+++ jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch13-History.xml 2009-07-03 12:21:36 UTC (rev 5215)
@@ -0,0 +1,42 @@
+<chapter id="history">
+ <title>History</title>
+
+ <section id="overview">
+ <title>Overview</title>
+
+ <para>HistoryEvents are fired during process execution.
+ </para>
+
+ <para>We maintain history information on 2 levels: process instance and activity instance.
+ </para>
+
+ <para>Process instance start and process instance end generate history events are fired directly
+ from within the implementation.
+ </para>
+
+ <para>ActivityBehaviour implementations are responsible for calling the historyXxx methods that
+ are exposed on the ActivityExecution
+ </para>
+
+ <para>All the HistoryEvents are delegated to a HistorySession. The default HistorySessionImpl
+ will invoke the process() method on the history events themselves.
+ </para>
+
+ <para>The HistoryEvents are temporary events. In the process method, they build up the information
+ in the history model. There is a HistoryProcessInstance and there is a whole class hierarchy starting with HistoryActivityInstance.
+ </para>
+
+ <para>In the HistoryEvent.process methods, the history events create model entities or merge
+ information into the model entities. For instance, a ProcessInstanceStart history event will
+ create a HistoryProcessInstance entity/record. And the ProcessInstanceEnd will set the endTime
+ property in the existing HistoryProcessInstance entity/record.
+ </para>
+
+ <para>Similar pattern for the activities. But for automatic activities, there is an optimisation
+ so that only 1 event is created and all the information is stored in one single insert (as all
+ this happens inside 1 transaction).
+ </para>
+
+ </section>
+
+</chapter>
\ No newline at end of file
Deleted: jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch13-JBossIntegration.xml
===================================================================
--- jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch13-JBossIntegration.xml 2009-07-03 11:46:43 UTC (rev 5214)
+++ jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch13-JBossIntegration.xml 2009-07-03 12:21:36 UTC (rev 5215)
@@ -1,140 +0,0 @@
-<chapter id="jbossintegration">
- <title>JBoss Integration</title>
-
- <para>
- jBPM provides integration with JBoss 4.2.x and JBoss 5.0.0.GA.
- As part of the <link linkend="runningtheinstaller">installation</link>, the ProcessEngine and a deployer for jBPM archives
- will be installed as a JBoss service.
- </para>
-
- <para>
- After a successful installation you should see that the ProcessEngine
- has been started and bound to JNDI:
- </para>
-
- <programlisting>
- [...]
- 14:12:09,301 INFO [JBPMService] jBPM 4 - Integration JBoss 4
- 14:12:09,301 INFO [JBPMService] 4.0.0.Beta1
- 14:12:09,301 INFO [JBPMService] ProcessEngine bound to: java:/ProcessEngine
- </programlisting>
-
- <section>
- <title>Packaging process archives</title>
- <para>
- When jBPM is deployed on a JBoss instance, process deployments are treated like
- any other deployment artifact (i.e. *.war, *.ear) and processed by the JBPMDeployer.
- In order to deploy a process archive simply create a *.jpdl archive (zip file) that contains
- the process definition (*.jpdl.xml) and all required resources to execute the process (i.e. classes, property files):
- </para>
- <programlisting>
- Bonanova:Desktop hbraun$ jar -tf OrderProcess.jpdl
-
- META-INF/MANIFEST.MF
- OrderProcess.jpdl.xml
- org/mycompany/order/*.class
- </programlisting>
- </section>
-
- <section>
- <title>Deploying processes archives to a JBoss instance</title>
- <para>
- In order to deploy a process archive simply copy it to $JBOSS_HOME/server/<config>/deploy:
- </para>
-
- <programlisting>
- (1) cp OrderProcess.jpdl $JBOSS_HOME/server/default/deploy
-
- (2) less $JBOSS_HOME/server/default/log
- [...]
- 2009-04-08 14:12:21,947 INFO [org.jbpm.integration.jboss4.JBPMDeployer]
- Deploy file:/Users/hbraun/dev/prj/jboss/tags/JBoss_4_2_2_GA
- /build/output/jboss-4.2.2.GA/server/default/deploy/OrderProcess.jpdl
- </programlisting>
-
- <para>
- In order to remove a process simply remove the process archive from the deploy directory.
- </para>
- </section>
-
- <section>
- <title>Process deployments and versioning</title>
- <para>
- TBD: A prelimenary explanation cn be found <ulink url="http://relative-order.blogspot.com/2009/03/rfc-process-deployment-use-cas...">here</ulink>
- </para>
- </section>
-
- <section>
- <title>ProcessEngine and J2EE/JEE programming models</title>
- <para>
- As described above the ProcessEngine will be installed as JBoss service and bound to JNDI.
- This means that any EE component (i.e. servlet, ejb) can access it doing a JNDI lookup:
- </para>
-
- <programlisting>
- private ProcessEngine processEngine;
- [...]
-
- try
- {
- InitialContext ctx = new InitialContext();
- this.processEngine = (ProcessEngine)ctx.lookup("java:/ProcessEngine");
- }
- catch (Exception e)
- {
- throw new RuntimeException("Failed to lookup process engine");
- }
- </programlisting>
-
- <para>
- Once you obtained an instance of the ProcessEngine you can invoke on it
- as described in <link linkend="services">chapter services</link>
- </para>
-
- <programlisting>
- UserTransaction tx = (UserTransaction)ctx.lookup("UserTransaction"); (1)
- Environment env = ((EnvironmentFactory)processEngine).openEnvironment();
-
- try
- {
-
- ExecutionService execService = (ExecutionService)
- this.processEngine.get(ExecutionService.class);
-
- // begin transaction
- tx.begin();
-
- // invoke on process engine
- executionService.signalExecutionById("ICL.82436");
-
- // commit transaction
- tx.commit();
-
- }
- catch (Exception e)
- {
- if(tx!=null)
- {
- try
- {
- tx.rollback();
- }
- catch (SystemException e1) {}
- }
-
- throw new RuntimeException("...", e);
-
- }
- finally
- {
- env.close();
- }
- </programlisting>
-
- <para>
- (1) Wrapping the call in a UserTransaction is not necessary if the invocation comes a
- CMT component, i.e. an EJB.
- </para>
- </section>
-
-</chapter>
Copied: jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch14-JBossIntegration.xml (from rev 5210, jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch13-JBossIntegration.xml)
===================================================================
--- jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch14-JBossIntegration.xml (rev 0)
+++ jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch14-JBossIntegration.xml 2009-07-03 12:21:36 UTC (rev 5215)
@@ -0,0 +1,140 @@
+<chapter id="jbossintegration">
+ <title>JBoss Integration</title>
+
+ <para>
+ jBPM provides integration with JBoss 4.2.x and JBoss 5.0.0.GA.
+ As part of the <link linkend="runningtheinstaller">installation</link>, the ProcessEngine and a deployer for jBPM archives
+ will be installed as a JBoss service.
+ </para>
+
+ <para>
+ After a successful installation you should see that the ProcessEngine
+ has been started and bound to JNDI:
+ </para>
+
+ <programlisting>
+ [...]
+ 14:12:09,301 INFO [JBPMService] jBPM 4 - Integration JBoss 4
+ 14:12:09,301 INFO [JBPMService] 4.0.0.Beta1
+ 14:12:09,301 INFO [JBPMService] ProcessEngine bound to: java:/ProcessEngine
+ </programlisting>
+
+ <section>
+ <title>Packaging process archives</title>
+ <para>
+ When jBPM is deployed on a JBoss instance, process deployments are treated like
+ any other deployment artifact (i.e. *.war, *.ear) and processed by the JBPMDeployer.
+ In order to deploy a process archive simply create a *.jpdl archive (zip file) that contains
+ the process definition (*.jpdl.xml) and all required resources to execute the process (i.e. classes, property files):
+ </para>
+ <programlisting>
+ Bonanova:Desktop hbraun$ jar -tf OrderProcess.jpdl
+
+ META-INF/MANIFEST.MF
+ OrderProcess.jpdl.xml
+ org/mycompany/order/*.class
+ </programlisting>
+ </section>
+
+ <section>
+ <title>Deploying processes archives to a JBoss instance</title>
+ <para>
+ In order to deploy a process archive simply copy it to $JBOSS_HOME/server/<config>/deploy:
+ </para>
+
+ <programlisting>
+ (1) cp OrderProcess.jpdl $JBOSS_HOME/server/default/deploy
+
+ (2) less $JBOSS_HOME/server/default/log
+ [...]
+ 2009-04-08 14:12:21,947 INFO [org.jbpm.integration.jboss4.JBPMDeployer]
+ Deploy file:/Users/hbraun/dev/prj/jboss/tags/JBoss_4_2_2_GA
+ /build/output/jboss-4.2.2.GA/server/default/deploy/OrderProcess.jpdl
+ </programlisting>
+
+ <para>
+ In order to remove a process simply remove the process archive from the deploy directory.
+ </para>
+ </section>
+
+ <section>
+ <title>Process deployments and versioning</title>
+ <para>
+ TBD: A prelimenary explanation cn be found <ulink url="http://relative-order.blogspot.com/2009/03/rfc-process-deployment-use-cas...">here</ulink>
+ </para>
+ </section>
+
+ <section>
+ <title>ProcessEngine and J2EE/JEE programming models</title>
+ <para>
+ As described above the ProcessEngine will be installed as JBoss service and bound to JNDI.
+ This means that any EE component (i.e. servlet, ejb) can access it doing a JNDI lookup:
+ </para>
+
+ <programlisting>
+ private ProcessEngine processEngine;
+ [...]
+
+ try
+ {
+ InitialContext ctx = new InitialContext();
+ this.processEngine = (ProcessEngine)ctx.lookup("java:/ProcessEngine");
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException("Failed to lookup process engine");
+ }
+ </programlisting>
+
+ <para>
+ Once you obtained an instance of the ProcessEngine you can invoke on it
+ as described in <link linkend="services">chapter services</link>
+ </para>
+
+ <programlisting>
+ UserTransaction tx = (UserTransaction)ctx.lookup("UserTransaction"); (1)
+ Environment env = ((EnvironmentFactory)processEngine).openEnvironment();
+
+ try
+ {
+
+ ExecutionService execService = (ExecutionService)
+ this.processEngine.get(ExecutionService.class);
+
+ // begin transaction
+ tx.begin();
+
+ // invoke on process engine
+ executionService.signalExecutionById("ICL.82436");
+
+ // commit transaction
+ tx.commit();
+
+ }
+ catch (Exception e)
+ {
+ if(tx!=null)
+ {
+ try
+ {
+ tx.rollback();
+ }
+ catch (SystemException e1) {}
+ }
+
+ throw new RuntimeException("...", e);
+
+ }
+ finally
+ {
+ env.close();
+ }
+ </programlisting>
+
+ <para>
+ (1) Wrapping the call in a UserTransaction is not necessary if the invocation comes a
+ CMT component, i.e. an EJB.
+ </para>
+ </section>
+
+</chapter>
Deleted: jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch14-SpringIntegration.xml
===================================================================
--- jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch14-SpringIntegration.xml 2009-07-03 11:46:43 UTC (rev 5214)
+++ jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch14-SpringIntegration.xml 2009-07-03 12:21:36 UTC (rev 5215)
@@ -1,137 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<chapter id="springIntegration">
- <title>Spring Integration</title>
-
- <para>
- The embeddability of the jBPM engine in different environments has always
- been one of its core strengths, but often extra libraries to do the integration
- were required. Since jBPM4 however, it is now possible to natively
- integrate jBPM with <ulink url="http://www.springsource.org/about">Spring</ulink>.
- This section will explain which steps are required for such an integration.
- </para>
-
- <para>
- The Spring integration has started out as a community effort by
- <ulink url="http://www.inze.be/andries/">Andries Inzé</ulink>.
- Do note that Spring integration currently is in 'incubation', before
- it is moved to the user guide.
- </para>
-
- <section id="spring_overview">
- <title>Overview</title>
- <para>
- The default jBPM behaviour is to open a transaction for each operation
- that is called on the service API. In a typical Spring setup, applications are
- accessed from the web tier and enter a transactional boundary by invoking
- operations on service beans. These service beans will then access the jBPM services.
- All these operations run typically in a single transaction (ie one transaction
- per request from the browser), which invalidates the standard jBPM
- transaction handling approach. Instead of starting and committing
- a transaction for every service operation, the existing transaction
- should be used (or a new one started if none exists).
- </para>
- </section>
-
- <section id="spring_configuration">
- <title>Configuration</title>
- <para>
- Replace the standard-transaction-interceptor with the
- spring-transaction-interceptor. The hibernate session needs the attribute current=”true”.
- This forces jBPM to search for the current session,
- which will be provided by Spring.
- <programlisting>
- <process-engine-context>
- <command-service>
- <emphasis role="bold"><spring-transaction-interceptor /></emphasis>
- ...
- </command-service>
- ...
- </process-engine-context>
- <transaction-context>
- ...
- <emphasis role="bold"><hibernate-session current="true"/></emphasis>
- </transaction-context>
- </programlisting>
- </para>
-
- <para>
- The Spring integration provides a special context, which is added to
- the set of context where the jBPM engine will look for beans.
- Using this SpringContext, it is now possible to retrieve beans from the
- Spring Application Context. For the Spring context to be known, a
- SpringConfiguration must be created. This class extends the JbpmConfiguration
- but will add itself as a context. The single constructor take the location of the jBPM configuration.
-
- <programlisting>
- <bean id="jbpmConfiguration" class="org.jbpm.pvm.internal.cfg.SpringConfiguration">
- <constructor-arg value="be/inze/spring/demo/jbpm.cfg.xml" />
- </bean>
- </programlisting>
- </para>
-
- <para>
- The jBPM services can also be defined in the Spring applicationContext, as following:
- <programlisting>
-<bean id="processEngine" factory-bean="jbpmConfiguration" factory-method="buildProcessEngine" />
-<bean id="repositoryService" factory-bean="processEngine" factory-method="getRepositoryService" />
-<bean id="executionService" factory-bean="processEngine" factory-method="getExecutionService" />
- </programlisting>
- </para>
-
- <para>
- For accessing Spring beans from withing a process, we need to register
- the Spring applicationContext with the scripting-manager.
-
- <programlisting>
- <script-manager default-expression-language="juel"
- default-script-language="juel"
- read-contexts="execution, environment, process-engine, <emphasis role="bold">spring</emphasis>"
- write-context="">
- <script-language name="juel"
- factory="org.jbpm.pvm.internal.script.JuelScriptEngineFactory" />
- </script-manager>
- </programlisting>
- </para>
- </section>
-
- <section id="spring_usage">
- <title>Usage</title>
-
- <para>
- The previous section already showed how the jBPM services can be made
- accessible for other Spring services. The other use case is calling
- Spring beans from within a process. This can be done by using
- an expression which resolves to the name of a Spring bean.
-
- <programlisting>
-<java name="echo" expr="#{echoService}" method="sayHello" >
- <transition name="to accept" to="join1"/>
- </java>
- </programlisting>
-
- The scripting engine will look into all contexts from the bean named echoService.
- If you configured the ScriptManager as above, Spring will be the last context to search for.
- You can also add a Spring bean to the Spring Application context
- (eg IdentitySessionImpl with id <emphasis role="italic">identitySession</emphasis>)
- and use it in the jBPM config (eg by adding <env class="identitySession" />)
- </para>
-
- </section>
-
- <section id="spring_testing">
- <title>Testing</title>
-
- <para>
- Use the <emphasis role="bold">AbstractTransactionalJbpmTestCase</emphasis>
- to test a process in isolation (ie without impact on the database).
- This class extends from
- the <emphasis role="italic">AbstractTransactionalDataSourceSpringContextTests</emphasis>
- class, which means that testing a process comes down to exactly the same
- approach as testing a DAO.
- </para>
-
- </section>
-
-
-
-</chapter>
Deleted: jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch15-Jpdl3Migration.xml
===================================================================
--- jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch15-Jpdl3Migration.xml 2009-07-03 11:46:43 UTC (rev 5214)
+++ jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch15-Jpdl3Migration.xml 2009-07-03 12:21:36 UTC (rev 5215)
@@ -1,84 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<chapter id="jpdl3Migration">
- <title>JPDL3 migration</title>
-
- <para>
- In many cases, a lot of work has been put in the design of JPDL3 process
- definitions. To avoid a complete manual translation of these processes to the
- JPDL4 format, the jBPM distribution contains a subdirectory called
- <emphasis role="bold">migration</emphasis>, which contains a command-line
- tool for converting JPDL3 process definition files to JPDL process XML files.
- </para>
-
- <para>
- The tool itself uses only dom4j to do the translation between
- the two formats and should be easy extensible (the source code is also in
- the same directory). The design of the tool is deliberately kept very simple
- (ie most of the logic can be found in the <emphasis role="bold">Jpdl3Converter</emphasis> class).
- Note that this tool is experimental and tested only a small set of JPDL3
- process files.
- </para>
-
- <section id="migration_overview">
- <title>Overview</title>
- <para>
- The jPDL Conversion tool takes a jpdl3 process file as input, and
- converts it to a jpdl4 process file.
- </para>
- <para>
- Syntax:
- <programlisting>java org.jbpm.jpdl.internal.convert.JpdlConverterTool -v -o <outputfile> <processfile></programlisting>
- </para>
- </section>
-
- <section id="migration_arguments">
- <title>Arguments</title>
- <itemizedlist>
- <listitem>
- <emphasis role="bold">-v (verbose):</emphasis> The tool will print the detail
- messages while converting the process file. When this argument is used,
- it will also print the error stacktrace if exceptions are thrown.
- </listitem>
- <listitem>
- <emphasis role="bold">-o (output)</emphasis> Specifies the output file name.
- By default, the tool will generate a file name ending in 'converted.jpdl.xml'
- using as a base file name the name derived from the input process file.
- The output-filename can be an absolute file name path or a relative file name path.
- </listitem>
- </itemizedlist>
- </section>
-
- <section id="migration_examples">
- <title>Usage examples</title>
- <programlisting>
- java -jar jpdl-migration-XX.jar simple.jpdl.xml
- java -jar jpdl-migration-XX.jar -v simple.jpdl.xml
- java -jar jpdl-migration-XX.jar -o /home/scott/simple.converted.xml simple.jpdl.xml
- </programlisting>
- </section>
-
- <section id="migration_integration">
- <title>Advanced</title>
- <para>
- The conversion tool can easily be integrated with regular Java code
- (or with Maven or Ant). The following code example shows how to call the
- internal api to convert the process file:
- <programlisting>
- URL url = new URL("simple.jpdl");
- Jpdl3Converter jpdlConverter = new Jpdl3Converter(url);
- Document jpdl4Doc = jpdlConverter.readAndConvert();
-
- for (Problem problem : jpdlConverter.problems) {
- //do something to handle the problem
- }
-
- Writer fileWriter = new FileWriter(outputFile);
- OutputFormat format = OutputFormat.createPrettyPrint();
- XMLWriter writer = new XMLWriter( fileWriter, format );
- writer.write(jpdl4Doc);
- writer.close();
- </programlisting>
- </para>
- </section>
-
-</chapter>
Copied: jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch15-SpringIntegration.xml (from rev 5210, jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch14-SpringIntegration.xml)
===================================================================
--- jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch15-SpringIntegration.xml (rev 0)
+++ jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch15-SpringIntegration.xml 2009-07-03 12:21:36 UTC (rev 5215)
@@ -0,0 +1,137 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<chapter id="springIntegration">
+ <title>Spring Integration</title>
+
+ <para>
+ The embeddability of the jBPM engine in different environments has always
+ been one of its core strengths, but often extra libraries to do the integration
+ were required. Since jBPM4 however, it is now possible to natively
+ integrate jBPM with <ulink url="http://www.springsource.org/about">Spring</ulink>.
+ This section will explain which steps are required for such an integration.
+ </para>
+
+ <para>
+ The Spring integration has started out as a community effort by
+ <ulink url="http://www.inze.be/andries/">Andries Inzé</ulink>.
+ Do note that Spring integration currently is in 'incubation', before
+ it is moved to the user guide.
+ </para>
+
+ <section id="spring_overview">
+ <title>Overview</title>
+ <para>
+ The default jBPM behaviour is to open a transaction for each operation
+ that is called on the service API. In a typical Spring setup, applications are
+ accessed from the web tier and enter a transactional boundary by invoking
+ operations on service beans. These service beans will then access the jBPM services.
+ All these operations run typically in a single transaction (ie one transaction
+ per request from the browser), which invalidates the standard jBPM
+ transaction handling approach. Instead of starting and committing
+ a transaction for every service operation, the existing transaction
+ should be used (or a new one started if none exists).
+ </para>
+ </section>
+
+ <section id="spring_configuration">
+ <title>Configuration</title>
+ <para>
+ Replace the standard-transaction-interceptor with the
+ spring-transaction-interceptor. The hibernate session needs the attribute current=”true”.
+ This forces jBPM to search for the current session,
+ which will be provided by Spring.
+ <programlisting>
+ <process-engine-context>
+ <command-service>
+ <emphasis role="bold"><spring-transaction-interceptor /></emphasis>
+ ...
+ </command-service>
+ ...
+ </process-engine-context>
+ <transaction-context>
+ ...
+ <emphasis role="bold"><hibernate-session current="true"/></emphasis>
+ </transaction-context>
+ </programlisting>
+ </para>
+
+ <para>
+ The Spring integration provides a special context, which is added to
+ the set of context where the jBPM engine will look for beans.
+ Using this SpringContext, it is now possible to retrieve beans from the
+ Spring Application Context. For the Spring context to be known, a
+ SpringConfiguration must be created. This class extends the JbpmConfiguration
+ but will add itself as a context. The single constructor take the location of the jBPM configuration.
+
+ <programlisting>
+ <bean id="jbpmConfiguration" class="org.jbpm.pvm.internal.cfg.SpringConfiguration">
+ <constructor-arg value="be/inze/spring/demo/jbpm.cfg.xml" />
+ </bean>
+ </programlisting>
+ </para>
+
+ <para>
+ The jBPM services can also be defined in the Spring applicationContext, as following:
+ <programlisting>
+<bean id="processEngine" factory-bean="jbpmConfiguration" factory-method="buildProcessEngine" />
+<bean id="repositoryService" factory-bean="processEngine" factory-method="getRepositoryService" />
+<bean id="executionService" factory-bean="processEngine" factory-method="getExecutionService" />
+ </programlisting>
+ </para>
+
+ <para>
+ For accessing Spring beans from withing a process, we need to register
+ the Spring applicationContext with the scripting-manager.
+
+ <programlisting>
+ <script-manager default-expression-language="juel"
+ default-script-language="juel"
+ read-contexts="execution, environment, process-engine, <emphasis role="bold">spring</emphasis>"
+ write-context="">
+ <script-language name="juel"
+ factory="org.jbpm.pvm.internal.script.JuelScriptEngineFactory" />
+ </script-manager>
+ </programlisting>
+ </para>
+ </section>
+
+ <section id="spring_usage">
+ <title>Usage</title>
+
+ <para>
+ The previous section already showed how the jBPM services can be made
+ accessible for other Spring services. The other use case is calling
+ Spring beans from within a process. This can be done by using
+ an expression which resolves to the name of a Spring bean.
+
+ <programlisting>
+<java name="echo" expr="#{echoService}" method="sayHello" >
+ <transition name="to accept" to="join1"/>
+ </java>
+ </programlisting>
+
+ The scripting engine will look into all contexts from the bean named echoService.
+ If you configured the ScriptManager as above, Spring will be the last context to search for.
+ You can also add a Spring bean to the Spring Application context
+ (eg IdentitySessionImpl with id <emphasis role="italic">identitySession</emphasis>)
+ and use it in the jBPM config (eg by adding <env class="identitySession" />)
+ </para>
+
+ </section>
+
+ <section id="spring_testing">
+ <title>Testing</title>
+
+ <para>
+ Use the <emphasis role="bold">AbstractTransactionalJbpmTestCase</emphasis>
+ to test a process in isolation (ie without impact on the database).
+ This class extends from
+ the <emphasis role="italic">AbstractTransactionalDataSourceSpringContextTests</emphasis>
+ class, which means that testing a process comes down to exactly the same
+ approach as testing a DAO.
+ </para>
+
+ </section>
+
+
+
+</chapter>
Copied: jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch16-Jpdl3Migration.xml (from rev 5210, jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch15-Jpdl3Migration.xml)
===================================================================
--- jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch16-Jpdl3Migration.xml (rev 0)
+++ jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch16-Jpdl3Migration.xml 2009-07-03 12:21:36 UTC (rev 5215)
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<chapter id="jpdl3Migration">
+ <title>JPDL3 migration</title>
+
+ <para>
+ In many cases, a lot of work has been put in the design of JPDL3 process
+ definitions. To avoid a complete manual translation of these processes to the
+ JPDL4 format, the jBPM distribution contains a subdirectory called
+ <emphasis role="bold">migration</emphasis>, which contains a command-line
+ tool for converting JPDL3 process definition files to JPDL process XML files.
+ </para>
+
+ <para>
+ The tool itself uses only dom4j to do the translation between
+ the two formats and should be easy extensible (the source code is also in
+ the same directory). The design of the tool is deliberately kept very simple
+ (ie most of the logic can be found in the <emphasis role="bold">Jpdl3Converter</emphasis> class).
+ Note that this tool is experimental and tested only a small set of JPDL3
+ process files.
+ </para>
+
+ <section id="migration_overview">
+ <title>Overview</title>
+ <para>
+ The jPDL Conversion tool takes a jpdl3 process file as input, and
+ converts it to a jpdl4 process file.
+ </para>
+ <para>
+ Syntax:
+ <programlisting>java org.jbpm.jpdl.internal.convert.JpdlConverterTool -v -o <outputfile> <processfile></programlisting>
+ </para>
+ </section>
+
+ <section id="migration_arguments">
+ <title>Arguments</title>
+ <itemizedlist>
+ <listitem>
+ <emphasis role="bold">-v (verbose):</emphasis> The tool will print the detail
+ messages while converting the process file. When this argument is used,
+ it will also print the error stacktrace if exceptions are thrown.
+ </listitem>
+ <listitem>
+ <emphasis role="bold">-o (output)</emphasis> Specifies the output file name.
+ By default, the tool will generate a file name ending in 'converted.jpdl.xml'
+ using as a base file name the name derived from the input process file.
+ The output-filename can be an absolute file name path or a relative file name path.
+ </listitem>
+ </itemizedlist>
+ </section>
+
+ <section id="migration_examples">
+ <title>Usage examples</title>
+ <programlisting>
+ java -jar jpdl-migration-XX.jar simple.jpdl.xml
+ java -jar jpdl-migration-XX.jar -v simple.jpdl.xml
+ java -jar jpdl-migration-XX.jar -o /home/scott/simple.converted.xml simple.jpdl.xml
+ </programlisting>
+ </section>
+
+ <section id="migration_integration">
+ <title>Advanced</title>
+ <para>
+ The conversion tool can easily be integrated with regular Java code
+ (or with Maven or Ant). The following code example shows how to call the
+ internal api to convert the process file:
+ <programlisting>
+ URL url = new URL("simple.jpdl");
+ Jpdl3Converter jpdlConverter = new Jpdl3Converter(url);
+ Document jpdl4Doc = jpdlConverter.readAndConvert();
+
+ for (Problem problem : jpdlConverter.problems) {
+ //do something to handle the problem
+ }
+
+ Writer fileWriter = new FileWriter(outputFile);
+ OutputFormat format = OutputFormat.createPrettyPrint();
+ XMLWriter writer = new XMLWriter( fileWriter, format );
+ writer.write(jpdl4Doc);
+ writer.close();
+ </programlisting>
+ </para>
+ </section>
+
+</chapter>
Modified: jbpm4/trunk/modules/userguide/src/main/docbook/en/master.xml
===================================================================
--- jbpm4/trunk/modules/userguide/src/main/docbook/en/master.xml 2009-07-03 11:46:43 UTC (rev 5214)
+++ jbpm4/trunk/modules/userguide/src/main/docbook/en/master.xml 2009-07-03 12:21:36 UTC (rev 5215)
@@ -10,7 +10,6 @@
<!ENTITY ch07-Variables SYSTEM "modules/ch07-Variables.xml">
<!ENTITY ch08-Scripting SYSTEM "modules/ch08-Scripting.xml">
<!ENTITY ch09-Identity SYSTEM "modules/ch09-Identity.xml">
- <!ENTITY ch11-Emails SYSTEM "modules/ch11-Emails.xml">
]>
<book lang="en">
@@ -30,6 +29,5 @@
&ch07-Variables;
&ch08-Scripting;
&ch09-Identity;
- &ch11-Emails;
</book>
\ No newline at end of file
Modified: jbpm4/trunk/modules/userguide/src/main/docbook/en/modules/ch06-Jpdl.xml
===================================================================
--- jbpm4/trunk/modules/userguide/src/main/docbook/en/modules/ch06-Jpdl.xml 2009-07-03 11:46:43 UTC (rev 5214)
+++ jbpm4/trunk/modules/userguide/src/main/docbook/en/modules/ch06-Jpdl.xml 2009-07-03 12:21:36 UTC (rev 5215)
@@ -1233,8 +1233,6 @@
<notification/>
<reminder duedate="2 days" repeat="1 day"/>
</task>]]></programlisting>
- <para>Refer to the <link linkend="mailsupport">mail chapter</link> for full details
- on mail support.</para>
</section>
</section>
@@ -2313,8 +2311,44 @@
</tbody>
</tgroup>
</table>
- <para>Refer to the <link linkend="mailsupport">mail chapter</link> for full details
- on mail support.</para>
+
+ <para>
+ Example usage:
+ <programlisting>
+<process name="InlineMail" xmlns="http://jbpm.org/4.0/jpdl">
+ <start>
+ <transition to="send birthday reminder note" />
+ </start>
+ <mail name="send birthday reminder note">
+ <to addresses="johnDoe(a)some-company.com" />
+ <subject>Reminder: ${person} celebrates his birthday!</subject>
+ <text>Do not forget: ${date} is the birthday of ${person} </text>
+ <transition to="end" />
+ </mail>
+ <state name="end"/>
+</process>
+ </programlisting>
+ </para>
+
+ <para>
+ The examples in the distribution contain some processes using the mail
+ activity. If you want to change the SMTP server, you can adjust the
+ <emphasis role="bold">jbpm.mail.properties</emphasis> file, which is
+ imported in the examples jBPM configuration file as follows:
+
+ <programlisting>
+<transaction-context>
+ ...
+ <mail-session>
+ <mail-server>
+ <session-properties resource="jbpm.mail.properties" />
+ </mail-server>
+ </mail-session>
+</transaction-context>
+ </programlisting>
+ </para>
+
+ <para>Refer to the Developers Guide for advanced mail configuration and usage.</para>
</section>
</section>
16 years, 10 months
JBoss JBPM SVN: r5214 - projects.
by do-not-reply@jboss.org
Author: tom.baeyens(a)jboss.com
Date: 2009-07-03 07:46:43 -0400 (Fri, 03 Jul 2009)
New Revision: 5214
Added:
projects/kunsole/
Removed:
projects/kukeltjes-console/
Log:
renaming kukeltjes console
Copied: projects/kunsole (from rev 5213, projects/kukeltjes-console)
16 years, 10 months