org.atricore.idbus.kernel.planning.jbpm.ProcessFragmentState.java Source code

Java tutorial

Introduction

Here is the source code for org.atricore.idbus.kernel.planning.jbpm.ProcessFragmentState.java

Source

/*
 * Atricore IDBus
 *
 * Copyright (c) 2009, Atricore Inc.
 *
 * 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.atricore.idbus.kernel.planning.jbpm;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.Collection;

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.JbpmContext;
import org.jbpm.context.def.VariableAccess;
import org.jbpm.context.exe.ContextInstance;
import org.jbpm.graph.def.*;
import org.jbpm.graph.exe.ExecutionContext;
import org.jbpm.graph.exe.ProcessInstance;
import org.jbpm.graph.exe.Token;
import org.jbpm.graph.log.ProcessStateLog;
import org.jbpm.jpdl.xml.JpdlXmlReader;
import org.jbpm.jpdl.xml.Parsable;
import org.jbpm.util.Clock;

/**
 * @author <a href="mailto:gbrigandi@atricore.org">Gianluca Brigandi</a>
 * @version $Rev: 278 $ $Date: 2008-12-31 19:42:22 -0200 (Wed, 31 Dec 2008) $
 */
public class ProcessFragmentState extends Node implements Parsable {

    private static final long serialVersionUID = 1L;

    protected final transient Log logger = LogFactory.getLog(getClass());

    static ProcessFragmentResolver defaultProcessFragmentResolver;

    static BPMSManager bpmsManager;

    public static synchronized void setDefaultProcessFragmentResolver(
            ProcessFragmentResolver processFragmentResolver) {
        defaultProcessFragmentResolver = processFragmentResolver;
    }

    public static ProcessFragmentResolver getDefaultProcessFragmentResolver() {
        return defaultProcessFragmentResolver;
    }

    public static synchronized void setBpmsManager(BPMSManager m) {
        bpmsManager = m;
    }

    protected Set<VariableAccess> variableAccesses = null;
    protected String processFragmentName = null;
    protected String processFragmentLifecycle = null;
    protected String processFragmentPhase = null;
    protected ProcessDefinition processFragmentDefinition = null;

    public ProcessFragmentState() {
        super();
    }

    // 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) {
        logger.debug("Start reading JPDL from XML ...");

        ProcessFragment processFragment;
        Element processFragmentElement = processStateElement.element("process-fragment");

        if (processFragmentElement != null) {

            processFragmentLifecycle = processFragmentElement.attributeValue("lifecycle");
            processFragmentPhase = processFragmentElement.attributeValue("phase");

            ProcessFragmentResolver processFragmentResolver = getProcessFragmentResolver();

            try {

                processFragment = processFragmentResolver.findProcessFragment(processFragmentElement);

                if (processFragment != null) {
                    processFragmentName = processFragment.getName();
                    processFragmentDefinition = processFragment.getDefinition();

                    JbpmContext jbpmContext = JbpmContext.getCurrentJbpmContext();

                    if (jbpmContext != null) {

                        logger.debug("Contributions found for lifecycle [" + processFragmentLifecycle + "], "
                                + "phase [" + processFragmentPhase + "]");

                        logger.debug("Deploying Process Fragment Definition '" + processFragmentDefinition.getName()
                                + "'");

                        jbpmContext.deployProcessDefinition(processFragmentDefinition);

                        // Dump this process fragment for debugging purposes.
                        if (logger.isDebugEnabled()) {

                            logger.debug("Process Fragment [" + processFragmentName + "] Nodes:");

                            java.util.List<Node> nodes = processFragmentDefinition.getNodes();
                            for (Node node : nodes) {

                                StringBuffer sb = new StringBuffer();
                                sb.append("Node: ").append(node.getFullyQualifiedName());

                                sb.append(" from: [");
                                java.util.Set<Transition> froms = node.getArrivingTransitions();
                                if (froms != null) {
                                    String prefix = "";
                                    for (Transition t : froms) {
                                        sb.append(prefix).append(t.getFrom().getFullyQualifiedName());
                                        prefix = ",";
                                    }
                                }
                                sb.append("]");

                                java.util.List<Transition> tos = node.getLeavingTransitions();
                                sb.append(" to: [");
                                if (tos != null) {
                                    String prefix = "";
                                    for (Transition t : tos) {
                                        if (t.getTo() != null)
                                            sb.append(prefix).append(t.getTo().getFullyQualifiedName());
                                        else
                                            sb.append(prefix).append("UNRESOLVED");
                                        prefix = ",";
                                    }
                                }
                                sb.append("]");

                                logger.debug(sb);
                            }
                        }

                        logger.debug("Deployed Process Fragment Definition " + processFragmentDefinition.getName());
                    }
                } else {
                    logger.debug("No contributions found for lifecycle [" + processFragmentLifecycle + "], "
                            + "phase [" + processFragmentPhase + "]");
                }
            } catch (JbpmException e) {
                jpdlReader.addWarning(e.getMessage());
            }

        }

        if (processFragmentDefinition != null) {
            logger.debug("processfragment for process-state '" + name + "' bound to '"
                    + processFragmentDefinition.getName() + "'");
        }

        // Fill variable accesses

        this.variableAccesses = new HashSet<VariableAccess>();
        java.util.List vas = jpdlReader.readVariableAccesses(processStateElement);
        for (Object va : vas) {
            this.variableAccesses.add((VariableAccess) va);
        }

        logger.debug("End reading JPDL from XML");

    }

    private ProcessFragmentResolver getProcessFragmentResolver() {
        ProcessFragmentResolver processFragmentResolver = defaultProcessFragmentResolver;
        /* TODO : Check why this restarts all spring setups!
        if (JbpmConfiguration.Configs.hasObject("jbpm.process.fragment.resolver")) {
        processFragmentResolver = (ProcessFragmentResolver) JbpmConfiguration.Configs.getObject("jbpm.process.fragment.resolver");
        } */
        return processFragmentResolver;
    }

    public void execute(ExecutionContext executionContext) {
        ProcessFragment processFragment;
        Token superProcessToken = executionContext.getToken();
        ProcessDefinition usedProcessFragmentDefinition = processFragmentDefinition;

        ProcessFragmentRegistry pfr;
        String pdn;
        if (processFragmentName != null) {

            pfr = (ProcessFragmentRegistry) executionContext.getContextInstance()
                    .getTransientVariable(Constants.VAR_PFR);
            if (pfr == null) {
                throw new NullPointerException("No ProcessFragmentRegistry instance found as transient variable ["
                        + Constants.VAR_PFR + "] in fragment " + this.processFragmentName);
            }

            pdn = (String) executionContext.getContextInstance().getTransientVariable(Constants.VAR_PDN);
            if (pdn == null) {
                throw new NullPointerException("No Process Descriptor Name instance found as transient variable ["
                        + Constants.VAR_PDN + "] in fragment " + this.processFragmentName);
            }

            processFragment = pfr.lookupProcessFragment(processFragmentName);
            ProcessDescriptor currentProcessDescriptor = pfr.lookupProcessDescriptor(pdn);
            boolean isProcessFragmentActive = currentProcessDescriptor.isActive(processFragment.getName());
            if (isProcessFragmentActive) {

                logger.debug("Contributions found for lifecycle [" + processFragmentLifecycle + "], " + "phase ["
                        + processFragmentPhase + "]. Spawning enabled fragment " + processFragment.getName());

                // create the processfragment
                ProcessInstance processFragmentInstance = superProcessToken
                        .createSubProcessInstance(usedProcessFragmentDefinition);
                // fire the processfragment created event
                fireEvent(Event.EVENTTYPE_SUBPROCESS_CREATED, executionContext);
                // Copy all transient variables
                ContextInstance superContextInstance = executionContext.getContextInstance();
                ContextInstance subContextInstance = processFragmentInstance.getContextInstance();

                for (Object var : superContextInstance.getTransientVariables().keySet()) {
                    logger.debug("Copying super process transient var '" + var + "'");
                }
                subContextInstance.setTransientVariables(superContextInstance.getTransientVariables());

                // feed the readable variableInstances
                if ((variableAccesses != null) && (!variableAccesses.isEmpty())) {

                    // loop over all the variable accesses
                    for (VariableAccess variableAccess : variableAccesses) {

                        // 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() != null
                                    ? variableAccess.getMappedName()
                                    : variableAccess.getVariableName();

                            if (value != null) {
                                logger.debug("Copying super process var '" + variableName + "' to sub process var '"
                                        + mappedName + "': " + value);
                                subContextInstance.setVariable(mappedName, value);
                            } else {
                                logger.debug("Super process var '" + variableName + "' has no value, ignoring");
                            }
                        }
                    }

                }

                // TODO : If BPM enigne is removed from planning, this must go way
                // Always add IN/OUT Artifacts as variables!
                if (logger.isDebugEnabled())
                    logger.debug("Automatically Copying super process var '" + Constants.VAR_IN_IDENTITY_ARTIFACT
                            + "' to sub process var '" + Constants.VAR_IN_IDENTITY_ARTIFACT + "': "
                            + superContextInstance.getVariable(Constants.VAR_IN_IDENTITY_ARTIFACT,
                                    superProcessToken));
                subContextInstance.setVariable(Constants.VAR_IN_IDENTITY_ARTIFACT,
                        superContextInstance.getVariable(Constants.VAR_IN_IDENTITY_ARTIFACT, superProcessToken));

                if (logger.isDebugEnabled())
                    logger.debug("Automatically Copying super process var '" + Constants.VAR_OUT_IDENTITY_ARTIFACT
                            + "' to sub process var '" + Constants.VAR_OUT_IDENTITY_ARTIFACT + "': "
                            + superContextInstance.getVariable(Constants.VAR_OUT_IDENTITY_ARTIFACT,
                                    superProcessToken));
                subContextInstance.setVariable(Constants.VAR_OUT_IDENTITY_ARTIFACT,
                        superContextInstance.getVariable(Constants.VAR_OUT_IDENTITY_ARTIFACT, superProcessToken));
                processFragmentInstance.signal();
                if (!processFragmentInstance.hasEnded()) {
                    logger.warn("Identity Plan process fragment '" + processFragmentName + "' ["
                            + processFragmentInstance.getId() + "] has not ended! Check your process definition");
                }
                logger.debug("Spawned enabled Process Fragment " + processFragment.getName());

            } else {
                if (logger.isDebugEnabled()) {
                    StringBuffer actives = new StringBuffer();
                    Collection<String> activeFragments = currentProcessDescriptor.getActiveProcessFragments();
                    for (String name : activeFragments) {
                        actives.append(name).append(",");
                    }
                    logger.debug("Process Fragment " + processFragment.getName()
                            + " not enabled. Skipping execution.  " + "Active fragments are [" + actives + "]");
                }
                leave(executionContext, getDefaultLeavingTransition());
            }
        } else {
            logger.debug("No contributions found for lifecycle [" + processFragmentLifecycle + "], " + "phase ["
                    + processFragmentPhase + "]. Skipping execution...");
            leave(executionContext, getDefaultLeavingTransition());
        }

    }

    public void leave(ExecutionContext executionContext, Transition transition) {
        ProcessInstance processFragmentInstance = executionContext.getSubProcessInstance();

        if (processFragmentInstance != null) {
            Token superProcessToken = processFragmentInstance.getSuperProcessToken();

            // feed the readable variableInstances
            if ((variableAccesses != null) && (!variableAccesses.isEmpty())) {

                ContextInstance superContextInstance = executionContext.getContextInstance();
                ContextInstance subContextInstance = processFragmentInstance.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();

                        if (value != null) {
                            logger.debug("copying sub process var '" + mappedName + "' to super process var '"
                                    + variableName + "': " + value);
                            superContextInstance.setVariable(variableName, value, superProcessToken);
                        }
                    }
                }
            }

            // fire the processfragment ended event
            fireEvent(Event.EVENTTYPE_SUBPROCESS_END, executionContext);

            // remove the processfragment reference
            superProcessToken.setSubProcessInstance(null);

            // We replaced the normal log generation of super.leave() by creating the log here
            // and overriding the addNodeLog method with an empty version
            superProcessToken.addLog(new ProcessStateLog(this, superProcessToken.getNodeEnter(),
                    Clock.getCurrentTime(), processFragmentInstance));

        }

        // call the processFragmentEndAction
        super.leave(executionContext, getDefaultLeavingTransition());
    }

    // We replaced the normal log generation of super.leave() by creating the log above in the leave method
    // and overriding the addNodeLog method with an empty version
    protected void addNodeLog(Token token) {
    }

}