org.jbpm.bpel.graph.exe.ScopeInstance.java Source code

Java tutorial

Introduction

Here is the source code for org.jbpm.bpel.graph.exe.ScopeInstance.java

Source

/*
 * JBoss, Home of Professional Open Source
 * Copyright 2005, JBoss Inc., and individual contributors as indicated
 * by the @authors tag.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the JBPM BPEL PUBLIC LICENSE AGREEMENT as
 * published by JBoss Inc.; either version 1.0 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.
 */
package org.jbpm.bpel.graph.exe;

import java.io.Serializable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.xml.namespace.QName;

import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.w3c.dom.Element;

import org.jbpm.JbpmContext;
import org.jbpm.bpel.alarm.AlarmAction;
import org.jbpm.bpel.graph.def.Activity;
import org.jbpm.bpel.graph.exe.state.ActiveState;
import org.jbpm.bpel.graph.scope.Handler;
import org.jbpm.bpel.graph.scope.OnAlarm;
import org.jbpm.bpel.graph.scope.OnEvent;
import org.jbpm.bpel.graph.scope.Scope;
import org.jbpm.bpel.integration.IntegrationService;
import org.jbpm.bpel.integration.def.CorrelationSetDefinition;
import org.jbpm.bpel.integration.def.PartnerLinkDefinition;
import org.jbpm.bpel.integration.def.ReceiveAction;
import org.jbpm.bpel.persistence.db.BpelGraphSession;
import org.jbpm.bpel.persistence.db.ScopeSession;
import org.jbpm.bpel.variable.def.VariableDefinition;
import org.jbpm.bpel.variable.def.VariableType;
import org.jbpm.bpel.variable.exe.MessageValue;
import org.jbpm.graph.def.Node;
import org.jbpm.graph.exe.ExecutionContext;
import org.jbpm.graph.exe.Token;
import org.jbpm.scheduler.SchedulerService;

/**
 * @author Juan Cantu
 * @version $Revision$ $Date: 2008/06/11 19:58:04 $
 */
public class ScopeInstance implements Serializable, Compensator {

    long id;
    private Scope definition;
    private ScopeState state;
    private Token token;
    private FaultInstance faultInstance;
    private Compensator compensator;

    private static final String PRIMARY_TOKEN = "primary";
    private static final String HANDLER_TOKEN = "handler";
    private static final String EVENTS_TOKEN = "events";
    private static final String EVENT_TOKEN_PREFIX = "event-";

    private static final Log log = LogFactory.getLog(ScopeInstance.class);

    private static final long serialVersionUID = 1L;

    ScopeInstance() {
    }

    protected ScopeInstance(Scope definition, Token token) {
        this.definition = definition;
        this.token = token;
        // initial state is performing primary activity
        state = ActiveState.PRIMARY;
        // create a token for the primary activity
        Activity activity = definition.getActivity();
        new Token(token, activity != null ? activity.getName() : PRIMARY_TOKEN);
    }

    public void initializeData() {
        // TODO variable initialization and bpws:scopeInitializationFault handling
        // variables
        for (Iterator i = definition.getVariables().values().iterator(); i.hasNext();)
            ((VariableDefinition) i.next()).createInstance(token);

        // correlation sets
        for (Iterator i = definition.getCorrelationSets().values().iterator(); i.hasNext();)
            ((CorrelationSetDefinition) i.next()).createInstance(token);

        // partner links
        for (Iterator i = definition.getPartnerLinks().values().iterator(); i.hasNext();)
            ((PartnerLinkDefinition) i.next()).createInstance(token);
    }

    // signals
    // ///////////////////////////////////////////////////////////////////////////

    public void faulted(FaultInstance faultInstance) {
        this.faultInstance = faultInstance;
        state.faulted(this);
    }

    public void terminate() {
        state.terminate(this);
    }

    public void compensate(Compensator compensator) {
        this.compensator = compensator;
        state.compensate(this);
    }

    public void completed() {
        state.completed(this);
    }

    public void scopeCompensated(ScopeInstance nestedInstance) {
        ScopeSession scopeSession = ScopeSession.getContextInstance(JbpmContext.getCurrentJbpmContext());
        ScopeInstance nextNestedInstance = scopeSession.nextChildToCompensate(this);
        if (nextNestedInstance != null)
            nextNestedInstance.compensate(this);
        else
            state.childrenCompensated(this);
    }

    public void scopeTerminated(ScopeInstance nestedInstance) {
        if (!hasTerminableChildren())
            state.childrenTerminated(this);
    }

    private boolean hasTerminableChildren() {
        for (Iterator i = new ScopeInstanceIterator(token); i.hasNext();) {
            ScopeInstance scopeInstance = (ScopeInstance) i.next();
            if (scopeInstance.getState().isTerminable())
                return true;
        }
        return false;
    }

    // behavior methods
    // ///////////////////////////////////////////////////////////////////////////

    /**
     * Selects a handler for the internal fault. The handler is selected as follows.
     * <ul>
     * <li>if the fault has no data, select a handler with a matching faultName and no faultVariable</li>
     * <li>if the fault has data, select a handler with a matching faultName and a matching
     * faultVariable; if there is no such handler then select a handler with a matching faultVariable
     * and no faultName</li>
     * <li>otherwise, select the catchAll handler if it exists</li>
     * </ul>
     * @return the selected fault handler, or <code>null</code> if no handler is able to catch the
     * fault
     */
    public Handler getFaultHandler() {
        if (faultInstance == null)
            throw new IllegalStateException("scope has not faulted");

        // determine the type of fault data
        VariableType dataType;
        // is it a message?
        MessageValue messageValue = faultInstance.getMessageValue();
        if (messageValue != null)
            dataType = messageValue.getType();
        else {
            // is it an element?
            Element elementValue = faultInstance.getElementValue();
            if (elementValue != null) {
                QName elementName = new QName(elementValue.getNamespaceURI(), elementValue.getLocalName());
                dataType = definition.getBpelProcessDefinition().getImportDefinition().getElementType(elementName);
            }
            // it is none of the above
            else
                dataType = null;
        }
        return definition.selectFaultHandler(faultInstance.getName(), dataType);
    }

    public void enableEvents() {
        List onEvents = definition.getOnEvents();
        List onAlarms = definition.getOnAlarms();

        // easy way out: no events to enable
        if (onEvents.isEmpty() && onAlarms.isEmpty())
            return;

        // eventToken is the context for event handlers
        Token eventToken = new Token(token, EVENTS_TOKEN);
        eventToken.setNode(definition);

        JbpmContext jbpmContext = JbpmContext.getCurrentJbpmContext();

        // enable message events
        IntegrationService integrationService = ReceiveAction.getIntegrationService(jbpmContext);
        for (int i = 0, n = onEvents.size(); i < n; i++) {
            OnEvent onEvent = (OnEvent) onEvents.get(i);
            integrationService.receive(onEvent.getReceiveAction(), eventToken, false);
        }

        // enable alarm events
        SchedulerService schedulerService = AlarmAction.getSchedulerService(jbpmContext);
        for (int i = 0, n = onAlarms.size(); i < n; i++) {
            OnAlarm onAlarm = (OnAlarm) onAlarms.get(i);
            onAlarm.getAlarmAction().createTimer(eventToken, schedulerService);
        }
    }

    public void disableEvents() {
        Token eventsToken = getEventsToken();
        // easy way out: no events to disable
        if (eventsToken == null)
            return;

        JbpmContext jbpmContext = JbpmContext.getCurrentJbpmContext();

        // disable message events
        List onEvents = definition.getOnEvents();
        IntegrationService integrationService = ReceiveAction.getIntegrationService(jbpmContext);
        for (int i = 0, n = onEvents.size(); i < n; i++) {
            OnEvent onEvent = (OnEvent) onEvents.get(i);
            integrationService.cancelReception(onEvent.getReceiveAction(), eventsToken);
        }

        // disable alarm events
        List onAlarms = definition.getOnAlarms();
        SchedulerService schedulerService = AlarmAction.getSchedulerService(jbpmContext);
        for (int i = 0, n = onAlarms.size(); i < n; i++) {
            OnAlarm onAlarm = (OnAlarm) onAlarms.get(i);
            onAlarm.getAlarmAction().deleteTimer(eventsToken, schedulerService);
        }
    }

    public void proceed() {
        Token parentToken = token.getParent();
        if (parentToken != null) {
            // end scope token (do not cause parent termination)
            token.end(false);
            // leave the scope
            new ExecutionContext(parentToken).leaveNode();
        } else {
            // end global scope token (this will end the process instance)
            token.end();
        }
    }

    public void terminateChildren() {
        Token handlerToken = getHandlerToken();
        if (handlerToken != null && !handlerToken.hasEnded()) {
            // terminate handler execution
            terminateToken(handlerToken);
        } else {
            Token primaryToken = getPrimaryToken();
            if (!primaryToken.hasEnded()) {
                // terminate primary activity execution
                terminateToken(primaryToken);
            }
            // check whether any event token needs termination
            Token eventsToken = getEventsToken();
            if (eventsToken != null && !eventsToken.hasEnded()) {
                // stop listening for events
                disableEvents();
                // terminate active event tokens
                Map eventTokens = eventsToken.getChildren();
                if (eventTokens != null) {
                    for (Iterator i = eventTokens.values().iterator(); i.hasNext();) {
                        Token eventToken = (Token) i.next();
                        if (!eventToken.hasEnded())
                            terminateToken(eventToken);
                    }
                }
                // end events token (do not cause parent termination)
                eventsToken.end(false);
            }
        }
        // notify children termination if no nested scope instances are being terminated
        if (!hasTerminableChildren())
            state.childrenTerminated(this);
    }

    private static void terminateToken(Token token) {
        Activity activity;
        // check whether node has the proper type already
        Node node = token.getNode();
        if (node instanceof Activity)
            activity = (Activity) node;
        else {
            // acquire proxy of the proper type
            JbpmContext jbpmContext = JbpmContext.getCurrentJbpmContext();
            BpelGraphSession graphSession = BpelGraphSession.getContextInstance(jbpmContext);
            activity = graphSession.loadActivity(node.getId());
        }

        // terminate activity
        activity.terminate(new ExecutionContext(token));

        // end token (do not verify parent termination)
        token.end(false);
    }

    public boolean hasPendingEvents() {
        Token eventsToken = getEventsToken();
        if (eventsToken == null)
            return false;

        for (Iterator i = new ScopeInstanceIterator(eventsToken); i.hasNext();) {
            ScopeInstance scopeInstance = (ScopeInstance) i.next();
            if (!scopeInstance.getState().isEnd())
                return true;
        }
        return false;
    }

    public Token getPrimaryToken() {
        Activity activity = definition.getActivity();
        return token.getChild(activity != null ? activity.getName() : PRIMARY_TOKEN);
    }

    public Token createEventToken() {
        Token eventsToken = getEventsToken();
        Map eventTokens = eventsToken.getChildren();
        return new Token(eventsToken, EVENT_TOKEN_PREFIX + (eventTokens != null ? eventTokens.size() : 0));
    }

    public Token createHandlerToken() {
        if (token.hasChild(HANDLER_TOKEN))
            throw new IllegalStateException("handler token already exists");

        return new Token(token, HANDLER_TOKEN);
    }

    public Token getHandlerToken() {
        return token.getChild(HANDLER_TOKEN);
    }

    private Token getEventsToken() {
        return token.getChild(EVENTS_TOKEN);
    }

    public Map getEventTokens() {
        return getEventsToken().getChildren();
    }

    public Token getEventToken(int index) {
        return getEventsToken().getChild(EVENT_TOKEN_PREFIX + index);
    }

    public ScopeState getState() {
        return state;
    }

    public void setState(ScopeState state) {
        log.debug("state change to " + state.getName() + " on " + definition + " for " + token);
        this.state = state;
    }

    public FaultInstance getFaultInstance() {
        return faultInstance;
    }

    public void setFaultInstance(FaultInstance faultInstance) {
        this.faultInstance = faultInstance;
    }

    public Compensator getCompensator() {
        return compensator;
    }

    public void setCompensator(Compensator compensator) {
        this.compensator = compensator;
    }

    public Token getToken() {
        return token;
    }

    public void setToken(Token token) {
        this.token = token;
    }

    public Scope getDefinition() {
        return definition;
    }

    // operations helper methods
    // ///////////////////////////////////////////////////////////////////////////

    public ScopeInstance getParent() {
        Token parentToken = token.getParent();
        return parentToken != null ? Scope.getInstance(parentToken) : null;
    }

    public String toString() {
        ToStringBuilder builder = new ToStringBuilder(this).append("name", definition.getName())
                .append("token", token.getFullName()).append("state", state.getName());

        if (faultInstance != null)
            builder.append("fault", faultInstance);

        if (compensator != null)
            builder.append("compensator", compensator);

        return builder.toString();
    }

    public static ScopeInstance createScopeInstance(Scope definition, Token token) {
        return new ScopeInstance(definition, token);
    }

    public static ScopeInstance createEventInstance(Scope scope, Token token) {
        return new EventInstance(scope, token);
    }
}