/*
* 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.graph.node;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Element;
import org.jbpm.JbpmConfiguration;
import org.jbpm.JbpmException;
import org.jbpm.context.def.VariableAccess;
import org.jbpm.context.exe.ContextInstance;
import org.jbpm.graph.def.Event;
import org.jbpm.graph.def.Node;
import org.jbpm.graph.def.ProcessDefinition;
import org.jbpm.graph.def.Transition;
import org.jbpm.graph.exe.ExecutionContext;
import org.jbpm.graph.exe.ProcessInstance;
import org.jbpm.graph.exe.Token;
import org.jbpm.jpdl.xml.JpdlXmlReader;
import org.jbpm.jpdl.xml.Parsable;
public class ProcessState extends Node implements Parsable {
private static final long serialVersionUID = 1L;
static SubProcessResolver defaultSubProcessResolver = new DbSubProcessResolver();
public static void setDefaultSubProcessResolver(SubProcessResolver subProcessResolver) {
defaultSubProcessResolver = subProcessResolver;
}
protected ProcessDefinition subProcessDefinition = null;
protected Set variableAccesses = null;
// event types //////////////////////////////////////////////////////////////
public static final String[] supportedEventTypes = new String[] { Event.EVENTTYPE_SUBPROCESS_CREATED, Event.EVENTTYPE_SUBPROCESS_END,
Event.EVENTTYPE_NODE_ENTER, Event.EVENTTYPE_NODE_LEAVE, Event.EVENTTYPE_BEFORE_SIGNAL, Event.EVENTTYPE_AFTER_SIGNAL };
public String[] getSupportedEventTypes() {
return supportedEventTypes;
}
// xml //////////////////////////////////////////////////////////////////////
public void read(Element processStateElement, JpdlXmlReader jpdlReader) {
Element subProcessElement = processStateElement.element("sub-process");
if (subProcessElement!=null) {
SubProcessResolver subProcessResolver = defaultSubProcessResolver;
if (JbpmConfiguration.Configs.hasObject("jbpm.sub.process.resolver")) {
subProcessResolver = (SubProcessResolver) JbpmConfiguration.Configs.getObject("jbpm.sub.process.resolver");
}
try {
subProcessDefinition = subProcessResolver.findSubProcess(subProcessElement);
} catch (JbpmException e) {
jpdlReader.addWarning(e.getMessage());
}
// in case this is a self-recursive process invocation...
if (subProcessDefinition==null) {
String subProcessName = subProcessElement.attributeValue("name");
if (subProcessName.equals(processDefinition.getName())) {
subProcessDefinition = processDefinition;
}
}
}
if (subProcessDefinition!=null) {
log.debug("subprocess for process-state '"+name+"' bound to "+subProcessDefinition);
} else {
log.debug("subprocess for process-state '"+name+"' not yet bound");
}
this.variableAccesses = new HashSet(jpdlReader.readVariableAccesses(processStateElement));
}
public void execute(ExecutionContext executionContext) {
Token superProcessToken = executionContext.getToken();
// create the subprocess
ProcessInstance subProcessInstance = superProcessToken.createSubProcessInstance(subProcessDefinition);
// fire the subprocess created event
fireEvent(Event.EVENTTYPE_SUBPROCESS_CREATED, executionContext);
// feed the readable variableInstances
if ((variableAccesses != null) && (!variableAccesses.isEmpty())) {
ContextInstance superContextInstance = executionContext.getContextInstance();
ContextInstance subContextInstance = subProcessInstance.getContextInstance();
subContextInstance.setTransientVariables(superContextInstance.getTransientVariables());
// loop over all the variable accesses
Iterator iter = variableAccesses.iterator();
while (iter.hasNext()) {
VariableAccess variableAccess = (VariableAccess) iter.next();
// if this variable access is readable
if (variableAccess.isReadable()) {
// the variable is copied from the super process variable name
// to the sub process mapped name
String variableName = variableAccess.getVariableName();
Object value = superContextInstance.getVariable(variableName, superProcessToken);
String mappedName = variableAccess.getMappedName();
log.debug("copying super process var '"+variableName+"' to sub process var '"+mappedName+"': "+value);
if (value!=null) {
subContextInstance.setVariable(mappedName, value);
}
}
}
}
// send the signal to start the subprocess
subProcessInstance.signal();
}
public void leave(ExecutionContext executionContext, Transition transition) {
ProcessInstance subProcessInstance = executionContext.getSubProcessInstance();
Token superProcessToken = subProcessInstance.getSuperProcessToken();
// feed the readable variableInstances
if ((variableAccesses != null) && (!variableAccesses.isEmpty())) {
ContextInstance superContextInstance = executionContext.getContextInstance();
ContextInstance subContextInstance = subProcessInstance.getContextInstance();
// loop over all the variable accesses
Iterator iter = variableAccesses.iterator();
while (iter.hasNext()) {
VariableAccess variableAccess = (VariableAccess) iter.next();
// if this variable access is writable
if (variableAccess.isWritable()) {
// the variable is copied from the sub process mapped name
// to the super process variable name
String mappedName = variableAccess.getMappedName();
Object value = subContextInstance.getVariable(mappedName);
String variableName = variableAccess.getVariableName();
log.debug("copying sub process var '"+mappedName+"' to super process var '"+variableName+"': "+value);
if (value!=null) {
superContextInstance.setVariable(variableName, value, superProcessToken);
}
}
}
}
// fire the subprocess ended event
fireEvent(Event.EVENTTYPE_SUBPROCESS_END, executionContext);
// remove the subprocess reference
superProcessToken.setSubProcessInstance(null);
// call the subProcessEndAction
super.leave(executionContext, getDefaultLeavingTransition());
}
public ProcessDefinition getSubProcessDefinition() {
return subProcessDefinition;
}
public void setSubProcessDefinition(ProcessDefinition subProcessDefinition) {
this.subProcessDefinition = subProcessDefinition;
}
private static Log log = LogFactory.getLog(ProcessState.class);
}