[seam-commits] Seam SVN: r10631 - in modules/trunk: bpm and 7 other directories.
seam-commits at lists.jboss.org
seam-commits at lists.jboss.org
Fri Apr 24 19:24:15 EDT 2009
Author: shane.bryzak at jboss.com
Date: 2009-04-24 19:24:14 -0400 (Fri, 24 Apr 2009)
New Revision: 10631
Added:
modules/trunk/bpm/
modules/trunk/bpm/pom.xml
modules/trunk/bpm/src/
modules/trunk/bpm/src/main/
modules/trunk/bpm/src/main/java/
modules/trunk/bpm/src/main/java/org/
modules/trunk/bpm/src/main/java/org/jboss/
modules/trunk/bpm/src/main/java/org/jboss/seam/
modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/
modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/Actor.java
modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/BusinessProcess.java
modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/BusinessProcessInterceptor.java
modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/Jbpm.java
modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/JbpmELResolver.java
modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/ManagedJbpmContext.java
modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/PageflowDeploymentHandler.java
modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/PageflowParser.java
modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/PooledTask.java
modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/PooledTaskInstanceList.java
modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/ProcessInstance.java
modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/ProcessInstanceFinder.java
modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/SeamExpressionEvaluator.java
modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/SeamUserCodeInterceptor.java
modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/TaskInstance.java
modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/TaskInstanceList.java
modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/TaskInstanceListForType.java
modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/TaskInstancePriorityList.java
modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/Transition.java
modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/jbpm.pageflow.cfg.xml
modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/package-info.java
Log:
initial import of bpm module
Added: modules/trunk/bpm/pom.xml
===================================================================
--- modules/trunk/bpm/pom.xml (rev 0)
+++ modules/trunk/bpm/pom.xml 2009-04-24 23:24:14 UTC (rev 10631)
@@ -0,0 +1,32 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <artifactId>seam-parent</artifactId>
+ <groupId>org.jboss.seam</groupId>
+ <version>3.0.0-SNAPSHOT</version>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.jboss.seam</groupId>
+ <artifactId>seam-bpm</artifactId>
+ <packaging>jar</packaging>
+ <version>3.0.0-SNAPSHOT</version>
+ <name>Seam BPM</name>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.jboss.webbeans</groupId>
+ <artifactId>jsr299-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.webbeans</groupId>
+ <artifactId>webbeans-logging</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.jbpm</groupId>
+ <artifactId>jbpm-jpdl</artifactId>
+ </dependency>
+ </dependencies>
+
+</project>
Added: modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/Actor.java
===================================================================
--- modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/Actor.java (rev 0)
+++ modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/Actor.java 2009-04-24 23:24:14 UTC (rev 10631)
@@ -0,0 +1,105 @@
+package org.jboss.seam.bpm;
+
+import java.io.Serializable;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import javax.annotation.Named;
+import javax.context.SessionScoped;
+
+/**
+ * Allows the application to specify the jBPM actorId
+ * during the login cycle.
+ *
+ * @author Gavin King
+ */
+ at Named
+ at SessionScoped
+public class Actor extends AbstractMutable implements Serializable
+{
+ private static final long serialVersionUID = -6515302276074415520L;
+ private String id;
+ private Set<String> groupActorIds = new HashSet<String>()
+ {
+ @Override
+ public boolean add(String o)
+ {
+ boolean dirty = super.add(o);
+ if (dirty) setDirty();
+ return dirty;
+ }
+
+ @Override
+ public void clear()
+ {
+ if (size() > 0) setDirty();
+ super.clear();
+ }
+
+ @Override
+ public boolean remove(Object o)
+ {
+ boolean dirty = super.remove(o);
+ if (dirty) setDirty();
+ return dirty;
+ }
+
+ @Override
+ public Iterator<String> iterator()
+ {
+ final Iterator<String> it = super.iterator();
+ return new Iterator<String>()
+ {
+
+ public boolean hasNext()
+ {
+ return it.hasNext();
+ }
+
+ public String next()
+ {
+ return it.next();
+ }
+
+ public void remove()
+ {
+ setDirty();
+ it.remove();
+ }
+
+ };
+ }
+ };
+
+ public String getId()
+ {
+ return id;
+ }
+ public void setId(String id)
+ {
+ setDirty(this.id, id);
+ this.id = id;
+ }
+
+ public Set<String> getGroupActorIds()
+ {
+ return groupActorIds;
+ }
+ public static Actor instance()
+ {
+ if ( !Contexts.isSessionContextActive() )
+ {
+ throw new IllegalStateException("No active session context");
+ }
+ return (Actor) Component.getInstance(Actor.class);
+ }
+
+ @Override
+ public String toString()
+ {
+ return "Actor(" + id + ")";
+ }
+}
+
+
\ No newline at end of file
Added: modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/BusinessProcess.java
===================================================================
--- modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/BusinessProcess.java (rev 0)
+++ modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/BusinessProcess.java 2009-04-24 23:24:14 UTC (rev 10631)
@@ -0,0 +1,421 @@
+package org.jboss.seam.bpm;
+
+import java.io.Serializable;
+
+import javax.annotation.Named;
+import javax.context.ConversationScoped;
+
+import org.jboss.seam.international.StatusMessage;
+import org.jboss.seam.international.StatusMessages;
+import org.jbpm.graph.def.ProcessDefinition;
+import org.jbpm.graph.exe.ProcessInstance;
+import org.jbpm.taskmgmt.exe.TaskInstance;
+
+/**
+ * Holds the task and process ids for the current conversation,
+ * and provides programmatic control over the business process.
+ *
+ * @author Gavin King
+ *
+ */
+ at Named
+ at ConversationScoped
+public class BusinessProcess extends AbstractMutable implements Serializable
+{
+ private static final long serialVersionUID = 4722350870845851070L;
+
+ private Long processId;
+ private Long taskId;
+
+ public static BusinessProcess instance()
+ {
+ if ( !Contexts.isConversationContextActive() )
+ {
+ throw new IllegalStateException("No active conversation context");
+ }
+ return (BusinessProcess) Component.getInstance(BusinessProcess.class, ScopeType.CONVERSATION);
+ }
+
+ /**
+ * Is there a process instance associated with
+ * the current conversation?
+ */
+ public boolean hasCurrentProcess()
+ {
+ return processId!=null;
+ }
+
+ /**
+ * Is there a process instance that has not ended
+ * associated with the current conversation?
+ */
+ public boolean hasActiveProcess()
+ {
+ return hasCurrentProcess() &&
+ !org.jboss.seam.bpm.ProcessInstance.instance().hasEnded();
+ }
+
+ /**
+ * Is there a task instance associated with
+ * the current conversation?
+ */
+ public boolean hasCurrentTask()
+ {
+ return taskId!=null;
+ }
+
+ /**
+ * The jBPM process instance id associated with
+ * the current conversation.
+ */
+ public Long getProcessId()
+ {
+ return processId;
+ }
+
+ /**
+ * Set the process instance id, without validating
+ * that the process instance actually exists.
+ */
+ public void setProcessId(Long processId)
+ {
+ setDirty(this.processId, processId);
+ this.processId = processId;
+ }
+
+ /**
+ * The jBPM task instance id associated with
+ * the current conversation.
+ */
+ public Long getTaskId()
+ {
+ return taskId;
+ }
+
+ /**
+ * Set the task instance id, without validating
+ * that the task instance actually exists.
+ */
+ public void setTaskId(Long taskId)
+ {
+ setDirty(this.taskId, taskId);
+ this.taskId = taskId;
+ }
+
+ /**
+ * Create a process instance and associate it with the
+ * current conversation.
+ *
+ * @param processDefinitionName the jBPM process definition name
+ */
+ public void createProcess(String processDefinitionName)
+ {
+ createProcess(processDefinitionName, true);
+ }
+
+ /**
+ * Create a process instance and associate it with the
+ * current conversation.
+ *
+ * @param processDefinitionName the jBPM process definition name
+ */
+ public void createProcess(String processDefinitionName, boolean shouldSignalProcess)
+ {
+ ProcessInstance process = ManagedJbpmContext.instance().newProcessInstanceForUpdate(processDefinitionName);
+ afterCreateProcess(processDefinitionName, process, shouldSignalProcess);
+ }
+
+ /**
+ * Create a process instance and associate it with the
+ * current conversation.
+ *
+ * @param processDefinitionName the jBPM process definition name
+ * @param businessKey the business key of the new process definition
+ */
+ public void createProcess(String processDefinitionName, String businessKey)
+ {
+ /*ProcessInstance process = ManagedJbpmContext.instance().getGraphSession()
+ .findLatestProcessDefinition(processDefinitionName)
+ .createProcessInstance(Collections.EMPTY_MAP, businessKey);*/
+ ProcessInstance process = ManagedJbpmContext.instance().newProcessInstanceForUpdate(processDefinitionName);
+ process.setKey(businessKey);
+ afterCreateProcess(processDefinitionName, process, true);
+ }
+
+ private void afterCreateProcess(String processDefinitionName, ProcessInstance process, boolean shouldSignalProcess)
+ {
+ setProcessId( process.getId() );
+ // need to set process variables before the signal
+ Contexts.getBusinessProcessContext().flush();
+ if (shouldSignalProcess) {
+ process.signal();
+ }
+
+ Events.instance().raiseEvent("org.jboss.seam.createProcess." + processDefinitionName);
+ }
+
+ /**
+ * Start the current task, using the current actor id
+ *
+ * @see Actor
+ */
+ public void startTask()
+ {
+ String actorId = Actor.instance().getId();
+ TaskInstance task = org.jboss.seam.bpm.TaskInstance.instance();
+ if ( actorId != null )
+ {
+ task.start(actorId);
+ }
+ else
+ {
+ task.start();
+ }
+
+ Events.instance().raiseEvent("org.jboss.seam.startTask." + task.getTask().getName());
+ }
+
+ /**
+ * End the current task, via the given transition. If no transition name
+ * is given, check the Transition component for a transition, or use the
+ * default transition.
+ *
+ * @param transitionName the jBPM transition name, or null
+ */
+ public void endTask(String transitionName)
+ {
+ TaskInstance task = org.jboss.seam.bpm.TaskInstance.instance();
+ if (task==null)
+ {
+ throw new IllegalStateException( "no task instance associated with context" );
+ }
+
+ if ( transitionName==null || "".equals(transitionName) )
+ {
+ transitionName = Transition.instance().getName();
+ }
+
+ if (transitionName==null)
+ {
+ task.end();
+ }
+ else
+ {
+ task.end(transitionName);
+ }
+
+ setTaskId(null); //TODO: do I really need this???!
+
+ Events.instance().raiseEvent("org.jboss.seam.endTask." + task.getTask().getName());
+ ProcessInstance process = org.jboss.seam.bpm.ProcessInstance.instance();
+ if ( process.hasEnded() )
+ {
+ Events.instance().raiseEvent("org.jboss.seam.endProcess." + process.getProcessDefinition().getName());
+ }
+ }
+
+ /**
+ * Signal the given transition for the current process instance.
+ *
+ * @param transitionName the jBPM transition name
+ */
+ public void transition(String transitionName)
+ {
+ ProcessInstance process = org.jboss.seam.bpm.ProcessInstance.instance();
+ process.signal(transitionName);
+ if ( process.hasEnded() )
+ {
+ Events.instance().raiseEvent("org.jboss.seam.endProcess." + process.getProcessDefinition().getName());
+ }
+ }
+
+ /**
+ * Associate the task instance with the given id with the current
+ * conversation.
+ *
+ * @param taskId the jBPM task instance id
+ * @return true if the task was found and was not ended
+ */
+ public boolean resumeTask(Long taskId)
+ {
+ setTaskId(taskId);
+ TaskInstance task = org.jboss.seam.bpm.TaskInstance.instance();
+ if (task==null)
+ {
+ taskNotFound(taskId);
+ return false;
+ }
+ else if ( task.hasEnded() )
+ {
+ taskEnded(taskId);
+ return false;
+ }
+ else
+ {
+ setProcessId( task.getTaskMgmtInstance().getProcessInstance().getId() );
+ Events.instance().raiseEvent("org.jboss.seam.initTask." + task.getTask().getName());
+ return true;
+ }
+ }
+
+ /**
+ * Associate the process instance with the given id with the
+ * current conversation.
+ *
+ * @param processId the jBPM process instance id
+ * @return true if the process was found and was not ended
+ */
+ public boolean resumeProcess(Long processId)
+ {
+ setProcessId(processId);
+ ProcessInstance process = org.jboss.seam.bpm.ProcessInstance.instance();
+ return afterResumeProcess(processId, process);
+ }
+
+ /**
+ * Associate the process instance with the given business key
+ * with the current conversation.
+ *
+ * @param processDefinition the jBPM process definition name
+ * @param key the jBPM process instance key
+ * @return true if the process was found and was not ended
+ */
+ public boolean resumeProcess(String processDefinition, String key)
+ {
+ ProcessDefinition definition = ManagedJbpmContext.instance().getGraphSession().findLatestProcessDefinition(processDefinition);
+ ProcessInstance process = definition==null ?
+ null : ManagedJbpmContext.instance().getProcessInstanceForUpdate(definition, key);
+ if (process!=null) setProcessId( process.getId() );
+ return afterResumeProcess(key, process);
+ }
+
+ private boolean afterResumeProcess(long processId, ProcessInstance process)
+ {
+ if ( process==null )
+ {
+ processNotFound(processId);
+ return false;
+ }
+ else if ( process.hasEnded() )
+ {
+ processEnded(processId);
+ return false;
+ }
+ else
+ {
+ Events.instance().raiseEvent("org.jboss.seam.initProcess." + process.getProcessDefinition().getName());
+ return true;
+ }
+ }
+
+ private boolean afterResumeProcess(String processKey, ProcessInstance process)
+ {
+ if ( process==null )
+ {
+ processNotFound(processKey);
+ return false;
+ }
+ else if ( process.hasEnded() )
+ {
+ processEnded(processKey);
+ return false;
+ }
+ else
+ {
+ Events.instance().raiseEvent("org.jboss.seam.initProcess." + process.getProcessDefinition().getName());
+ return true;
+ }
+ }
+
+ /**
+ * Check that the task currently associated with the conversation
+ * exists and has not ended.
+ *
+ * @return true if the task exists and was not ended
+ */
+ public boolean validateTask()
+ {
+ if ( !hasCurrentTask() )
+ {
+ taskNotFound(taskId);
+ return false;
+ }
+ else if ( org.jboss.seam.bpm.TaskInstance.instance().hasEnded() )
+ {
+ taskEnded(taskId);
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+ }
+
+ protected void taskNotFound(Long taskId)
+ {
+ StatusMessages.instance().addFromResourceBundleOrDefault(
+ StatusMessage.Severity.WARN,
+ "org.jboss.seam.TaskNotFound",
+ "Task #0 not found",
+ taskId
+ );
+ }
+
+ protected void taskEnded(Long taskId)
+ {
+ StatusMessages.instance().addFromResourceBundleOrDefault(
+ StatusMessage.Severity.WARN,
+ "org.jboss.seam.TaskEnded",
+ "Task #0 already ended",
+ taskId
+ );
+ }
+
+ protected void processEnded(Long processId)
+ {
+ StatusMessages.instance().addFromResourceBundleOrDefault(
+ StatusMessage.Severity.WARN,
+ "org.jboss.seam.ProcessEnded",
+ "Process #0 already ended",
+ processId
+ );
+ }
+
+ protected void processNotFound(Long processId)
+ {
+ StatusMessages.instance().addFromResourceBundleOrDefault(
+ StatusMessage.Severity.WARN,
+ "org.jboss.seam.ProcessNotFound",
+ "Process #0 not found",
+ processId
+ );
+ }
+
+ protected void processEnded(String key)
+ {
+ StatusMessages.instance().addFromResourceBundleOrDefault(
+ StatusMessage.Severity.WARN,
+ "org.jboss.seam.ProcessEnded",
+ "Process #0 already ended",
+ key
+ );
+ }
+
+ protected void processNotFound(String key)
+ {
+ StatusMessages.instance().addFromResourceBundleOrDefault(
+ StatusMessage.Severity.WARN,
+ "org.jboss.seam.ProcessNotFound",
+ "Process #0 not found",
+ key
+ );
+ }
+
+
+ @Override
+ public String toString()
+ {
+ return "BusinessProcess(processId=" + processId + ",taskId=" + taskId + ")";
+ }
+
+}
Added: modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/BusinessProcessInterceptor.java
===================================================================
--- modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/BusinessProcessInterceptor.java (rev 0)
+++ modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/BusinessProcessInterceptor.java 2009-04-24 23:24:14 UTC (rev 10631)
@@ -0,0 +1,182 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jboss.seam.bpm;
+
+import java.lang.reflect.Method;
+
+import org.jboss.seam.annotations.bpm.BeginTask;
+import org.jboss.seam.annotations.bpm.CreateProcess;
+import org.jboss.seam.annotations.bpm.EndTask;
+import org.jboss.seam.annotations.bpm.ResumeProcess;
+import org.jboss.seam.annotations.bpm.StartTask;
+import org.jboss.seam.annotations.intercept.AroundInvoke;
+import org.jboss.seam.annotations.intercept.Interceptor;
+import org.jboss.seam.contexts.Contexts;
+import org.jboss.seam.core.BijectionInterceptor;
+import org.jboss.seam.core.Expressions;
+import org.jboss.seam.core.Init;
+import org.jboss.seam.intercept.AbstractInterceptor;
+import org.jboss.seam.intercept.InvocationContext;
+import org.jboss.seam.log.LogProvider;
+import org.jboss.seam.log.Logging;
+import org.jboss.seam.util.Strings;
+import org.jboss.seam.web.Parameters;
+
+/**
+ * Implements annotation-based business-process demarcation.
+ *
+ * @author <a href="mailto:steve at hibernate.org">Steve Ebersole</a>
+ * @author Gavin King
+ */
+ at Interceptor(stateless=true, around=BijectionInterceptor.class)
+public class BusinessProcessInterceptor extends AbstractInterceptor
+{
+ private static final long serialVersionUID = 758197867958840918L;
+
+ private static final LogProvider log = Logging.getLogProvider( BusinessProcessInterceptor.class );
+
+ @AroundInvoke
+ public Object aroundInvoke(InvocationContext invocation) throws Exception
+ {
+ if ( !beforeInvocation(invocation) )
+ {
+ return null;
+ }
+ else
+ {
+ return afterInvocation( invocation, invocation.proceed() );
+ }
+ }
+
+ private boolean beforeInvocation(InvocationContext invocationContext)
+ {
+ Method method = invocationContext.getMethod();
+ if ( method.isAnnotationPresent(StartTask.class) )
+ {
+ log.trace( "encountered @StartTask" );
+ StartTask tag = method.getAnnotation(StartTask.class);
+ Long taskId = getProcessOrTaskId( tag.taskIdParameter(), tag.taskId() );
+ return BusinessProcess.instance().resumeTask(taskId);
+ }
+ else if ( method.isAnnotationPresent(BeginTask.class) )
+ {
+ log.trace( "encountered @BeginTask" );
+ BeginTask tag = method.getAnnotation(BeginTask.class);
+ Long taskId = getProcessOrTaskId( tag.taskIdParameter(), tag.taskId() );
+ return BusinessProcess.instance().resumeTask(taskId);
+ }
+ else if ( method.isAnnotationPresent(ResumeProcess.class) )
+ {
+ log.trace( "encountered @ResumeProcess" );
+ ResumeProcess tag = method.getAnnotation(ResumeProcess.class);
+ if ( tag.processKey().equals("") )
+ {
+ Long processId = getProcessOrTaskId( tag.processIdParameter(), tag.processId() );
+ return BusinessProcess.instance().resumeProcess(processId);
+ }
+ else
+ {
+ return BusinessProcess.instance().resumeProcess( tag.definition(), getProcessKey( tag.processKey() ) );
+ }
+ }
+ if ( method.isAnnotationPresent(EndTask.class) )
+ {
+ log.trace( "encountered @EndTask" );
+ return BusinessProcess.instance().validateTask();
+ }
+ else
+ {
+ return true;
+ }
+ }
+
+ private Object afterInvocation(InvocationContext invocation, Object result)
+ {
+ Method method = invocation.getMethod();
+ if ( result!=null || method.getReturnType().equals(void.class) ) //interpreted as "redisplay"
+ {
+ if ( method.isAnnotationPresent(CreateProcess.class) )
+ {
+ log.trace( "encountered @CreateProcess" );
+ CreateProcess tag = method.getAnnotation(CreateProcess.class);
+ if ( tag.processKey().equals("") )
+ {
+ BusinessProcess.instance().createProcess( tag.definition() );
+ }
+ else
+ {
+ BusinessProcess.instance().createProcess( tag.definition(), getProcessKey( tag.processKey() ) );
+ }
+ }
+ if ( method.isAnnotationPresent(StartTask.class) )
+ {
+ log.trace( "encountered @StartTask" );
+ BusinessProcess.instance().startTask();
+ }
+ if ( method.isAnnotationPresent(EndTask.class) )
+ {
+ log.trace( "encountered @EndTask" );
+ BusinessProcess.instance().endTask( method.getAnnotation(EndTask.class).transition() );
+ }
+ if ( method.isAnnotationPresent(org.jboss.seam.annotations.bpm.Transition.class) )
+ {
+ log.trace( "encountered @Transition" );
+ String transitionName = method.getAnnotation(org.jboss.seam.annotations.bpm.Transition.class).value();
+ if ( "".equals(transitionName) ) transitionName = method.getName();
+ BusinessProcess.instance().transition(transitionName);
+ }
+ }
+ return result;
+ }
+
+ private String getProcessKey(String el)
+ {
+ Object key = Expressions.instance().createValueExpression(el).getValue();
+ if (key==null)
+ {
+ throw new IllegalStateException("process business key may not be null");
+ }
+ return key.toString();
+ }
+
+ private Long getProcessOrTaskId(String paramName, String el)
+ {
+ Object id;
+ if ( Strings.isEmpty(paramName) )
+ {
+ id = Expressions.instance().createValueExpression(el).getValue();
+ }
+ else
+ {
+ String[] values = Parameters.instance().getRequestParameters().get(paramName);
+ id = values!=null && values.length==1 ? values[0] : null;
+ }
+
+ if (id==null)
+ {
+ throw new IllegalStateException("task/process id may not be null");
+ }
+ else if (id instanceof Long)
+ {
+ return (Long) id;
+ }
+ else if (id instanceof String)
+ {
+ return new Long( (String) id );
+ }
+ else
+ {
+ throw new IllegalArgumentException("task/process id must be a string or long");
+ }
+ }
+
+ public boolean isInterceptorEnabled()
+ {
+ return Contexts.isApplicationContextActive() && Init.instance().isJbpmInstalled();
+ }
+
+}
Added: modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/Jbpm.java
===================================================================
--- modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/Jbpm.java (rev 0)
+++ modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/Jbpm.java 2009-04-24 23:24:14 UTC (rev 10631)
@@ -0,0 +1,367 @@
+package org.jboss.seam.bpm;
+
+import java.io.InputStream;
+import java.io.StringReader;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import javax.annotation.Named;
+import javax.context.ApplicationScoped;
+import javax.inject.Initializer;
+import javax.naming.NamingException;
+
+import org.dom4j.Element;
+import org.hibernate.HibernateException;
+import org.hibernate.cfg.Environment;
+import org.hibernate.lob.ReaderInputStream;
+import org.jboss.seam.contexts.Contexts;
+import org.jboss.seam.core.Init;
+import org.jboss.seam.core.ResourceLoader;
+import org.jboss.seam.deployment.DeploymentStrategy;
+import org.jboss.seam.deployment.FileDescriptor;
+import org.jboss.seam.deployment.StandardDeploymentStrategy;
+import org.jboss.webbeans.log.LogProvider;
+import org.jboss.webbeans.log.Logging;
+import org.jboss.seam.util.Naming;
+import org.jboss.seam.util.Resources;
+import org.jbpm.JbpmConfiguration;
+import org.jbpm.JbpmContext;
+import org.jbpm.graph.def.ProcessDefinition;
+import org.jbpm.graph.node.DbSubProcessResolver;
+import org.jbpm.graph.node.ProcessState;
+import org.jbpm.graph.node.SubProcessResolver;
+import org.jbpm.instantiation.UserCodeInterceptorConfig;
+import org.jbpm.jpdl.JpdlException;
+import org.jbpm.jpdl.el.impl.JbpmExpressionEvaluator;
+import org.jbpm.persistence.db.DbPersistenceServiceFactory;
+import org.xml.sax.InputSource;
+
+/**
+ * A seam component that boostraps a JBPM SessionFactory
+ *
+ * @author Gavin King
+ * @author <a href="mailto:steve at hibernate.org">Steve Ebersole</a>
+ * @author Norman Richards
+ * @author <a href="mailto:theute at jboss.org">Thomas Heute</a>
+ */
+ at Named
+ at ApplicationScoped
+public class Jbpm
+{
+ private static final LogProvider log = Logging.getLogProvider(Jbpm.class);
+
+ private JbpmConfiguration jbpmConfiguration;
+ private String jbpmConfigurationJndiName;
+ private String[] processDefinitions;
+ private String[] pageflowDefinitions;
+ private Map<String, ProcessDefinition> pageflowProcessDefinitions = new HashMap<String, ProcessDefinition>();
+
+ @Initializer
+ public void startup() throws Exception
+ {
+ log.trace( "Starting jBPM" );
+ ProcessState.setDefaultSubProcessResolver( new SeamSubProcessResolver() );
+ installProcessDefinitions();
+ installPageflowDefinitions();
+ //JbpmExpressionEvaluator.setVariableResolver( new SeamVariableResolver() );
+ //JbpmExpressionEvaluator.setFunctionMapper( new SeamFunctionMapper() );
+ JbpmExpressionEvaluator.setExpressionEvaluator( new SeamExpressionEvaluator() );
+ UserCodeInterceptorConfig.setUserCodeInterceptor( new SeamUserCodeInterceptor() );
+ }
+
+ @Destroy
+ public void shutdown()
+ {
+ if (jbpmConfiguration!=null)
+ {
+ jbpmConfiguration.close();
+ }
+ }
+
+ public JbpmConfiguration getJbpmConfiguration()
+ {
+ if (jbpmConfiguration==null)
+ {
+ initJbpmConfiguration();
+ }
+ return jbpmConfiguration;
+ }
+
+ private void initJbpmConfiguration()
+ {
+ if (jbpmConfigurationJndiName==null)
+ {
+ jbpmConfiguration = JbpmConfiguration.getInstance();
+ }
+ else
+ {
+ try
+ {
+ jbpmConfiguration = (JbpmConfiguration) Naming.getInitialContext().lookup(jbpmConfigurationJndiName);
+ }
+ catch (NamingException ne)
+ {
+ throw new IllegalArgumentException("JbpmConfiguration not found in JNDI", ne);
+ }
+ }
+
+ DbPersistenceServiceFactory dbpsf = (DbPersistenceServiceFactory) jbpmConfiguration.getServiceFactory("persistence");
+ if (Naming.getInitialContextProperties()!=null)
+ {
+ // Prefix regular JNDI properties for Hibernate
+ Hashtable<String, String> hash = Naming.getInitialContextProperties();
+ Properties prefixed = new Properties();
+ for (Map.Entry<String, String> entry: hash.entrySet() )
+ {
+ prefixed.setProperty( Environment.JNDI_PREFIX + "." + entry.getKey(), entry.getValue() );
+ }
+
+ try
+ {
+ dbpsf.getConfiguration().getProperties().putAll(prefixed);
+ }
+ catch (HibernateException he)
+ {
+ log.info("could not set JNDI properties for jBPM persistence: " + he.getMessage());
+ }
+ }
+ }
+
+ public ProcessDefinition getPageflowProcessDefinition(String pageflowName)
+ {
+ return pageflowProcessDefinitions.get(pageflowName);
+ }
+
+ public boolean isPageflowProcessDefinition(String pageflowName)
+ {
+ return pageflowProcessDefinitions.containsKey(pageflowName);
+ }
+
+ public static ProcessDefinition getPageflowDefinitionFromResource(String resourceName)
+ {
+ InputStream resource = ResourceLoader.instance().getResourceAsStream(resourceName);
+ if (resource==null)
+ {
+ throw new IllegalArgumentException("pageflow resource not found: " + resourceName);
+ }
+ try
+ {
+ return Jbpm.parseInputSource( new InputSource(resource) );
+ }
+ catch (JpdlException e)
+ {
+ throw new JpdlException("Unable to parse process definition " + resourceName, e);
+ } finally {
+ Resources.closeStream(resource);
+ }
+ }
+
+ public ProcessDefinition getProcessDefinitionFromResource(String resourceName)
+ {
+ InputStream resource = ResourceLoader.instance().getResourceAsStream(resourceName);
+ if (resource==null)
+ {
+ throw new IllegalArgumentException("process definition resource not found: " + resourceName);
+ }
+
+ try {
+ return ProcessDefinition.parseXmlInputStream(resource);
+ } finally {
+ Resources.closeStream(resource);
+ }
+ }
+
+ public String[] getPageflowDefinitions()
+ {
+ return pageflowDefinitions;
+ }
+
+ public void setPageflowDefinitions(String[] pageflowDefinitions)
+ {
+ this.pageflowDefinitions = pageflowDefinitions;
+ }
+
+ public String[] getProcessDefinitions()
+ {
+ return processDefinitions;
+ }
+
+ public void setProcessDefinitions(String[] processDefinitions)
+ {
+ this.processDefinitions = processDefinitions;
+ }
+
+ /**
+ * Dynamically deploy a page flow definition, if a pageflow with an
+ * identical name already exists, the pageflow is updated.
+ *
+ * @return true if the pageflow definition has been updated
+ */
+ public boolean deployPageflowDefinition(ProcessDefinition pageflowDefinition)
+ {
+ return pageflowProcessDefinitions.put( pageflowDefinition.getName(), pageflowDefinition )!=null;
+ }
+
+ /**
+ * Read a pageflow definition
+ *
+ * @param pageflowDefinition the pageflow as an XML string
+ */
+ public ProcessDefinition getPageflowDefinitionFromXml(String pageflowDefinition)
+ {
+ InputStream stream = null;
+ try {
+ stream = new ReaderInputStream(new StringReader(pageflowDefinition));
+ return Jbpm.parseInputSource(new InputSource(stream));
+ } finally {
+ Resources.closeStream(stream);
+ }
+ }
+
+ /**
+ * Read a process definition
+ *
+ * @param processDefinition the process as an XML string
+ */
+ public ProcessDefinition getProcessDefinitionFromXml(String processDefinition)
+ {
+ InputStream stream = null;
+ try {
+ stream = new ReaderInputStream(new StringReader(processDefinition));
+ return ProcessDefinition.parseXmlInputStream(stream);
+ } finally {
+ Resources.closeStream(stream);
+ }
+ }
+
+ /**
+ * Remove a pageflow definition
+ *
+ * @param pageflowName Name of the pageflow to remove
+ * @return true if the pageflow definition has been removed
+ */
+ public boolean undeployPageflowDefinition(String pageflowName)
+ {
+ return pageflowProcessDefinitions.remove(pageflowName)!=null;
+ }
+
+ private void installPageflowDefinitions() {
+ Set<String> mergedPageflowDefinitions = new LinkedHashSet<String>();
+ if ( pageflowDefinitions!=null )
+ {
+ mergedPageflowDefinitions.addAll(Arrays.asList(pageflowDefinitions));
+ }
+
+ for (FileDescriptor fileDescriptor : ((PageflowDeploymentHandler) ((DeploymentStrategy) Contexts.getEventContext().get(StandardDeploymentStrategy.NAME)).getDeploymentHandlers().get(PageflowDeploymentHandler.NAME)).getResources())
+ {
+ mergedPageflowDefinitions.add(fileDescriptor.getName());
+ }
+
+ for (String pageflow: mergedPageflowDefinitions)
+ {
+ ProcessDefinition pd = getPageflowDefinitionFromResource(pageflow);
+ pageflowProcessDefinitions.put( pd.getName(), pd );
+ }
+ }
+
+ private void installProcessDefinitions()
+ {
+ if ( isProcessDeploymentEnabled() )
+ {
+ JbpmContext jbpmContext = getJbpmConfiguration().createJbpmContext();
+ try
+ {
+ if (processDefinitions!=null)
+ {
+ for ( String definitionResource : processDefinitions )
+ {
+ deployProcess(jbpmContext, definitionResource);
+ }
+ }
+ }
+ catch (RuntimeException e)
+ {
+ throw new RuntimeException("could not deploy a process definition", e);
+ }
+ finally
+ {
+ jbpmContext.close();
+ }
+ }
+ }
+
+ private void deployProcess(JbpmContext jbpmContext, String definitionResource)
+ {
+ ProcessDefinition processDefinition = ProcessDefinition.parseXmlResource(definitionResource);
+ if (log.isDebugEnabled())
+ {
+ log.debug( "deploying process definition : " + processDefinition.getName() );
+ }
+ jbpmContext.deployProcessDefinition(processDefinition);
+ }
+
+ protected boolean isProcessDeploymentEnabled()
+ {
+ return processDefinitions!=null && processDefinitions.length>0;
+ }
+
+ public static Jbpm instance()
+ {
+ if ( !Contexts.isApplicationContextActive() )
+ {
+ throw new IllegalStateException("No application context active");
+ }
+ if ( !Init.instance().isJbpmInstalled() )
+ {
+ throw new IllegalStateException("jBPM support is not installed (use components.xml to install it)");
+ }
+ return (Jbpm) Component.getInstance(Jbpm.class, ScopeType.APPLICATION);
+ }
+
+ protected String getJbpmConfigurationJndiName()
+ {
+ return jbpmConfigurationJndiName;
+ }
+
+ protected void setJbpmConfigurationJndiName(String jbpmConfigurationJndiName)
+ {
+ this.jbpmConfigurationJndiName = jbpmConfigurationJndiName;
+ }
+
+ public static JbpmConfiguration pageflowConfiguration = JbpmConfiguration.parseResource("org/jboss/seam/bpm/jbpm.pageflow.cfg.xml");
+
+ public static JbpmContext createPageflowContext()
+ {
+ return pageflowConfiguration.createJbpmContext();
+ }
+
+ public static ProcessDefinition parseInputSource(InputSource inputSource)
+ {
+ JbpmContext jbpmContext = createPageflowContext();
+ try
+ {
+ return new PageflowParser(inputSource).readProcessDefinition();
+ }
+ finally
+ {
+ jbpmContext.close();
+ }
+ }
+
+ private static final DbSubProcessResolver DB_SUB_PROCESS_RESOLVER = new DbSubProcessResolver();
+ class SeamSubProcessResolver implements SubProcessResolver
+ {
+ public ProcessDefinition findSubProcess(Element element)
+ {
+ String subProcessName = element.attributeValue("name");
+ ProcessDefinition pageflow = pageflowProcessDefinitions.get(subProcessName);
+ return pageflow==null ? DB_SUB_PROCESS_RESOLVER.findSubProcess(element) : pageflow;
+ }
+ }
+
+}
Added: modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/JbpmELResolver.java
===================================================================
--- modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/JbpmELResolver.java (rev 0)
+++ modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/JbpmELResolver.java 2009-04-24 23:24:14 UTC (rev 10631)
@@ -0,0 +1,69 @@
+package org.jboss.seam.bpm;
+
+import java.beans.FeatureDescriptor;
+import java.util.Iterator;
+
+import javax.el.ELContext;
+import javax.el.ELResolver;
+
+import org.jbpm.jpdl.el.VariableResolver;
+
+/**
+ * Resolves jBPM variables for Unified EL
+ *
+ * @author Gavin King
+ *
+ */
+final class JbpmELResolver extends ELResolver
+{
+ private final VariableResolver resolver;
+
+ JbpmELResolver(VariableResolver resolver)
+ {
+ this.resolver = resolver;
+ }
+
+ @Override
+ public Object getValue(ELContext context, Object base, Object property)
+ {
+ if ( base==null && property!=null )
+ {
+ return resolver.resolveVariable( (String) base );
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ @Override
+ public boolean isReadOnly(ELContext context, Object base, Object property)
+ {
+ return true;
+ }
+
+ @Override
+ public Class<?> getCommonPropertyType(ELContext context, Object base)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Iterator<FeatureDescriptor> getFeatureDescriptors(ELContext context, Object base)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Class<?> getType(ELContext context, Object base, Object property)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setValue(ELContext context, Object base, Object property, Object value)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+}
\ No newline at end of file
Added: modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/ManagedJbpmContext.java
===================================================================
--- modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/ManagedJbpmContext.java (rev 0)
+++ modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/ManagedJbpmContext.java 2009-04-24 23:24:14 UTC (rev 10631)
@@ -0,0 +1,168 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jboss.seam.bpm;
+
+import static org.jboss.seam.annotations.Install.BUILT_IN;
+
+import javax.naming.NamingException;
+import javax.transaction.RollbackException;
+import javax.transaction.Synchronization;
+import javax.transaction.SystemException;
+
+import org.jboss.seam.Component;
+import org.jboss.seam.ScopeType;
+import org.jboss.seam.annotations.Create;
+import org.jboss.seam.annotations.Destroy;
+import org.jboss.seam.annotations.Install;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.annotations.Unwrap;
+import org.jboss.seam.annotations.intercept.BypassInterceptors;
+import org.jboss.seam.contexts.Contexts;
+import org.jboss.seam.contexts.Lifecycle;
+import org.jboss.seam.log.LogProvider;
+import org.jboss.seam.log.Logging;
+import org.jboss.seam.transaction.Transaction;
+import org.jboss.seam.transaction.UserTransaction;
+import org.jbpm.JbpmContext;
+import org.jbpm.persistence.db.DbPersistenceServiceFactory;
+import org.jbpm.svc.Services;
+
+/**
+ * Manages a reference to a JbpmContext.
+ *
+ * @author <a href="mailto:steve at hibernate.org">Steve Ebersole</a>
+ * @author Gavin King
+ */
+ at Scope(ScopeType.EVENT)
+ at Name("org.jboss.seam.bpm.jbpmContext")
+ at BypassInterceptors
+ at Install(precedence=BUILT_IN, dependencies="org.jboss.seam.bpm.jbpm")
+public class ManagedJbpmContext implements Synchronization
+{
+ private static final LogProvider log = Logging.getLogProvider(ManagedJbpmContext.class);
+
+ private JbpmContext jbpmContext;
+ private boolean synchronizationRegistered;
+
+ @Create
+ public void create() throws NamingException, RollbackException, SystemException
+ {
+ jbpmContext = Jbpm.instance().getJbpmConfiguration().createJbpmContext();
+ assertNoTransactionManagement();
+ log.debug( "created seam managed jBPM context");
+ }
+
+ private void assertNoTransactionManagement()
+ {
+ DbPersistenceServiceFactory dpsf = (DbPersistenceServiceFactory) jbpmContext.getJbpmConfiguration()
+ .getServiceFactory(Services.SERVICENAME_PERSISTENCE);
+ if ( dpsf.isTransactionEnabled() )
+ {
+ throw new IllegalStateException("jBPM transaction management is enabled, disable in jbpm.cfg.xml");
+ }
+ }
+
+ @Unwrap
+ public JbpmContext getJbpmContext() throws NamingException, RollbackException, SystemException
+ {
+ joinTransaction();
+ return jbpmContext;
+ }
+
+ private void joinTransaction() throws SystemException
+ {
+ UserTransaction transaction = Transaction.instance();
+
+ if ( !transaction.isActiveOrMarkedRollback() )
+ {
+ throw new IllegalStateException("JbpmContext may only be used inside a transaction");
+ }
+
+ if ( !synchronizationRegistered && !Lifecycle.isDestroying() && transaction.isActive() )
+ {
+ jbpmContext.getSession().isOpen();
+ try //TODO: what we really want here is if (!cmt)
+ {
+ transaction.registerSynchronization(this);
+ }
+ catch (UnsupportedOperationException uoe)
+ {
+ jbpmContext.getSession().getTransaction().registerSynchronization(this);
+ }
+ synchronizationRegistered = true;
+ }
+ }
+
+ public void beforeCompletion()
+ {
+ log.debug( "flushing seam managed jBPM context" );
+ /*org.jbpm.graph.exe.ProcessInstance processInstance = ProcessInstance.instance();
+ if (processInstance!=null)
+ {
+ jbpmContext.save(processInstance);
+ }*/
+ if ( Contexts.isBusinessProcessContextActive() )
+ {
+ //in requests that come through SeamPhaseListener,
+ //transactions are committed before the contexts are
+ //destroyed, flush here:
+ Contexts.getBusinessProcessContext().flush();
+ }
+ jbpmContext.getSession().flush();
+ log.debug( "done flushing seam managed jBPM context" );
+ }
+
+ public void afterCompletion(int status)
+ {
+ synchronizationRegistered = false;
+ if ( !Contexts.isEventContextActive() )
+ {
+ //in calls to MDBs and remote calls to SBs, the
+ //transaction doesn't commit until after contexts
+ //are destroyed, so wait until the transaction
+ //completes before closing the session
+ //on the other hand, if we still have an active
+ //event context, leave it open
+ closeContext();
+ }
+ }
+
+ @Destroy
+ public void destroy()
+ {
+ if ( !synchronizationRegistered )
+ {
+ //in requests that come through SeamPhaseListener,
+ //there can be multiple transactions per request,
+ //but they are all completed by the time contexts
+ //are dstroyed
+ //so wait until the end of the request to close
+ //the session
+ //on the other hand, if we are still waiting for
+ //the transaction to commit, leave it open
+ closeContext();
+ }
+ }
+
+ private void closeContext()
+ {
+ log.debug( "destroying seam managed jBPM context" );
+ jbpmContext.close();
+ log.debug( "done destroying seam managed jBPM context" );
+ }
+
+ public static JbpmContext instance()
+ {
+ if ( !Contexts.isEventContextActive() )
+ {
+ throw new IllegalStateException("no active event context");
+ }
+ return (JbpmContext) Component.getInstance(ManagedJbpmContext.class, ScopeType.EVENT);
+ }
+
+}
Added: modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/PageflowDeploymentHandler.java
===================================================================
--- modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/PageflowDeploymentHandler.java (rev 0)
+++ modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/PageflowDeploymentHandler.java 2009-04-24 23:24:14 UTC (rev 10631)
@@ -0,0 +1,81 @@
+package org.jboss.seam.bpm;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.dom4j.DocumentException;
+import org.dom4j.Element;
+import org.jboss.seam.deployment.AbstractDeploymentHandler;
+import org.jboss.seam.deployment.DeploymentMetadata;
+import org.jboss.seam.deployment.FileDescriptor;
+import org.jboss.seam.log.LogProvider;
+import org.jboss.seam.log.Logging;
+import org.jboss.seam.util.Resources;
+import org.jboss.seam.util.XML;
+
+
+public class PageflowDeploymentHandler extends AbstractDeploymentHandler
+{
+
+ private static DeploymentMetadata NAMESPACE_METADATA = new DeploymentMetadata()
+ {
+
+ public String getFileNameSuffix()
+ {
+ return ".jpdl.xml";
+ }
+
+ };
+
+ private static LogProvider log = Logging.getLogProvider(PageflowDeploymentHandler.class);
+
+ public static final String NAME = "org.jboss.seam.bpm.PageflowDeploymentHandler";
+
+ public String getName()
+ {
+ return NAME;
+ }
+
+ @Override
+ public void postProcess(ClassLoader classLoader)
+ {
+ Set<FileDescriptor> files = new HashSet<FileDescriptor>();
+ for (FileDescriptor fileDescriptor : getResources())
+ {
+ try
+ {
+ InputStream inputStream = fileDescriptor.getUrl().openStream();
+ try
+ {
+
+ Element root = XML.getRootElementSafely(inputStream);
+ if ("pageflow-definition".equals(root.getName()))
+ {
+ files.add(fileDescriptor);
+ }
+ }
+ catch (DocumentException e)
+ {
+ log.debug("Unable to parse " + fileDescriptor.getName(), e);
+ }
+ finally
+ {
+ Resources.closeStream(inputStream);
+ }
+ } catch (IOException e)
+ {
+ log.trace("Error loading " + fileDescriptor.getName());
+ }
+
+ }
+ setResources(files);
+ }
+
+ public DeploymentMetadata getMetadata()
+ {
+ return NAMESPACE_METADATA;
+ }
+
+}
Added: modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/PageflowParser.java
===================================================================
--- modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/PageflowParser.java (rev 0)
+++ modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/PageflowParser.java 2009-04-24 23:24:14 UTC (rev 10631)
@@ -0,0 +1,65 @@
+package org.jboss.seam.bpm;
+
+import java.io.Reader;
+
+import org.dom4j.Element;
+import org.jbpm.graph.def.Node;
+import org.jbpm.graph.def.NodeCollection;
+import org.jbpm.jpdl.xml.JpdlXmlReader;
+import org.jbpm.jpdl.xml.ProblemListener;
+import org.xml.sax.InputSource;
+
+/**
+ * A jPDL parser for Seam pageflow definitions
+ *
+ * @author Tom Baeyens
+ *
+ */
+public class PageflowParser extends JpdlXmlReader
+{
+
+ private static final long serialVersionUID = 1L;
+
+ public PageflowParser(InputSource inputSource, ProblemListener problemListener)
+ {
+ super(inputSource, problemListener);
+ }
+
+ public PageflowParser(InputSource inputSource)
+ {
+ super(inputSource);
+ }
+
+ public PageflowParser(Reader reader)
+ {
+ super(reader);
+ }
+
+ @Override
+ public void readNodes(Element nodeCollectionElement, NodeCollection nodeCollection)
+ {
+ super.readNodes(nodeCollectionElement, nodeCollection);
+
+ if ( "pageflow-definition".equals( nodeCollectionElement.getName() ) )
+ {
+ String startPageName = nodeCollectionElement.attributeValue("start-page");
+ if (startPageName==null)
+ {
+ Element startPageElement = nodeCollectionElement.element("start-page");
+ if (startPageElement!=null)
+ {
+ startPageName = startPageElement.attributeValue("name");
+ }
+ }
+ if (startPageName!=null)
+ {
+ Node startPage = getProcessDefinition().getNode(startPageName);
+ if (startPage!=null)
+ {
+ getProcessDefinition().setStartState(startPage);
+ }
+ }
+ }
+ }
+
+}
Added: modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/PooledTask.java
===================================================================
--- modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/PooledTask.java (rev 0)
+++ modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/PooledTask.java 2009-04-24 23:24:14 UTC (rev 10631)
@@ -0,0 +1,120 @@
+package org.jboss.seam.bpm;
+
+import static org.jboss.seam.annotations.Install.BUILT_IN;
+
+import org.jboss.seam.ScopeType;
+import org.jboss.seam.annotations.Install;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.annotations.Transactional;
+import org.jboss.seam.web.Parameters;
+import org.jbpm.taskmgmt.exe.TaskInstance;
+
+/**
+ * Support for assigning tasks in the pooled task list.
+ *
+ * @see TaskInstanceList
+ * @author Gavin King
+ */
+ at Name("org.jboss.seam.bpm.pooledTask")
+ at Scope(ScopeType.APPLICATION)
+ at Install(precedence=BUILT_IN, dependencies="org.jboss.seam.bpm.jbpm")
+public class PooledTask
+{
+
+ /**
+ * Assign the TaskInstance with the id passed
+ * in the request parameter named "taskId" to
+ * the current actor.
+ *
+ * @see Actor
+ * @return a null outcome only if the task was not found
+ */
+ @Transactional
+ public String assignToCurrentActor()
+ {
+ Actor actor = Actor.instance();
+ if ( actor.getId()==null )
+ {
+ throw new IllegalStateException("no current actor id defined");
+ }
+ TaskInstance taskInstance = getTaskInstance();
+ if (taskInstance!=null)
+ {
+ taskInstance.setActorId( actor.getId() );
+ return "taskAssignedToActor";
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Assign the TaskInstance with the id passed
+ * in the request parameter named "taskId" to
+ * the given actor id.
+ *
+ * @param actorId the jBPM actor id
+ * @return a null outcome only if the task was not found
+ */
+ @Transactional
+ public String assign(String actorId)
+ {
+ TaskInstance taskInstance = getTaskInstance();
+ if (taskInstance!=null)
+ {
+ taskInstance.setActorId(actorId);
+ return "taskAssigned";
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Unassign the TaskInstance with the id passed
+ * in the request parameter named "taskId" from
+ * the actor to which it is assigned, and return
+ * it to the pool it came from.
+ *
+ * @return a null outcome only if the task was not found
+ */
+ @Transactional
+ public String unassign()
+ {
+ TaskInstance taskInstance = getTaskInstance();
+ if (taskInstance!=null)
+ {
+ taskInstance.setActorId(null);
+ return "taskUnassigned";
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * @return the TaskInstance with the id passed
+ * in the request parameter named "taskId".
+ */
+ @Transactional
+ public TaskInstance getTaskInstance()
+ {
+ String[] values = Parameters.instance().getRequestParameters().get("taskId");
+ if ( values==null || values.length!=1 )
+ {
+ return null;
+ }
+ else
+ {
+ String taskId = values[0];
+ return taskId==null ?
+ null :
+ ManagedJbpmContext.instance().getTaskInstanceForUpdate( Long.parseLong(taskId) );
+ }
+ }
+
+}
Added: modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/PooledTaskInstanceList.java
===================================================================
--- modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/PooledTaskInstanceList.java (rev 0)
+++ modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/PooledTaskInstanceList.java 2009-04-24 23:24:14 UTC (rev 10631)
@@ -0,0 +1,40 @@
+package org.jboss.seam.bpm;
+
+import static org.jboss.seam.annotations.Install.BUILT_IN;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.jboss.seam.ScopeType;
+import org.jboss.seam.annotations.Install;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.annotations.Transactional;
+import org.jboss.seam.annotations.Unwrap;
+import org.jbpm.taskmgmt.exe.TaskInstance;
+
+/**
+ * Support for the pooled task list.
+ *
+ * @see TaskInstanceList
+ * @author Gavin King
+ */
+ at Name("org.jboss.seam.bpm.pooledTaskInstanceList")
+ at Scope(ScopeType.APPLICATION)
+ at Install(precedence=BUILT_IN, dependencies="org.jboss.seam.bpm.jbpm")
+public class PooledTaskInstanceList
+{
+
+ @Unwrap
+ @Transactional
+ public List<TaskInstance> getPooledTaskInstanceList()
+ {
+ Actor actor = Actor.instance();
+ String actorId = actor.getId();
+ if ( actorId == null ) return null;
+ ArrayList groupIds = new ArrayList( actor.getGroupActorIds() );
+ groupIds.add(actorId);
+ return ManagedJbpmContext.instance().getGroupTaskList(groupIds);
+ }
+
+}
Added: modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/ProcessInstance.java
===================================================================
--- modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/ProcessInstance.java (rev 0)
+++ modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/ProcessInstance.java 2009-04-24 23:24:14 UTC (rev 10631)
@@ -0,0 +1,67 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jboss.seam.bpm;
+
+import static org.jboss.seam.annotations.Install.BUILT_IN;
+
+import org.jboss.seam.Component;
+import org.jboss.seam.ScopeType;
+import org.jboss.seam.annotations.Install;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.annotations.Unwrap;
+import org.jboss.seam.annotations.intercept.BypassInterceptors;
+import org.jboss.seam.contexts.Contexts;
+import org.jboss.seam.util.Work;
+
+/**
+ * A Seam component that allows injection of the current
+ * jBPM ProcessInstance.
+ *
+ * @author Gavin King
+ */
+ at Scope(ScopeType.STATELESS)
+ at Name("org.jboss.seam.bpm.processInstance")
+ at BypassInterceptors
+ at Install(precedence=BUILT_IN, dependencies="org.jboss.seam.bpm.jbpm")
+public class ProcessInstance
+{
+
+ @Unwrap
+ public org.jbpm.graph.exe.ProcessInstance getProcessInstance() throws Exception
+ {
+ if ( !Contexts.isConversationContextActive() ) return null;
+
+ return new Work<org.jbpm.graph.exe.ProcessInstance>()
+ {
+
+ @Override
+ protected org.jbpm.graph.exe.ProcessInstance work() throws Exception
+ {
+ Long processId = BusinessProcess.instance().getProcessId();
+ if (processId!=null)
+ {
+ //TODO: do we need to cache this??
+ return ManagedJbpmContext.instance().getProcessInstanceForUpdate(processId);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ }.workInTransaction();
+
+ }
+
+ public static org.jbpm.graph.exe.ProcessInstance instance()
+ {
+ if ( !Contexts.isConversationContextActive() || !BusinessProcess.instance().hasCurrentProcess() ) return null; //so we don't start a txn
+
+ return (org.jbpm.graph.exe.ProcessInstance) Component.getInstance(ProcessInstance.class, ScopeType.STATELESS);
+ }
+}
Added: modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/ProcessInstanceFinder.java
===================================================================
--- modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/ProcessInstanceFinder.java (rev 0)
+++ modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/ProcessInstanceFinder.java 2009-04-24 23:24:14 UTC (rev 10631)
@@ -0,0 +1,105 @@
+package org.jboss.seam.bpm;
+
+import static org.hibernate.criterion.Order.asc;
+import static org.hibernate.criterion.Order.desc;
+import static org.hibernate.criterion.Restrictions.isNotNull;
+import static org.hibernate.criterion.Restrictions.isNull;
+import static org.jboss.seam.annotations.Install.BUILT_IN;
+
+import java.util.List;
+
+import org.hibernate.Criteria;
+import org.hibernate.criterion.Restrictions;
+import org.jboss.seam.annotations.Factory;
+import org.jboss.seam.annotations.Install;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Transactional;
+import org.jbpm.graph.exe.ProcessInstance;
+
+/**
+ * Support for the process list.
+ *
+ * @author Gavin King
+ */
+ at Name("org.jboss.seam.bpm.processInstanceFinder")
+ at Install(precedence=BUILT_IN, dependencies="org.jboss.seam.bpm.jbpm")
+public class ProcessInstanceFinder
+{
+
+ private String processDefinitionName;
+ private String nodeName;
+ private Boolean processInstanceEnded = false;
+ private Boolean sortDescending = false;
+
+ @Factory(value="org.jboss.seam.bpm.processInstanceList", autoCreate=true)
+ @Transactional
+ public List<ProcessInstance> getProcessInstanceList()
+ {
+ Criteria query = ManagedJbpmContext.instance().getSession()
+ .createCriteria(ProcessInstance.class);
+ if ( processInstanceEnded!=null )
+ {
+ query.add( processInstanceEnded ? isNotNull("end") : isNull("end") );
+ }
+
+ if (processDefinitionName!=null)
+ {
+ query.createCriteria("processDefinition")
+ .add( Restrictions.eq("name", processDefinitionName) );
+ }
+
+ query = query.createCriteria("rootToken");
+ if (sortDescending!=null)
+ {
+ query.addOrder( sortDescending ? desc("nodeEnter") : asc("nodeEnter") );
+ }
+ if (nodeName!=null)
+ {
+ query.createCriteria("node")
+ .add( Restrictions.eq("name", nodeName) );
+ }
+
+ return query.list();
+ }
+
+ protected String getNodeName()
+ {
+ return nodeName;
+ }
+
+ protected void setNodeName(String nodeName)
+ {
+ this.nodeName = nodeName;
+ }
+
+ protected String getProcessDefinitionName()
+ {
+ return processDefinitionName;
+ }
+
+ protected void setProcessDefinitionName(String processDefinitionName)
+ {
+ this.processDefinitionName = processDefinitionName;
+ }
+
+ protected Boolean isSortDescending()
+ {
+ return sortDescending;
+ }
+
+ protected void setSortDescending(Boolean sortDescending)
+ {
+ this.sortDescending = sortDescending;
+ }
+
+ protected Boolean getProcessInstanceEnded()
+ {
+ return processInstanceEnded;
+ }
+
+ protected void setProcessInstanceEnded(Boolean ended)
+ {
+ this.processInstanceEnded = ended;
+ }
+
+}
Added: modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/SeamExpressionEvaluator.java
===================================================================
--- modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/SeamExpressionEvaluator.java (rev 0)
+++ modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/SeamExpressionEvaluator.java 2009-04-24 23:24:14 UTC (rev 10631)
@@ -0,0 +1,167 @@
+package org.jboss.seam.bpm;
+
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.el.CompositeELResolver;
+import javax.el.ELContext;
+import javax.el.MethodExpression;
+import javax.el.MethodNotFoundException;
+import javax.el.PropertyNotFoundException;
+import javax.el.ValueExpression;
+
+import org.jboss.seam.el.EL;
+import org.jboss.seam.el.SeamFunctionMapper;
+import org.jboss.seam.log.LogProvider;
+import org.jboss.seam.log.Logging;
+import org.jbpm.jpdl.el.ELException;
+import org.jbpm.jpdl.el.Expression;
+import org.jbpm.jpdl.el.ExpressionEvaluator;
+import org.jbpm.jpdl.el.FunctionMapper;
+import org.jbpm.jpdl.el.VariableResolver;
+
+/**
+ * Plugs the JBoss EL expression language and Seam
+ * EL resolvers into jBPM. Note that this current
+ * implementation does not allow jBPM to see stuff
+ * defined only by the JSF ELResolvers.
+ *
+ * @author Gavin King
+ * @author Pete Muir
+ *
+ */
+public class SeamExpressionEvaluator
+ extends ExpressionEvaluator
+{
+
+ private static LogProvider log = Logging.getLogProvider(SeamExpressionEvaluator.class);
+
+ @Override
+ public Object evaluate(String expression, Class returnType, final VariableResolver resolver, FunctionMapper mapper)
+ throws ELException
+ {
+ return createExpression(expression, returnType, mapper).evaluate(resolver);
+ }
+
+ @Override
+ public Expression parseExpression(final String expression, final Class returnType, FunctionMapper mapper)
+ throws ELException
+ {
+ return createExpression(expression, returnType, mapper);
+ }
+
+ private static Expression createExpression(final String expression, final Class returnType, final FunctionMapper mapper)
+ {
+
+ return new Expression()
+ {
+ private ELContext elContext = EL.createELContext();
+
+ private MethodExpression me;
+ private ValueExpression ve;
+
+ private void initMethodExpression()
+ {
+ if (me == null || ve == null)
+ {
+ me = EL.EXPRESSION_FACTORY.createMethodExpression(elContext, expression, returnType, new Class[0]);
+ }
+ }
+
+ private void initValueExpression()
+ {
+ if (me == null || ve == null)
+ {
+ ve = EL.EXPRESSION_FACTORY.createValueExpression(elContext, expression, returnType);
+ }
+ }
+
+ @Override
+ public Object evaluate(VariableResolver resolver) throws ELException
+ {
+ List<javax.el.ELException> exceptions = new ArrayList<javax.el.ELException>();
+ try
+ {
+ initMethodExpression();
+ if (me != null)
+ {
+ try
+ {
+ return me.invoke(createELContext(resolver, mapper), new Object[0]);
+ }
+ catch (MethodNotFoundException e)
+ {
+ exceptions.add(e);
+ }
+ }
+ }
+ catch (javax.el.ELException e)
+ {
+ exceptions.add(e);
+ }
+
+ try
+ {
+ initValueExpression();
+ if (ve != null)
+ {
+ try
+ {
+ return ve.getValue(createELContext(resolver, mapper));
+ }
+ catch (PropertyNotFoundException e)
+ {
+ exceptions.add(e);
+ }
+ }
+ }
+ catch (javax.el.ELException e)
+ {
+ exceptions.add(e);
+ }
+
+ if (exceptions.size() == 1)
+ {
+ throw new ELException("Error evaluating " + expression, exceptions.get(0));
+ }
+ else if (exceptions.size() > 1)
+ {
+ log.error("Exceptions occurred when parsing " + expression);
+ for (javax.el.ELException e : exceptions)
+ {
+ log.error("Possible cause", e);
+ }
+ }
+ if (me == null && ve == null)
+ {
+ log.error("Error parsing " + expression);
+ throw new ELException("Error parsing " + expression + "; not a valid EL expression");
+ }
+ throw new ELException("Error evaluating " + expression + "; possible causes are logged at debug level");
+ }
+ };
+ }
+
+ private static javax.el.FunctionMapper decorateFunctionMapper(final FunctionMapper functionMapper)
+ {
+ return new SeamFunctionMapper( new javax.el.FunctionMapper()
+ {
+ @Override
+ public Method resolveFunction(String prefix, String localName)
+ {
+ return functionMapper.resolveFunction(prefix, localName);
+ }
+ });
+ }
+
+ private static ELContext createELContext(VariableResolver resolver, FunctionMapper functionMapper)
+ {
+ CompositeELResolver composite = new CompositeELResolver();
+ composite.add(EL.EL_RESOLVER);
+ composite.add( new JbpmELResolver(resolver) );
+ return EL.createELContext(composite, decorateFunctionMapper(functionMapper));
+ }
+
+}
Added: modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/SeamUserCodeInterceptor.java
===================================================================
--- modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/SeamUserCodeInterceptor.java (rev 0)
+++ modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/SeamUserCodeInterceptor.java 2009-04-24 23:24:14 UTC (rev 10631)
@@ -0,0 +1,153 @@
+package org.jboss.seam.bpm;
+
+import org.jboss.seam.contexts.Contexts;
+import org.jboss.seam.contexts.Lifecycle;
+import org.jbpm.context.exe.ContextInstance;
+import org.jbpm.graph.def.Action;
+import org.jbpm.graph.exe.ExecutionContext;
+import org.jbpm.graph.exe.Token;
+import org.jbpm.instantiation.UserCodeInterceptor;
+import org.jbpm.taskmgmt.def.AssignmentHandler;
+import org.jbpm.taskmgmt.def.TaskControllerHandler;
+import org.jbpm.taskmgmt.exe.Assignable;
+import org.jbpm.taskmgmt.exe.TaskInstance;
+
+/**
+ * Intercepts calls to user code coming from jBPM, sets up
+ * Seam contexts and associates the process and task instances
+ * with the contexts.
+ *
+ * @author Gavin King
+ *
+ */
+class SeamUserCodeInterceptor implements UserCodeInterceptor
+{
+ abstract static class ContextualCall
+ {
+ abstract void process() throws Exception;
+
+ void run() throws Exception
+ {
+ if ( Contexts.isEventContextActive() || Contexts.isApplicationContextActive() ) //not sure about the second bit (only needed at init time!)
+ {
+ process();
+ }
+ else
+ {
+ Lifecycle.beginCall();
+ try
+ {
+ process();
+ }
+ finally
+ {
+ Lifecycle.endCall();
+ }
+ }
+ }
+
+ void runAndWrap()
+ {
+ try
+ {
+ run();
+ }
+ catch (RuntimeException re)
+ {
+ throw re;
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ public void executeAction(final Action action, final ExecutionContext context) throws Exception
+ {
+ if ( isPageflow(context) )
+ {
+ action.execute(context);
+ }
+ else
+ {
+ new ContextualCall()
+ {
+ @Override
+ void process() throws Exception
+ {
+ initProcessAndTask(context);
+ action.execute(context);
+ }
+ }.run();
+ }
+ }
+
+ private boolean isPageflow(final ExecutionContext context)
+ {
+ return Contexts.isConversationContextActive() &&
+ Jbpm.instance().isPageflowProcessDefinition( context.getProcessDefinition().getName() );
+ }
+
+ public void executeAssignment(final AssignmentHandler handler, final Assignable assignable,
+ final ExecutionContext context)
+ throws Exception
+ {
+ new ContextualCall()
+ {
+ @Override
+ void process() throws Exception
+ {
+ initProcessAndTask(context);
+ handler.assign(assignable, context);
+ }
+ }.run();
+ }
+
+ public void executeTaskControllerInitialization(final TaskControllerHandler handler, final TaskInstance task,
+ final ContextInstance context, final Token token)
+ {
+ new ContextualCall()
+ {
+ @Override
+ void process() throws Exception
+ {
+ initProcessAndTask(task);
+ handler.initializeTaskVariables(task, context, token);
+ }
+ }.runAndWrap();
+ }
+
+ public void executeTaskControllerSubmission(final TaskControllerHandler handler, final TaskInstance task,
+ final ContextInstance context, final Token token)
+ {
+ new ContextualCall()
+ {
+ @Override
+ void process() throws Exception
+ {
+ initProcessAndTask(task);
+ handler.submitTaskVariables(task, context, token);
+ }
+ }.runAndWrap();
+ }
+
+ private static void initProcessAndTask(ExecutionContext context)
+ {
+ BusinessProcess businessProcess = BusinessProcess.instance();
+ businessProcess.setProcessId( context.getProcessInstance().getId() );
+ TaskInstance taskInstance = context.getTaskInstance();
+ if (taskInstance!=null)
+ {
+ businessProcess.setTaskId( taskInstance.getId() );
+ }
+ }
+
+ private static void initProcessAndTask(TaskInstance task)
+ {
+ BusinessProcess businessProcess = BusinessProcess.instance();
+ businessProcess.setProcessId( task.getProcessInstance().getId() );
+ businessProcess.setTaskId( task.getId() );
+ }
+
+}
Added: modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/TaskInstance.java
===================================================================
--- modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/TaskInstance.java (rev 0)
+++ modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/TaskInstance.java 2009-04-24 23:24:14 UTC (rev 10631)
@@ -0,0 +1,53 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jboss.seam.bpm;
+
+import javax.annotation.Named;
+import javax.inject.Produces;
+
+/**
+ * A Seam component that allows injection of the current
+ * jBPM TaskInstance.
+ *
+ * @author Gavin King
+ */
+public class TaskInstance
+{
+ @Produces
+ public org.jbpm.taskmgmt.exe.TaskInstance getTaskInstance() throws Exception
+ {
+ if ( !Contexts.isConversationContextActive() ) return null;
+
+ return new Work<org.jbpm.taskmgmt.exe.TaskInstance>()
+ {
+
+ @Override
+ protected org.jbpm.taskmgmt.exe.TaskInstance work() throws Exception
+ {
+ Long taskId = BusinessProcess.instance().getTaskId();
+ if (taskId!=null)
+ {
+ //TODO: do we need to cache this??
+ return ManagedJbpmContext.instance().getTaskInstanceForUpdate(taskId);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ }.workInTransaction();
+ }
+
+ public static org.jbpm.taskmgmt.exe.TaskInstance instance()
+ {
+ if ( !Contexts.isConversationContextActive() || !BusinessProcess.instance().hasCurrentTask() ) return null; //so we don't start a txn
+
+ return (org.jbpm.taskmgmt.exe.TaskInstance) Component.getInstance(TaskInstance.class, ScopeType.STATELESS);
+ }
+
+}
Added: modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/TaskInstanceList.java
===================================================================
--- modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/TaskInstanceList.java (rev 0)
+++ modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/TaskInstanceList.java 2009-04-24 23:24:14 UTC (rev 10631)
@@ -0,0 +1,33 @@
+package org.jboss.seam.bpm;
+
+import java.util.List;
+
+import javax.context.ApplicationScoped;
+import javax.inject.Produces;
+
+import org.jbpm.taskmgmt.exe.TaskInstance;
+
+/**
+ * Support for the task list.
+ *
+ * @see TaskInstanceListForType
+ * @see PooledTask
+ * @author <a href="mailto:steve at hibernate.org">Steve Ebersole</a>
+ * @author Gavin King
+ */
+public class TaskInstanceList
+{
+ @Produces
+ public List<TaskInstance> getTaskInstanceList()
+ {
+ return getTaskInstanceList( Actor.instance().getId() );
+ }
+
+ private List<TaskInstance> getTaskInstanceList(String actorId)
+ {
+ if ( actorId == null ) return null;
+
+ return ManagedJbpmContext.instance().getTaskList(actorId);
+ }
+
+}
Added: modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/TaskInstanceListForType.java
===================================================================
--- modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/TaskInstanceListForType.java (rev 0)
+++ modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/TaskInstanceListForType.java 2009-04-24 23:24:14 UTC (rev 10631)
@@ -0,0 +1,49 @@
+package org.jboss.seam.bpm;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.context.ApplicationScoped;
+
+import org.jbpm.taskmgmt.exe.TaskInstance;
+
+/**
+ * Support for a list of tasks of a particular type.
+ *
+ * @see TaskInstanceList
+ * @author Gavin King
+ * @author <a href="mailto:steve at hibernate.org">Steve Ebersole </a>
+ */
+ at ApplicationScoped
+public class TaskInstanceListForType
+{
+ @Unwrap
+ @Transactional
+ public Map<String,List<TaskInstance>> getTaskInstanceList()
+ {
+ return getTaskInstanceList( Actor.instance().getId() );
+ }
+
+ private Map<String,List<TaskInstance>> getTaskInstanceList(String actorId)
+ {
+ if ( actorId == null ) return null;
+
+ Map<String, List<TaskInstance>> map = new HashMap<String, List<TaskInstance>>();
+ List<TaskInstance> taskInstances = ManagedJbpmContext.instance().getTaskList(actorId);
+ for ( TaskInstance task: taskInstances )
+ {
+ String name = task.getName();
+ List<TaskInstance> list = map.get(name);
+ if (list==null)
+ {
+ list = new ArrayList<TaskInstance>();
+ map.put(name, list);
+ }
+ list.add(task);
+ }
+ return map;
+ }
+
+}
Added: modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/TaskInstancePriorityList.java
===================================================================
--- modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/TaskInstancePriorityList.java (rev 0)
+++ modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/TaskInstancePriorityList.java 2009-04-24 23:24:14 UTC (rev 10631)
@@ -0,0 +1,45 @@
+package org.jboss.seam.bpm;
+
+import java.util.List;
+
+import javax.context.ApplicationScoped;
+import javax.inject.Produces;
+
+import org.hibernate.criterion.Order;
+import org.hibernate.criterion.Restrictions;
+import org.jbpm.taskmgmt.exe.TaskInstance;
+
+/**
+ * Support for a task list ordered by priority.
+ *
+ * @see TaskInstanceList
+ * @see PooledTask
+ * @author Gavin King
+ */
+public class TaskInstancePriorityList
+{
+
+ //TODO: we really need to cache the list in the event context,
+ // but then we would need some events to refresh it
+ // when tasks end, which is non-trivial to do....
+ @Produces @Transactional
+ public List<TaskInstance> getTaskInstanceList()
+ {
+ return getTaskInstanceList( Actor.instance().getId() );
+ }
+
+ private List<TaskInstance> getTaskInstanceList(String actorId)
+ {
+ if ( actorId == null ) return null;
+
+ return ManagedJbpmContext.instance().getSession()
+ .createCriteria(TaskInstance.class)
+ .add( Restrictions.eq("actorId", actorId) )
+ .add( Restrictions.eq("isOpen", true) )
+ .add( Restrictions.ne("isSuspended", true) )
+ .addOrder( Order.asc("priority") )
+ .setCacheable(true)
+ .list();
+ }
+
+}
Added: modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/Transition.java
===================================================================
--- modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/Transition.java (rev 0)
+++ modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/Transition.java 2009-04-24 23:24:14 UTC (rev 10631)
@@ -0,0 +1,63 @@
+package org.jboss.seam.bpm;
+
+import static org.jboss.seam.annotations.Install.BUILT_IN;
+
+import java.io.Serializable;
+
+import org.jboss.seam.Component;
+import org.jboss.seam.ScopeType;
+import org.jboss.seam.annotations.Install;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.annotations.intercept.BypassInterceptors;
+import org.jboss.seam.contexts.Contexts;
+import org.jboss.seam.core.AbstractMutable;
+
+/**
+ * Allows the application to set the jBPM transition to be used when
+ * an <tt>@EndTask</tt> method is encountered.
+ *
+ * @see org.jboss.seam.annotations.bpm.EndTask
+ *
+ * @author Gavin King
+ */
+ at Name("org.jboss.seam.bpm.transition")
+ at Scope(ScopeType.CONVERSATION)
+ at BypassInterceptors
+ at Install(precedence=BUILT_IN, dependencies="org.jboss.seam.bpm.jbpm")
+public class Transition extends AbstractMutable implements Serializable
+{
+ private static final long serialVersionUID = -3054558654376670239L;
+
+ private String name;
+
+ public String getName()
+ {
+ return name;
+ }
+
+ /**
+ * Set the jBPM transition name
+ */
+ public void setName(String name)
+ {
+ setDirty(this.name, name);
+ this.name = name;
+ }
+
+ public static Transition instance()
+ {
+ if ( !Contexts.isApplicationContextActive() )
+ {
+ throw new IllegalStateException("No active application context");
+ }
+ return (Transition) Component.getInstance(Transition.class, ScopeType.CONVERSATION);
+ }
+
+ @Override
+ public String toString()
+ {
+ return "Transition(" + name + ")";
+ }
+
+}
Added: modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/jbpm.pageflow.cfg.xml
===================================================================
--- modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/jbpm.pageflow.cfg.xml (rev 0)
+++ modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/jbpm.pageflow.cfg.xml 2009-04-24 23:24:14 UTC (rev 10631)
@@ -0,0 +1,3 @@
+<pageflow-configuration>
+ <jbpm-context />
+</pageflow-configuration>
Added: modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/package-info.java
===================================================================
--- modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/package-info.java (rev 0)
+++ modules/trunk/bpm/src/main/java/org/jboss/seam/bpm/package-info.java 2009-04-24 23:24:14 UTC (rev 10631)
@@ -0,0 +1,17 @@
+/**
+ * A set of Seam components for business process management
+ * via jBPM, including control of process and task instances,
+ * rendering of task lists, and integration with jBPM.
+ *
+ * The application may call components in this package
+ * directly, or via EL, or may use them indirectly via
+ * the annotations in org.jboss.seam.annotations.
+ *
+ * @see org.jboss.seam.annotations.bpm
+ */
+ at Namespace(value="http://jboss.com/products/seam/bpm", prefix="org.jboss.seam.bpm")
+ at AutoCreate
+package org.jboss.seam.bpm;
+
+import org.jboss.seam.annotations.AutoCreate;
+import org.jboss.seam.annotations.Namespace;
More information about the seam-commits
mailing list