Package org.ofbiz.workflow.impl

Source Code of org.ofbiz.workflow.impl.WfProcessImpl

/*******************************************************************************
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*******************************************************************************/
package org.ofbiz.workflow.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.ofbiz.base.util.Debug;
import org.ofbiz.base.util.StringUtil;
import org.ofbiz.base.util.UtilDateTime;
import org.ofbiz.base.util.UtilMisc;
import org.ofbiz.base.util.UtilValidate;
import org.ofbiz.entity.Delegator;
import org.ofbiz.entity.GenericEntityException;
import org.ofbiz.entity.GenericValue;
import org.ofbiz.service.GenericResultWaiter;
import org.ofbiz.service.LocalDispatcher;
import org.ofbiz.service.job.Job;
import org.ofbiz.service.job.JobManager;
import org.ofbiz.service.job.JobManagerException;
import org.ofbiz.workflow.AlreadyRunning;
import org.ofbiz.workflow.CannotChangeRequester;
import org.ofbiz.workflow.CannotStart;
import org.ofbiz.workflow.CannotStop;
import org.ofbiz.workflow.InvalidData;
import org.ofbiz.workflow.InvalidPerformer;
import org.ofbiz.workflow.InvalidState;
import org.ofbiz.workflow.NotRunning;
import org.ofbiz.workflow.ResultNotAvailable;
import org.ofbiz.workflow.WfActivity;
import org.ofbiz.workflow.WfEventAudit;
import org.ofbiz.workflow.WfException;
import org.ofbiz.workflow.WfFactory;
import org.ofbiz.workflow.WfProcess;
import org.ofbiz.workflow.WfProcessMgr;
import org.ofbiz.workflow.WfRequester;
import org.ofbiz.workflow.WfUtil;
import org.ofbiz.workflow.client.StartActivityJob;

/**
* WfProcessImpl - Workflow Process Object implementation
*/
public class WfProcessImpl extends WfExecutionObjectImpl implements WfProcess {

    public static final String module = WfProcessImpl.class.getName();

    protected WfRequester requester = null;
    protected WfProcessMgr manager = null;

    public WfProcessImpl(GenericValue valueObject, WfProcessMgr manager) throws WfException {
        super(valueObject, null);
        this.manager = manager;
        this.requester = null;
        init();
    }

    /**
     * @see org.ofbiz.workflow.impl.WfExecutionObjectImpl#WfExecutionObjectImpl(org.ofbiz.entity.Delegator, java.lang.String)
     */
    public WfProcessImpl(Delegator delegator, String workEffortId) throws WfException {
        super(delegator, workEffortId);
        if (UtilValidate.isNotEmpty(activityId))
            throw new WfException("Execution object is not of type WfProcess.");
        this.manager = WfFactory.getWfProcessMgr(delegator, packageId, packageVersion, processId, processVersion);
        this.requester = null;
    }

    private void init() throws WfException {
        // since we are a process we don't have a context yet
        // get the context to use with parsing descriptions from the manager
        Map<String, Object> context = manager.getInitialContext();
        this.parseDescriptions(context);
    }

    /**
     * @see org.ofbiz.workflow.WfProcess#setRequester(org.ofbiz.workflow.WfRequester)
     */
    public void setRequester(WfRequester newValue) throws WfException, CannotChangeRequester {
        if (requester != null)
            throw new CannotChangeRequester();
        requester = newValue;
    }

    /**
     * @see org.ofbiz.workflow.WfProcess#getSequenceStep(int)
     */
    public List<WfActivity> getSequenceStep(int maxNumber) throws WfException {
        if (maxNumber > 0)
            return new ArrayList<WfActivity>(activeSteps().subList(0, maxNumber - 1));
        return activeSteps();
    }

    /**
     * @see org.ofbiz.workflow.WfExecutionObject#abort()
     */
    @Override
    public void abort() throws WfException, CannotStop, NotRunning {
        super.abort();

        // cancel the active activities
        for (WfActivity activity : this.activeSteps()) {
            activity.abort();
        }
    }

    /**
     * @see org.ofbiz.workflow.WfProcess#start()
     */
    public void start() throws WfException, CannotStart, AlreadyRunning {
        start(null);
    }

    /**
     * @see org.ofbiz.workflow.WfProcess#start()
     */
    public void start(String activityId) throws WfException, CannotStart, AlreadyRunning {
        if (state().equals("open.running"))
            throw new AlreadyRunning("Process is already running");

        if (activityId == null && getDefinitionObject().get("defaultStartActivityId") == null)
            throw new CannotStart("Initial activity is not defined.");

        changeState("open.running");

        // start the first activity (using the defaultStartActivityId)
        GenericValue start = null;

        try {
            if (activityId != null) {
                GenericValue processDef = getDefinitionObject();
                Map<String, Object> fields = UtilMisc.toMap("packageId", (Object) processDef.getString("packageId"), "packageVersion",
                        processDef.getString("packageVersion"), "processId", processDef.getString("processId"),
                        "processVersion", processDef.getString("processVersion"), "activityId", activityId);
                start = getDelegator().findByPrimaryKey("WorkflowActivity", fields);

                // here we must check and make sure this activity is defined to as a starting activity
                if (!start.getBoolean("canStart").booleanValue())
                    throw new CannotStart("The specified activity cannot initiate the workflow process");
            } else {
                // this is either the first activity defined or specified as an ExtendedAttribute
                // since this is defined in XPDL, we don't care if canStart is set.
                start = getDefinitionObject().getRelatedOne("DefaultStartWorkflowActivity");
            }
        } catch (GenericEntityException e) {
            throw new WfException(e.getMessage(), e.getNested());
        }
        if (start == null)
            throw new CannotStart("No initial activity available");

        if (Debug.verboseOn())
            Debug.logVerbose("[WfProcess.start] : Started the workflow process.", module);

        // set the actualStartDate
        try {
            GenericValue v = getRuntimeObject();
            v.set("actualStartDate", UtilDateTime.nowTimestamp());
            v.store();
        } catch (GenericEntityException e) {
            Debug.logWarning("Could not set 'actualStartDate'.", module);
            e.printStackTrace();
        }
        startActivity(start);
    }

    /**
     * @see org.ofbiz.workflow.WfProcess#manager()
     */
    public WfProcessMgr manager() throws WfException {
        return manager;
    }

    /**
     * @see org.ofbiz.workflow.WfProcess#requester()
     */
    public WfRequester requester() throws WfException {
        return requester;
    }

    /**
     * @see org.ofbiz.workflow.WfProcess#getIteratorStep()
     */
    public Iterator<WfActivity> getIteratorStep() throws WfException {
        return activeSteps().iterator();
    }

    /**
     * @see org.ofbiz.workflow.WfProcess#isMemberOfStep(org.ofbiz.workflow.WfActivity)
     */
    public boolean isMemberOfStep(WfActivity member) throws WfException {
        return activeSteps().contains(member);
    }

    /**
     * @see org.ofbiz.workflow.WfProcess#getActivitiesInState(java.lang.String)
     */
    public Iterator<WfActivity> getActivitiesInState(String state) throws WfException, InvalidState {
        List<WfActivity> res = new ArrayList<WfActivity>();
       
        for (WfActivity a : activeSteps()) {
            if (a.state().equals(state))
                res.add(a);
        }
        return res.iterator();
    }

    /**
     * @see org.ofbiz.workflow.WfProcess#result()
     */
    public Map<String, Object> result() throws WfException, ResultNotAvailable {
        Map<String, Object> resultSig = manager().resultSignature();
        Map<String, Object> results = new HashMap<String, Object>();
        Map<String, Object> context = processContext();

        if (resultSig != null) {
            Set<String> resultKeys = resultSig.keySet();
           
            for (String key : resultKeys) {
                if (context.containsKey(key))
                    results.put(key, context.get(key));
            }
        }
        return results;
    }

    /**
     * @see org.ofbiz.workflow.WfProcess#howManyStep()
     */
    public int howManyStep() throws WfException {
        return activeSteps().size();
    }

    /**
     * @see org.ofbiz.workflow.WfProcess#receiveResults(org.ofbiz.workflow.WfActivity, java.util.Map)
     */
    public synchronized void receiveResults(WfActivity activity, Map<String, Object> results) throws WfException, InvalidData {
        Map<String, Object> context = processContext();
        context.putAll(results);
        setSerializedData(context);
    }

    /**
     * @see org.ofbiz.workflow.WfProcess#activityComplete(org.ofbiz.workflow.WfActivity)
     */
    public synchronized void activityComplete(WfActivity activity) throws WfException {
        if (!activity.state().equals("closed.completed"))
            throw new WfException("Activity state is not completed");
        if (Debug.verboseOn()) Debug.logVerbose("[WfProcess.activityComplete] : Activity (" + activity.name() + ") is complete", module);
        queueNext(activity);
    }

    /**
     * @see org.ofbiz.workflow.impl.WfExecutionObjectImpl#executionObjectType()
     */
    @Override
    public String executionObjectType() {
        return "WfProcess";
    }

    // Queues the next activities for processing
    private void queueNext(WfActivity fromActivity) throws WfException {
        List<GenericValue> nextTrans = getTransFrom(fromActivity);

        if (nextTrans.size() > 0) {
            for (GenericValue trans : nextTrans) {
                // Get the activity definition
                GenericValue toActivity = null;

                try {
                    toActivity = trans.getRelatedOne("ToWorkflowActivity");
                } catch (GenericEntityException e) {
                    throw new WfException(e.getMessage(), e);
                }

                // check for a join
                String join = "WJT_AND"; // default join is AND

                if (toActivity.get("joinTypeEnumId") != null)
                    join = toActivity.getString("joinTypeEnumId");

                if (Debug.verboseOn()) Debug.logVerbose("[WfProcess.queueNext] : " + join + " join.", module);

                // activate if XOR or test the join transition(s)
                if (join.equals("WJT_XOR"))
                    startActivity(toActivity);
                else
                    joinTransition(toActivity, trans);
            }
        } else {
            if (Debug.verboseOn())
                Debug.logVerbose("[WfProcess.queueNext] : No transitions left to follow.", module);
            this.finishProcess();
        }
    }

    // Follows the and-join transition
    private void joinTransition(GenericValue toActivity,
        GenericValue transition) throws WfException {
        // get all TO transitions to this activity
        GenericValue dataObject = getRuntimeObject();
       
        List<GenericValue> toTrans = null;
        try {
            toTrans = toActivity.getRelated("ToWorkflowTransition");
        } catch (GenericEntityException e) {
            throw new WfException(e.getMessage(), e);
        }

        // get a list of followed transition to this activity
        List<GenericValue> followed = null;
        try {
            Map<String, Object> fields = new HashMap<String, Object>();
            fields.put("processWorkEffortId", dataObject.getString("workEffortId"));
            fields.put("toActivityId", toActivity.getString("activityId"));
            followed = getDelegator().findByAnd("WorkEffortTransBox", fields);
        } catch (GenericEntityException e) {
            throw new WfException(e.getMessage(), e);
        }

        if (Debug.verboseOn()) Debug.logVerbose("[WfProcess.joinTransition] : toTrans (" + toTrans.size() + ") followed (" +
                (followed.size() + 1) + ")", module);

        // check to see if all transition requirements are met
        if (toTrans.size() == (followed.size() + 1)) {
            Debug.logVerbose("[WfProcess.joinTransition] : All transitions have followed.", module);
            startActivity(toActivity);
            try {
                Map<String, Object> fields = new HashMap<String, Object>();
                fields.put("processWorkEffortId", dataObject.getString("workEffortId"));
                fields.put("toActivityId", toActivity.getString("activityId"));
                getDelegator().removeByAnd("WorkEffortTransBox", fields);
            } catch (GenericEntityException e) {
                throw new WfException(e.getMessage(), e);
            }
        } else {
            Debug.logVerbose("[WfProcess.joinTransition] : Waiting for transitions to finish.", module);
            try {
                Map<String, Object> fields = new HashMap<String, Object>();
                fields.put("processWorkEffortId", dataObject.getString("workEffortId"));
                fields.put("toActivityId", toActivity.getString("activityId"));
                fields.put("transitionId", transition.getString("transitionId"));
                GenericValue obj = getDelegator().makeValue("WorkEffortTransBox", fields);

                getDelegator().create(obj);
            } catch (GenericEntityException e) {
                throw new WfException(e.getMessage(), e);
            }
        }
    }

    // Activates an activity object
    private void startActivity(GenericValue value) throws WfException {
        WfActivity activity = WfFactory.getWfActivity(value, workEffortId);
        GenericResultWaiter req = new GenericResultWaiter();

        if (Debug.verboseOn()) Debug.logVerbose("[WfProcess.startActivity] : Attempting to start activity (" + activity.name() + ")", module);

        // locate the dispatcher to use
        LocalDispatcher dispatcher = this.getDispatcher();

        // get the job manager
        JobManager jm = dispatcher.getJobManager();
        if (jm == null) {
            throw new WfException("No job manager found on the service dispatcher; cannot start activity");
        }

        // using the StartActivityJob class to run the activity within its own thread
        try {
            Job activityJob = new StartActivityJob(activity, req);
            jm.runJob(activityJob);
        } catch (JobManagerException e) {
            throw new WfException("JobManager error", e);
        }

        // the GenericRequester object will hold any exceptions; and report the job as failed
        if (req.status() == GenericResultWaiter.SERVICE_FAILED) {
            Throwable reqt = req.getThrowable();
            if (reqt instanceof CannotStart)
                Debug.logVerbose("[WfProcess.startActivity] : Cannot start activity. Waiting for manual start.", module);
            else if (reqt instanceof AlreadyRunning)
                throw new WfException("Activity already running", reqt);
            else
                throw new WfException("Activity error", reqt);
        }
    }

    // Determine the next activity or activities
    private List<GenericValue> getTransFrom(WfActivity fromActivity) throws WfException {
        List<GenericValue> transList = new ArrayList<GenericValue>();
       
        // get the from transitions
        List<GenericValue> fromTransitions = null;
        try {
            fromTransitions = fromActivity.getDefinitionObject().getRelated("FromWorkflowTransition");
        } catch (GenericEntityException e) {
            throw new WfException(e.getMessage(), e);
        }

        // check for a split
        String split = "WST_AND"; // default split is AND

        if (fromActivity.getDefinitionObject().get("splitTypeEnumId") != null)
            split = fromActivity.getDefinitionObject().getString("splitTypeEnumId");

        // the default value is TRUE, so if no expression is supplied we evaluate as true
        boolean transitionOk = true;

        // the otherwise condition (only used by XOR splits)
        GenericValue otherwise = null;

        // iterate through the possible transitions
        for (GenericValue transition : fromTransitions) {
            // if this transition is OTHERWISE store it for later and continue on
            if (transition.get("conditionTypeEnumId") != null && transition.getString("conditionTypeEnumId").equals("WTC_OTHERWISE")) {
                // there should be only one of these, if there is more then one we will use the last one defined
                otherwise = transition;
                continue;
            }

            // get the condition body from the condition tag
            String conditionBody = transition.getString("conditionExpr");

            // get the extended attributes for the transition
            Map<String, String> extendedAttr = StringUtil.strToMap(transition.getString("extendedAttributes"));

            // check for a conditionClassName attribute if exists use it
            if (extendedAttr != null && extendedAttr.get("conditionClassName") != null) {
                String conditionClassName = (String) extendedAttr.get("conditionClassName");
                transitionOk = this.evalConditionClass(conditionClassName, conditionBody, this.processContext(), extendedAttr);
            } else {
                // since no condition class is supplied, evaluate the expression using bsh
                if (conditionBody != null) {
                    transitionOk = this.evalBshCondition(conditionBody, this.processContext());
                }
            }

            if (transitionOk) {
                transList.add(transition);
                if (split.equals("WST_XOR"))
                    break;
            }
        }

        // we only use the otherwise transition for XOR splits
        if (split.equals("WST_XOR") && transList.size() == 0 && otherwise != null) {
            transList.add(otherwise);
            Debug.logVerbose("Used OTHERWISE Transition.", module);
        }

        if (Debug.verboseOn()) Debug.logVerbose("[WfProcess.getTransFrom] : Transitions: " + transList.size(), module);
        return transList;
    }

    // Complete this workflow
    private void finishProcess() throws WfException {
        changeState("closed.completed");
        Debug.logVerbose("[WfProcess.finishProcess] : Workflow Complete. Calling back to requester.", module);
        if (requester != null) {
            WfEventAudit audit = WfFactory.getWfEventAudit(this, null); // this will need to be updated

            try {
                requester.receiveEvent(audit);
            } catch (InvalidPerformer e) {
                throw new WfException(e.getMessage(), e);
            }
        }
    }

    // Get the active process activities
    private List<WfActivity> activeSteps() throws WfException {
        List<WfActivity> steps = new ArrayList<WfActivity>();

        List<GenericValue> workEffortList = null;
        try {
            workEffortList = getDelegator().findByAnd("WorkEffort", UtilMisc.toMap("workEffortParentId", runtimeKey()));
        } catch (GenericEntityException e) {
            throw new WfException(e.getMessage(), e);
        }
        if (workEffortList == null) {
            return steps;
        }
       
        for (GenericValue workEffort : workEffortList) {
            if (workEffort.get("currentStatusId") != null &&
                WfUtil.getOMGStatus(workEffort.getString("currentStatusId")).startsWith("open."))
                steps.add(WfFactory.getWfActivity(getDelegator(), workEffort.getString("workEffortId")));
        }
        return steps;
    }
}
TOP

Related Classes of org.ofbiz.workflow.impl.WfProcessImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.