Using Context and Command
asrickard Jul 30, 2009 9:39 AMI've been trying to work out how to use context functions and the Command system, and need some suggestions/assistance.
I have a conversation-scoped Seam component "workflowProcessManager" in which I have a list of running processes which is refreshed when the user clicks a commandLink. In the same component I have a function to suspend a ProcessInstance.
@Name("workflowProcessManager") @Scope(ScopeType.CONVERSATION) public class WorkflowProcessManager { private JbpmContext context; private CommandServiceImpl csi; private Boolean showActiveOnly = true; @DataModel private List<ProcessDefinition> processDefinitions = new Vector<ProcessDefinition>(0); @DataModelSelection("processDefinitions") @Out(required=false) private ProcessDefinition currentProcessDefinition; @DataModel private List<ProcessInstance> runningProcesses = new Vector<ProcessInstance>(0); @DataModelSelection("runningProcesses") @Out(required=false) private ProcessInstance currentRunningProcess; public void init() { context = JbpmConfiguration.getInstance().createJbpmContext(); populateProcessDefinitionList(); csi = new CommandServiceImpl(context.getJbpmConfiguration()); } public void showProcessesForProcessDefinition(ProcessDefinition pd) { GetProcessInstancesCommand gpic = new GetProcessInstancesCommand(); if (this.showActiveOnly) gpic.setOnlyRunning(true); else gpic.setOnlyRunning(false); gpic.setProcessName(pd.getName()); runningProcesses = (List<ProcessInstance>) csi.execute(gpic); System.out.println("ShowProcessesForProcessDefinition: runningProcesses contains " + runningProcesses.size() + " entries."); } public void suspendProcessInstance(Integer id) { System.out.println("Suspending process instance " + id); ProcessInstance pi = context.getProcessInstance(id); pi.suspend(); System.out.println("Saving process instance " + id); context.save(pi); //Session session = context.getSession(); //session.flush(); if (pi.isSuspended()) System.out.println("Process instance is suspended = true"); else System.out.println("Process instance is suspended = false"); System.out.println("Refreshing processes for definition " + this.currentProcessDefinition.getName()); showProcessesForProcessDefinition(this.currentProcessDefinition); for (ProcessInstance p : this.runningProcesses) { if (p.isSuspended()) System.out.println("Process instance " + p.getId() + " is suspended = true"); else System.out.println("Process instance " + p.getId() + " is suspended = false"); } } public Boolean getShowActiveOnly() { return this.showActiveOnly; } public void setShowActiveOnly(Boolean showActiveOnly) { this.showActiveOnly = showActiveOnly; } @SuppressWarnings("unchecked") private void populateProcessDefinitionList() { processDefinitions = context.getGraphSession().findAllProcessDefinitions(); } }
And the guts of the page:
<rich:panel> <f:facet name="header">Process List</f:facet> <h:panelGrid columns="2" columnClasses="twoColumnTopAligned"> <h:panelGroup> <rich:dataTable value="#{processDefinitions}" var="processDefinition" onRowMouseOver="this.style.backgroundColor='#EAEAEA';this.style.cursor='pointer'" onRowMouseOut="this.style.backgroundColor='#{a4jSkin.tableBackgroundColor}'"> <rich:column> <f:facet name="header">Process Name</f:facet> <h:outputText value="#{processDefinition.name}"/> </rich:column> <rich:column> <f:facet name="header">Description</f:facet> <h:outputText value="#{processDefinition.description}"/> </rich:column> <a:support event="onRowClick" reRender="instanceTable" action="#{workflowProcessManager.showProcessesForProcessDefinition(processDefinition)}"> </a:support> </rich:dataTable> <s:decorate id="showActiveOnlyField" template="/layout/edit.xhtml"> <ui:define name="label">Show only active processes</ui:define> <h:selectBooleanCheckbox id="showActiveOnly" value="#{workflowProcessManager.showActiveOnly}" /> </s:decorate> </h:panelGroup> <rich:dataTable id="instanceTable" value="#{runningProcesses}" var="processInstance"> <rich:column> <f:facet name="header">Id</f:facet> <h:outputText value="#{processInstance.id}"/> </rich:column> <rich:column> <f:facet name="header">Version</f:facet> <h:outputText value="#{processInstance.version}"/> </rich:column> <rich:column> <f:facet name="header">Status</f:facet> <h:outputText value="Finished" rendered="#{processInstance.hasEnded()}"/> <h:outputText value="Paused" rendered="#{processInstance.suspended}"/> <h:outputText value="Running" rendered="#{!(processInstance.hasEnded() or processInstance.suspended)}"/> </rich:column> <rich:column> <f:facet name="header">Current Node</f:facet> <h:outputText value="#{processInstance.rootToken.name}"/> </rich:column> <rich:column> <f:facet name="header">Actions</f:facet> <a:commandLink id="pauseProcessInstance" action="#{workflowProcessManager.suspendProcessInstance(processInstance.id)}" reRender="instanceTable" value="Pause"> <s:conversationId /> </a:commandLink> #{' '} <a:commandLink id="resumeProcessInstance" action="#{workflowProcessManager.resumeProcessInstance(processInstance.id)}" reRender="instanceTable" value="Restart"> <s:conversationId /> </a:commandLink> #{' '} <a:commandLink id="signalProcessInstances" action="#{workflowProcessManager.signalProcessInstance(processInstance.id)}" reRender="instanceTable" value="Signal"> <s:conversationId /> </a:commandLink> </rich:column> </rich:dataTable> </h:panelGrid> </rich:panel>
The problem I experience is that the list of running ProcessInstances is not refreshed correctly, unless I add in the hibernate session flush() (commented out in the code above).
The command service starts up a separate JbpmContext, which I believe is not seeing the results of the suspend() call, and so refreshes the .
Should I be looking for a problem somewhere in the configuration, and if so where? Or am I using the Jbpm features incorrectly somehow? Or do I need to manually flush like this?
Any pointers from more experienced people will be much appreciated...