Package org.ofbiz.workflow.impl

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

/*******************************************************************************
* 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.io.FileNotFoundException;
import java.io.IOException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.ofbiz.base.util.BshUtil;
import org.ofbiz.base.util.Debug;
import org.ofbiz.base.util.ObjectType;
import org.ofbiz.base.util.UtilGenerics;
import org.ofbiz.base.util.UtilMisc;
import org.ofbiz.base.util.UtilValidate;
import org.ofbiz.base.util.string.FlexibleStringExpander;
import org.ofbiz.entity.Delegator;
import org.ofbiz.entity.GenericEntityException;
import org.ofbiz.entity.GenericValue;
import org.ofbiz.entity.serialize.SerializeException;
import org.ofbiz.entity.serialize.XmlSerializer;
import org.ofbiz.service.DispatchContext;
import org.ofbiz.service.GenericDispatcher;
import org.ofbiz.service.LocalDispatcher;
import org.ofbiz.workflow.AlreadySuspended;
import org.ofbiz.workflow.CannotResume;
import org.ofbiz.workflow.CannotStop;
import org.ofbiz.workflow.CannotSuspend;
import org.ofbiz.workflow.EvaluationException;
import org.ofbiz.workflow.HistoryNotAvailable;
import org.ofbiz.workflow.InvalidData;
import org.ofbiz.workflow.InvalidState;
import org.ofbiz.workflow.NotRunning;
import org.ofbiz.workflow.NotSuspended;
import org.ofbiz.workflow.TransitionCondition;
import org.ofbiz.workflow.TransitionNotAllowed;
import org.ofbiz.workflow.UpdateNotAllowed;
import org.ofbiz.workflow.WfException;
import org.ofbiz.workflow.WfExecutionObject;
import org.ofbiz.workflow.WfUtil;

/**
* WfExecutionObjectImpl - Workflow Execution Object implementation
*/
public abstract class WfExecutionObjectImpl implements WfExecutionObject {

    public static final String module = WfExecutionObjectImpl.class.getName();
    public static final String dispatcherName = "WFDispatcher";

    protected String packageId = null;
    protected String packageVersion = null;
    protected String processId = null;
    protected String processVersion = null;
    protected String activityId = null;
    protected String workEffortId = null;
    protected Delegator delegator = null;
    protected List<?> history = null;

    public WfExecutionObjectImpl(GenericValue valueObject, String parentId) throws WfException {
        this.packageId = valueObject.getString("packageId");
        this.packageVersion = valueObject.getString("packageVersion");
        this.processId = valueObject.getString("processId");
        this.processVersion = valueObject.getString("processVersion");
        if (valueObject.getEntityName().equals("WorkflowActivity")) {
            this.activityId = valueObject.getString("activityId");
        } else {
            this.activityId = null;
        }
        this.delegator = valueObject.getDelegator();
        createRuntime(parentId);
    }

    public WfExecutionObjectImpl(Delegator delegator, String workEffortId) throws WfException {
        this.delegator = delegator;
        this.workEffortId = workEffortId;
        this.packageId = getRuntimeObject().getString("workflowPackageId");
        this.packageVersion = getRuntimeObject().getString("workflowPackageVersion");
        this.processId = getRuntimeObject().getString("workflowProcessId");
        this.processVersion = getRuntimeObject().getString("workflowProcessVersion");
        this.activityId = getRuntimeObject().getString("workflowActivityId");
        this.history = null;
        if (Debug.verboseOn()) Debug.logVerbose(" Package ID: " + packageId + " V: " + packageVersion, module);
        if (Debug.verboseOn()) Debug.logVerbose(" Process ID: " + processId + " V: " + processVersion, module);
        if (Debug.verboseOn()) Debug.logVerbose("Activity ID: " + activityId, module);
    }

    // creates the stored runtime workeffort data.
    private void createRuntime(String parentId) throws WfException {
        GenericValue valueObject = getDefinitionObject();
        GenericValue dataObject = null;

        workEffortId = getDelegator().getNextSeqId("WorkEffort");
        Map<String, Object> dataMap = new HashMap<String, Object>();
        String weType = activityId != null ? "ACTIVITY" : "WORK_FLOW";

        dataMap.put("workEffortId", workEffortId);
        dataMap.put("workEffortTypeId", weType);
        dataMap.put("workEffortParentId", parentId);
        dataMap.put("workflowPackageId", packageId);
        dataMap.put("workflowPackageVersion", packageVersion);
        dataMap.put("workflowProcessId", processId);
        dataMap.put("workflowProcessVersion", processVersion);
        dataMap.put("workEffortName", valueObject.getString("objectName"));
        dataMap.put("description", valueObject.getString("description"));
        dataMap.put("createdDate", new Timestamp((new Date()).getTime()));
        dataMap.put("estimatedStartDate", dataMap.get("createdDate"));
        dataMap.put("lastModifiedDate", dataMap.get("createdDate"));
        dataMap.put("priority", valueObject.getLong("objectPriority"));
        dataMap.put("currentStatusId", WfUtil.getOFBStatus("open.not_running.not_started"));
        if (activityId != null)
            dataMap.put("workflowActivityId", activityId);
        if (activityId != null && parentId != null) {
            GenericValue parentWorkEffort = getWorkEffort(parentId);
            if (parentWorkEffort != null && parentWorkEffort.get("sourceReferenceId") != null)
                dataMap.put("sourceReferenceId", parentWorkEffort.getString("sourceReferenceId"));
        }

        try {
            dataObject = getDelegator().makeValue("WorkEffort", dataMap);
            getDelegator().create(dataObject);

            String objectId = activityId != null ? activityId : processId;
            if (Debug.verboseOn()) Debug.logVerbose("Created new runtime object [" + objectId + "] (Workeffort: " + runtimeKey() + ")", module);
        } catch (GenericEntityException e) {
            throw new WfException(e.getMessage(), e);
        }
    }

    protected void parseDescriptions(Map<String, Object> parseContext) throws WfException {
        GenericValue runtime = getRuntimeObject();
        String name = runtime.getString("workEffortName");
        String desc = runtime.getString("description");
        String nameExp = FlexibleStringExpander.expandString(name, parseContext);
        String descExp = FlexibleStringExpander.expandString(desc, parseContext);

        boolean changed = false;
        if (nameExp != null && !nameExp.equals(name)) {
            changed = true;
            runtime.set("workEffortName", nameExp);
        }
        if (descExp != null && !descExp.equals(desc)) {
            changed = true;
            runtime.set("description", descExp);
        }

        if (changed) {
            try {
                runtime.store();
            } catch (GenericEntityException e) {
                throw new WfException(e.getMessage(), e);
            }
        }
    }

    /**
     * @see org.ofbiz.workflow.WfExecutionObject#name()
     */
    public String name() throws WfException {
        return getRuntimeObject().getString("workEffortName");
    }

    /**
     * @see org.ofbiz.workflow.WfExecutionObject#setName(java.lang.String)
     */
    public void setName(String newValue) throws WfException {
        GenericValue dataObject = getRuntimeObject();

        try {
            dataObject.set("workEffortName", newValue);
            dataObject.store();
        } catch (GenericEntityException e) {
            throw new WfException(e.getMessage(), e);
        }
    }

    /**
     * @see org.ofbiz.workflow.WfExecutionObject#setPriority(long)
     */
    public void setPriority(long newValue) throws WfException {
        GenericValue dataObject = getRuntimeObject();

        try {
            dataObject.set("priority", new Long(newValue));
            dataObject.store();
        } catch (GenericEntityException e) {
            throw new WfException(e.getMessage(), e);
        }
    }

    /**
     * @see org.ofbiz.workflow.WfExecutionObject#priority()
     */
    public long priority() throws WfException {
        if (getRuntimeObject().get("priority") != null)
            return getRuntimeObject().getLong("priority").longValue();
        return 0; // change to default priority value
    }

    /**
     * @see org.ofbiz.workflow.WfExecutionObject#state()
     */
    public String state() throws WfException {
        GenericValue statusObj = null;
        String stateStr = null;

        try {
            statusObj = getRuntimeObject().getRelatedOne("CurrentStatusItem");
        } catch (GenericEntityException e) {
            throw new WfException(e.getMessage(), e);
        }
        if (statusObj != null)
            stateStr = statusObj.getString("statusCode");

        if (stateStr == null)
            throw new WfException("Stored state is not a valid type.");

        if (Debug.verboseOn()) Debug.logVerbose("Current state: " + stateStr, module);
        return stateStr;
    }

    /**
     * @see org.ofbiz.workflow.WfExecutionObject#validStates()
     */
    public List<String> validStates() throws WfException {
        String statesArr[] = {"open.running", "open.not_running.not_started", "open.not_running.suspended",
                "closed.completed", "closed.terminated", "closed.aborted"};
        ArrayList<String> possibleStates = new ArrayList<String>(Arrays.asList(statesArr));
        String currentState = state();

        if (currentState.startsWith("closed"))
            return new ArrayList<String>();
        if (!currentState.startsWith("open"))
            throw new WfException("Currently in an unknown state.");
        if (currentState.equals("open.running")) {
            possibleStates.remove("open.running");
            possibleStates.remove("open.not_running.not_started");
            return possibleStates;
        }
        if (currentState.equals("open.not_running.not_started")) {
            possibleStates.remove("open.not_running.not_started");
            possibleStates.remove("open.not_running.suspended");
            possibleStates.remove("closed.completed");
            possibleStates.remove("closed.terminated");
            return possibleStates;
        }
        if (currentState.equals("open.not_running.suspended")) {
            possibleStates.remove("open.not_running.suspended");
            possibleStates.remove("open.not_running.not_started");
            possibleStates.remove("closed.complete");
            possibleStates.remove("closed.terminated");
            return possibleStates;
        }
        return new ArrayList<String>();
    }

    /**
     * @see org.ofbiz.workflow.WfExecutionObject#howManyHistory()
     */
    public int howManyHistory() throws WfException, HistoryNotAvailable {
        if (history.size() < 1)
            throw new HistoryNotAvailable();
        return history.size();
    }

    /**
     * @see org.ofbiz.workflow.WfExecutionObject#abort()
     */
    public void abort() throws WfException, CannotStop, NotRunning {
        Debug.logInfo("Aborting current state : " + state(), module);
        String stateStr = "closed.aborted";

        if (!state().startsWith("open")) {
            throw new NotRunning();
        }

        if (!validStates().contains(stateStr)) {
            throw new CannotStop();
        }

        changeState(stateStr);
    }

    /**
     * @see org.ofbiz.workflow.WfExecutionObject#whileOpenType()
     */
    public List<String> whileOpenType() throws WfException {
        String[] list = {"running", "not_running"};

        return Arrays.asList(list);
    }

    /**
     * @see org.ofbiz.workflow.WfExecutionObject#whyNotRunningType()
     */
    public List<String> whyNotRunningType() throws WfException {
        String[] list = {"not_started", "suspended"};

        return Arrays.asList(list);
    }

    /**
     * @see org.ofbiz.workflow.WfExecutionObject#runtimeKey()
     */
    public String runtimeKey() throws WfException {
        return getRuntimeObject().getString("workEffortId");
    }

    /**
     * @see org.ofbiz.workflow.WfExecutionObject#key()
     */
    public String key() throws WfException {
        if (activityId != null)
            return activityId;
        else
            return processId;
    }

    /**
     * @see org.ofbiz.workflow.WfExecutionObject#isMemberOfHistory(org.ofbiz.workflow.WfExecutionObject)
     */
    public boolean isMemberOfHistory(WfExecutionObject member) throws WfException {
        return false;
    }

    /**
     * @see org.ofbiz.workflow.WfExecutionObject#setProcessContext(java.util.Map)
     */
    public void setProcessContext(Map<String, Object> newValue) throws WfException, InvalidData, UpdateNotAllowed {
        setSerializedData(newValue);
    }

    /**
     * @see org.ofbiz.workflow.WfExecutionObject#setProcessContext(java.lang.String)
     */
    public void setProcessContext(String contextKey) throws WfException, InvalidData, UpdateNotAllowed {
        GenericValue dataObject = getRuntimeObject();

        try {
            dataObject.set("runtimeDataId", contextKey);
            dataObject.store();
        } catch (GenericEntityException e) {
            throw new WfException(e.getMessage(), e);
        }
    }

    /**
     * @see org.ofbiz.workflow.WfExecutionObject#contextKey()
     */
    public String contextKey() throws WfException {
        if (getRuntimeObject().get("runtimeDataId") == null)
            return null;
        else
            return getRuntimeObject().getString("runtimeDataId");
    }

    /**
     * @see org.ofbiz.workflow.WfExecutionObject#processContext()
     */
    public Map<String, Object> processContext() throws WfException {
        return getContext();
    }

    /**
     * @see org.ofbiz.workflow.WfExecutionObject#workflowStateType()
     */
    public List<String> workflowStateType() throws WfException {
        String[] list = {"open", "closed"};
        return Arrays.asList(list);
    }

    /**
     * @see org.ofbiz.workflow.WfExecutionObject#terminate()
     */
    public void terminate() throws WfException, CannotStop, NotRunning {
        String stateStr = "closed.terminated";

        if (!state().equals("open.running"))
            throw new NotRunning();
        if (!validStates().contains(stateStr))
            throw new CannotStop();
        changeState(stateStr);
    }

    /**
     * @see org.ofbiz.workflow.WfExecutionObject#setDescription(java.lang.String)
     */
    public void setDescription(String newValue) throws WfException {
        GenericValue valueObject = getDefinitionObject();

        try {
            valueObject.set("description", newValue);
            valueObject.store();
        } catch (GenericEntityException e) {
            throw new WfException(e.getMessage(), e);
        }
    }

    /**
     * @see org.ofbiz.workflow.WfExecutionObject#description()
     */
    public String description() throws WfException {
        return getDefinitionObject().getString("description");
    }

    /**
     * @see org.ofbiz.workflow.WfExecutionObject#lastStateTime()
     */
    public Timestamp lastStateTime() throws WfException {
        GenericValue dataObject = getRuntimeObject();

        if (dataObject == null || dataObject.get("lastStatusUpdate") == null)
            throw new WfException("No runtime object or status has never been set.");
        return dataObject.getTimestamp("lastStatusUpdate");
    }

    /**
     * @see org.ofbiz.workflow.WfExecutionObject#getSequenceHistory(int)
     */
    public List<?> getSequenceHistory(int maxNumber) throws WfException,
            HistoryNotAvailable {
        return history;
    }

    /**
     * @see org.ofbiz.workflow.WfExecutionObject#getIteratorHistory(java.lang.String, java.util.Map)
     */
    public Iterator<?> getIteratorHistory(String query, Map<String, Object> namesInQuery) throws WfException, HistoryNotAvailable {
        return history.iterator();
    }

    /**
     * @see org.ofbiz.workflow.WfExecutionObject#resume()
     */
    public void resume() throws WfException, CannotResume, NotRunning, NotSuspended {
        if (!state().equals("open.not_running.suspended")) {
            if (state().equals("open.not_running.not_started")) {
                throw new NotRunning();
            } else if (state().startsWith("closed")) {
                throw new CannotResume();
            } else {
                throw new NotSuspended();
            }
        } else {
            changeState("open.running");
        }
    }

    /**
     * @see org.ofbiz.workflow.WfExecutionObject#howClosedType()
     */
    public List<String> howClosedType() throws WfException {
        String[] list = {"completed", "terminated", "aborted"};

        return Arrays.asList(list);
    }

    /**
     * @see org.ofbiz.workflow.WfExecutionObject#changeState(java.lang.String)
     */
    public void changeState(String newState) throws WfException, InvalidState, TransitionNotAllowed {
        // Test is transaction is allowed???
        GenericValue dataObject = getRuntimeObject();

        if (validStates().contains(newState)) {
            try {
                long now = (new Date()).getTime();

                dataObject.set("currentStatusId", WfUtil.getOFBStatus(newState));
                dataObject.set("lastStatusUpdate", new Timestamp(now));
                dataObject.store();
            } catch (GenericEntityException e) {
                throw new WfException(e.getMessage(), e);
            }
        } else {
            throw new InvalidState();
        }
    }

    /**
     * @see org.ofbiz.workflow.WfExecutionObject#suspend()
     */
    public void suspend() throws WfException, CannotSuspend, NotRunning, AlreadySuspended {
        changeState("open.not_running.suspended");
    }

    /**
     * @see org.ofbiz.workflow.WfExecutionObject#getDelegator()
     */
    public Delegator getDelegator() throws WfException {
        return delegator;
    }

    /**
     * @see org.ofbiz.workflow.WfExecutionObject#getDefinitionObject()
     */
    public GenericValue getDefinitionObject() throws WfException {
        String entityName = activityId != null ? "WorkflowActivity" : "WorkflowProcess";
        GenericValue value = null;
        Map<String, Object> fields = UtilMisc.toMap("packageId", (Object) packageId, "packageVersion", packageVersion, "processId", processId,
                "processVersion", processVersion);

        if (activityId != null)
            fields.put("activityId", activityId);
        try {
            value = getDelegator().findByPrimaryKey(entityName, fields);
        } catch (GenericEntityException e) {
            throw new WfException(e.getMessage(), e);
        }
        return value;
    }

    public GenericValue getRuntimeObject() throws WfException {
        GenericValue value = null;

        try {
            value = getDelegator().findByPrimaryKey("WorkEffort",
                        UtilMisc.toMap("workEffortId", workEffortId));
        } catch (GenericEntityException e) {
            throw new WfException(e.getMessage(), e);
        }
        return value;
    }

    /**
     * Getter for this type of execution object.
     * @return String
     */
    public abstract String executionObjectType();

    /**
     * Updates the runtime data entity
     * @param value The value to serialize and set
     * @throws WfException
     */
    protected void setSerializedData(Map<String, Object> value) throws WfException, InvalidData {
        GenericValue runtimeData = null;
        GenericValue dataObject = getRuntimeObject();

        try {
            if (dataObject.get("runtimeDataId") == null) {
                String seqId = getDelegator().getNextSeqId("RuntimeData");

                runtimeData = getDelegator().makeValue("RuntimeData",
                            UtilMisc.toMap("runtimeDataId", seqId));
                getDelegator().create(runtimeData);
                dataObject.set("runtimeDataId", seqId);
                dataObject.store();
            } else {
                runtimeData = dataObject.getRelatedOne("RuntimeData");
            }
            // String serialized = XmlSerializer.serialize(value);
            // System.out.println(serialized);

            runtimeData.set("runtimeInfo", XmlSerializer.serialize(value));
            runtimeData.store();
        } catch (GenericEntityException e) {
            throw new WfException(e.getMessage(), e);
        } catch (SerializeException e) {
            throw new InvalidData(e.getMessage(), e);
        } catch (FileNotFoundException e) {
            throw new InvalidData(e.getMessage(), e);
        } catch (IOException e) {
            throw new InvalidData(e.getMessage(), e);
        }
    }

    /**
     * Get an instance of the local dispatcher
     * @return LocalDispatcher instance for use with this workflow
     * @throws WfException
     */
    protected LocalDispatcher getDispatcher() throws WfException {
        return GenericDispatcher.getLocalDispatcher(dispatcherName, getDelegator());
    }

    private Map<String, Object> getContext() throws WfException {
        GenericValue dataObject = getRuntimeObject();
        String contextXML = null;
        Map<String, Object> context = null;

        if (dataObject.get("runtimeDataId") == null)
            return context;
        try {
            GenericValue runtimeData = dataObject.getRelatedOne("RuntimeData");

            contextXML = runtimeData.getString("runtimeInfo");
        } catch (GenericEntityException e) {
            throw new WfException(e.getMessage(), e);
        }
        // De-serialize the context
        if (contextXML != null) {
            try {
                context = UtilGenerics.checkMap(XmlSerializer.deserialize(contextXML, getDelegator()));
            } catch (SerializeException e) {
                throw new WfException(e.getMessage(), e);
            } catch (IOException e) {
                throw new WfException(e.getMessage(), e);
            } catch (Exception e) {
                throw new WfException(e.getMessage(), e);
            }
        }
        return context;
    }

    private GenericValue getWorkEffort(String workEffortId) throws WfException {
        GenericValue we = null;
        try {
            we = getDelegator().findByPrimaryKey("WorkEffort", UtilMisc.toMap("workEffortId", workEffortId));
        } catch (GenericEntityException e) {
            throw new WfException("Problem getting WorkEffort entity (" + workEffortId + ")", e);
        }
        return we;
    }

    /**
     * Evaluate a condition expression using an implementation of TransitionCondition
     * @param className The class name of the TransitionCondition implementation
     * @param expression The expression to evaluate
     * @return The result of the evaluation (True/False)
     * @throws WfException
     */
    protected boolean evalConditionClass(String className, String expression, Map<String, Object> context, Map<String, String> attrs) throws WfException {
        // attempt to load and instance of the class
        Object conditionObject = null;
        try {
            conditionObject = ObjectType.getInstance(className);
        } catch (ClassNotFoundException e) {
            Debug.logError(e, "Cannot load class " + className, module);
            return false;
        } catch (InstantiationException e) {
            Debug.logError(e, "Cannot get instance of class " + className, module);
            return false;
        } catch (IllegalAccessException e) {
            Debug.logError(e, "Cannot access class " + className, module);
            return false;
        }

        // make sure we implement the TransitionCondition interface
        if (!ObjectType.instanceOf(conditionObject, "org.ofbiz.workflow.TransitionCondition")) {
            Debug.logError("Class " + className + " is not an instance of TransitionCondition", module);
            return false;
        }

        // cast to the interface
        TransitionCondition cond = (TransitionCondition) conditionObject;

        // trim up the expression if it isn't empty
        if (expression != null)
            expression = expression.trim();

        // get a DispatchContext object to pass over to the eval
        DispatchContext dctx = this.getDispatcher().getDispatchContext();

        // evaluate the condition
        Boolean evaluation = null;
        try {
            evaluation = cond.evaluateCondition(context, attrs, expression, dctx);
        } catch (EvaluationException e) {
            throw new WfException("Problems evaluating condition", e);
        }

        return evaluation.booleanValue();
    }

    /**
     * Evaluate a condition expression using BeanShell
     * @param expression The expression to evaluate
     * @param context The context to use in evaluation
     * @return The result of the evaluation (True/False)
     * @throws WfException
     */
    protected boolean evalBshCondition(String expression, Map<String, Object> context) throws WfException {
        if (UtilValidate.isEmpty(expression)) {
            Debug.logVerbose("Null or empty expression, returning true.", module);
            return true;
        }

        Object o = null;
        try {
            o = BshUtil.eval(expression.trim(), context);
        } catch (bsh.EvalError e) {
            throw new WfException("Bsh evaluation error.", e);
        }

        if (o == null)
            return false;
        else if (o instanceof Number)
            return (((Number) o).doubleValue() == 0) ? false : true;
        else
            return (!o.toString().equalsIgnoreCase("true")) ? false : true;
    }
}

TOP

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

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.