org.yawlfoundation.yawl.elements.YAtomicTask.java Source code

Java tutorial

Introduction

Here is the source code for org.yawlfoundation.yawl.elements.YAtomicTask.java

Source

/*
 * Copyright (c) 2004-2012 The YAWL Foundation. All rights reserved.
 * The YAWL Foundation is a collaboration of individuals and
 * organisations who are committed to improving workflow technology.
 *
 * This file is part of YAWL. YAWL 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.
 *
 * YAWL 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 YAWL. If not, see <http://www.gnu.org/licenses/>.
 */

package org.yawlfoundation.yawl.elements;

import org.jdom2.Element;
import org.yawlfoundation.yawl.elements.data.YParameter;
import org.yawlfoundation.yawl.elements.state.YIdentifier;
import org.yawlfoundation.yawl.engine.YPersistenceManager;
import org.yawlfoundation.yawl.engine.YWorkItem;
import org.yawlfoundation.yawl.exceptions.YDataStateException;
import org.yawlfoundation.yawl.exceptions.YPersistenceException;
import org.yawlfoundation.yawl.exceptions.YQueryException;
import org.yawlfoundation.yawl.exceptions.YStateException;
import org.yawlfoundation.yawl.util.YVerificationHandler;

import java.util.*;

/**
 * A YAtomicTask object is the executable equivalent of the Atomic Task
 * in the YAWL language. They have the same properties and behaviour.
 *
 * @author Lachlan Aldred
 * @author Michael Adams (v2.0 and later)
 * @since 0.1
 */
public class YAtomicTask extends YTask {

    /**
     * Constructs a new atomic task.
     * @param id the task identifier.
     * @param joinType the task's join type.
     * @param splitType the task's split type.
     * @param container the task's containing net.
     * @see YTask
     */
    public YAtomicTask(String id, int joinType, int splitType, YNet container) {
        super(id, joinType, splitType, container);
    }

    /**
     * Sets the enablement data mappings for an atomic task to those specified.
     * @param map a map of [variable name, query] pairs.
     * @deprecated Since 2.0, enablement mappings have no function.
     */
    public void setDataMappingsForEnablement(Map<String, String> map) {
        _dataMappingsForTaskEnablement.putAll(map);
    }

    /**
     * Changes the inner state of an atomic task from entered to executing.
     * @param pmgr an instantiated persistence manager object.
     * @param id the identifier to move from inner marking 'entered' to inner marking
     * 'executing'.
     * @throws YPersistenceException if there's a problem persisting the change.
     */
    protected void startOne(YPersistenceManager pmgr, YIdentifier id) throws YPersistenceException {
        this._mi_entered.removeOne(pmgr, id);
        this._mi_executing.add(pmgr, id);
    }

    /**
     * Checks that a task is currently executing.
     * @return true if the task has 'executing' state.
     */
    public boolean isRunning() {
        return _i != null;
    }

    /**
     * Cancels a task.
     * @param pmgr an instantiated persistence manager object.
     * @throws YPersistenceException if there's a problem persisting the change.
     */
    public synchronized void cancel(YPersistenceManager pmgr) throws YPersistenceException {
        cancelBusyWorkItem(pmgr);
        super.cancel(pmgr);
    }

    /**
     * Cancels the task. If the task is not currently executing, first check that the
     * workitem is still referenced by the engine before attempting the cancellation.
     * @param pmgr an instantiated persistence manager object.
     * @param caseID the case identifier of this atomic task.
     * @throws YPersistenceException if there's a problem persisting the change.
     */
    public synchronized void cancel(YPersistenceManager pmgr, YIdentifier caseID) throws YPersistenceException {
        if (!cancelBusyWorkItem(pmgr)) {
            String workItemID = caseID.get_idString() + ":" + getID();
            YWorkItem workItem = getWorkItemRepository().get(workItemID);
            if (null != workItem)
                cancelWorkItem(pmgr, workItem);
        }
        super.cancel(pmgr);
    }

    private boolean cancelBusyWorkItem(YPersistenceManager pmgr) throws YPersistenceException {

        // nothing to do if not fired or has no decomposition
        if ((_i == null) || (_decompositionPrototype == null))
            return false;

        YWorkItem workItem = getWorkItemRepository().get(_i.toString(), getID());
        if (null != workItem)
            cancelWorkItem(pmgr, workItem);
        return true;
    }

    private void cancelWorkItem(YPersistenceManager pmgr, YWorkItem workItem) throws YPersistenceException {
        getWorkItemRepository().removeWorkItemFamily(workItem);
        workItem.cancel(pmgr);
    }

    /**
     * Rolls back a task's inner state from 'executing' to 'entered'.
     * <p/>
     * The roll back will only occur if the task's inner 'executing' marking contains
     * the identifier specified.
     * @param pmgr an instantiated persistence manager object.
     * @param caseID the case identifier of this atomic task.
     * @return true if the rollback occurs, false if the rollback request could not
     * be actioned because the task's inner 'executing' marking does not contain 
     * the identifier specified.
     * @throws YPersistenceException if there's a problem persisting the change.
     */
    public boolean t_rollBackToFired(YPersistenceManager pmgr, YIdentifier caseID) throws YPersistenceException {
        if (_mi_executing.contains(caseID)) {
            _mi_executing.removeOne(pmgr, caseID);
            _mi_entered.add(pmgr, caseID);
            return true;
        }
        return false;
    }

    /**
     * Clones this atomic task.
     * @return a (Object) clone of the task.
     * @throws CloneNotSupportedException if there's a problem cloning the task.
     */
    public Object clone() throws CloneNotSupportedException {
        YNet copyContainer = _net.getCloneContainer();
        if (copyContainer.getNetElements().containsKey(this.getID())) {
            return copyContainer.getNetElement(this.getID());
        }
        return super.clone();
    }

    /**
     * Gets the map of enablement mappings for the task.
     * @return the map of enablement mappings.
     * @deprecated Since 2.0, enablement mappings have no function.
     */
    public Map getDataMappingsForEnablement() {
        return _dataMappingsForTaskEnablement;
    }

    /**
     * Builds the enablement data set for the task.
     * @return the enablement data set; that is, a set of data variables and
     * corresponding values that were populated after evaluating their mapping
     * expressions.
     * @throws YQueryException if there's a problem with a query evaluation.
     * @throws YDataStateException if there's a problem with the evaluated data.
     * @throws YStateException if there's a problem setting the task state.
     * @deprecated Since 2.0, enablement mappings have no function.
     */
    public Element prepareEnablementData() throws YQueryException, YDataStateException {
        if (null == getDecompositionPrototype()) {
            return null;
        }
        Element enablementData = produceDataRootElement();
        YAWLServiceGateway serviceGateway = (YAWLServiceGateway) _decompositionPrototype;
        List<YParameter> enablementParams = new ArrayList<YParameter>(
                serviceGateway.getEnablementParameters().values());
        Collections.sort(enablementParams);
        for (YParameter parameter : enablementParams) {
            String paramName = parameter.getPreferredName();
            String expression = _dataMappingsForTaskEnablement.get(paramName);
            Element result = performDataExtraction(expression, parameter);
            enablementData.addContent(result.clone());
        }
        return enablementData;
    }

    /***** VERIFICATION *******************************************************/

    /**
     * Verifies this atomic task definition against YAWL semantics.
     * @return a List of error and/or warning messages. An empty list is returned if
     * the atomic task verifies successfully.
     */
    public void verify(YVerificationHandler handler) {
        super.verify(handler);
        if (_decompositionPrototype == null) {
            if (_multiInstAttr != null
                    && (_multiInstAttr.getMaxInstances() > 1 || _multiInstAttr.getThreshold() > 1)) {
                handler.error(this, this + " cannot have multiple instances and a blank work description.");
            }
        } else if (!(_decompositionPrototype instanceof YAWLServiceGateway)) {
            handler.error(this, this + " task may not decompose to other than a WebServiceGateway.");
            checkEnablementParameterMappings(handler);
        }
    }

    /**
     * Verify this atomic task's enablement mappings.
     * @return a List of error and/or warning messages. An empty list is returned if
     * the atomic task's enablement mappings verify successfully.
     * @deprecated Since 2.0, enablement mappings have no function.
     */
    private void checkEnablementParameterMappings(YVerificationHandler handler) {

        //check that there is a link to each enablementParam
        Set<String> enablementParamNamesAtGateway = ((YAWLServiceGateway) _decompositionPrototype)
                .getEnablementParameterNames();
        Set<String> enablementParamNamesAtTask = _dataMappingsForTaskEnablement.keySet();

        //check that task input var maps to decomp input var
        for (String paramName : enablementParamNamesAtGateway) {
            if (!enablementParamNamesAtTask.contains(paramName)) {
                handler.error(this,
                        "The task [id= " + this.getID() + "] needs to be connected with the enablement parameter ["
                                + paramName + "] of decomposition [" + _decompositionPrototype + "].");
            }
        }
        for (String paramNameAtTask : enablementParamNamesAtTask) {
            String query = _dataMappingsForTaskEnablement.get(paramNameAtTask);
            checkXQuery(query, paramNameAtTask, handler);
            if (!enablementParamNamesAtGateway.contains(paramNameAtTask)) {
                handler.error(this,
                        "The task [id= " + this.getID() + "] cannot connect with enablement parameter ["
                                + paramNameAtTask + "] because it doesn't exist" + " at its decomposition ["
                                + _decompositionPrototype + "].");
            }
        }
    }

}