org.tinygroup.flow.impl.FlowExecutorImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.tinygroup.flow.impl.FlowExecutorImpl.java

Source

/**
 *  Copyright (c) 1997-2013, www.tinygroup.org (luo_guo@icloud.com).
 *
 *  Licensed under the GPL, Version 3.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.gnu.org/licenses/gpl.html
 *
 *  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.tinygroup.flow.impl;

import org.apache.commons.beanutils.PropertyUtils;
import org.tinygroup.commons.match.SimpleTypeMatcher;
import org.tinygroup.commons.tools.StringUtil;
import org.tinygroup.commons.tools.ValueUtil;
import org.tinygroup.context.Context;
import org.tinygroup.context.impl.ContextImpl;
import org.tinygroup.context2object.util.Context2ObjectUtil;
import org.tinygroup.event.Parameter;
import org.tinygroup.flow.ComponentInterface;
import org.tinygroup.flow.FlowExecutor;
import org.tinygroup.flow.config.*;
import org.tinygroup.flow.containers.ComponentContainers;
import org.tinygroup.flow.exception.FlowRuntimeException;
import org.tinygroup.flow.util.FlowElUtil;
import org.tinygroup.format.Formater;
import org.tinygroup.format.impl.ContextFormater;
import org.tinygroup.format.impl.FormaterImpl;
import org.tinygroup.i18n.I18nMessageFactory;
import org.tinygroup.i18n.I18nMessages;
import org.tinygroup.logger.LogLevel;
import org.tinygroup.logger.Logger;
import org.tinygroup.logger.LoggerFactory;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * ?
 * 
 * @author luoguo
 */
public class FlowExecutorImpl implements FlowExecutor {
    private static final Logger LOGGER = LoggerFactory.getLogger(FlowExecutorImpl.class);
    private static Map<String, Class<?>> exceptionMap = new HashMap<String, Class<?>>();
    private static transient Formater formater = new FormaterImpl();
    private Map<String, Flow> flowIdMap = new HashMap<String, Flow>();// ?nameid??id?
    private I18nMessages i18nMessages = I18nMessageFactory.getI18nMessages();
    private boolean change;
    // 
    private ComponentContainers containers = new ComponentContainers();

    static {
        formater.addFormatProvider("", new ContextFormater());
        formater.addFormatProvider(Parameter.INPUT, new ContextFormater());
        formater.addFormatProvider(Parameter.OUTPUT, new ContextFormater());
        formater.addFormatProvider(Parameter.BOTH, new ContextFormater());
    }

    public Map<String, Flow> getFlowIdMap() {
        return flowIdMap;
    }

    public void execute(String flowId, Context context) {
        execute(flowId, null, context);
    }

    public void execute(String flowId, String nodeId, Context context) {
        LOGGER.logMessage(LogLevel.INFO, "?[flowId:{0},nodeId:{1}]", flowId, nodeId);
        if (!getFlowIdMap().containsKey(flowId)) {
            LOGGER.log(LogLevel.ERROR, "flow.flowNotExist", flowId);
            throw new FlowRuntimeException("flow.flowNotExist", flowId);
        }
        Flow flow = getFlowIdMap().get(flowId);
        Node node = getNode(flow, nodeId);
        if (node != null) {
            logContext(context);
            checkInputParameter(flow, context);
            execute(flow, node, context);
            checkOutputParameter(flow, context);
            logContext(context);
        }
        LOGGER.logMessage(LogLevel.INFO, "?[flowId:{0},nodeId:{1}]", flowId, nodeId);
    }

    /**
     * nodeIdBegin begin?,? 1?0 2?0
     * nodeIdend ?null ,??
     * 
     * @param flow
     * @param nodeId
     * @return
     */
    private Node getNode(Flow flow, String nodeId) {
        if (DEFAULT_END_NODE.equals(nodeId)) { // end
            LOGGER.logMessage(LogLevel.INFO, "?[flowId:{0},nodeId:{1}]?,",
                    flow.getId(), DEFAULT_END_NODE);
            return null;
        }
        if (nodeId == null) { // begin
            nodeId = DEFAULT_BEGIN_NODE;
        }
        if (DEFAULT_BEGIN_NODE.equals(nodeId) && flow.getNodes().size() == 0) {
            LOGGER.logMessage(LogLevel.INFO, "?,?[flowId:{0},nodeId:{1}]",
                    flow.getId(), DEFAULT_BEGIN_NODE);
            return null;
        }
        Node node = flow.getNodeMap().get(nodeId);
        // begin?0
        if (node == null && DEFAULT_BEGIN_NODE.equals(nodeId)) {
            node = flow.getNodes().get(0);
        } else if (node == null) {// ????begin
            LOGGER.log(LogLevel.ERROR, "flow.flowNodeNotExist", flow.getId(), nodeId);
            throw new FlowRuntimeException(i18nMessages.getMessage("flow.flowNodeNotExist", flow.getId(), nodeId));
        }
        return node;
    }

    private void logContext(Context context) {
        if (LOGGER.isEnabled(LogLevel.DEBUG)) {
            LOGGER.logMessage(LogLevel.DEBUG, "");
            logItemMap(context.getItemMap());
            logSubContext(context.getSubContextMap());
            LOGGER.logMessage(LogLevel.DEBUG, "?");
        }
    }

    private void logSubContext(Map<String, Context> subContextMap) {
        LOGGER.logMessage(LogLevel.DEBUG, "?[{0}]");
        if (subContextMap != null) {
            for (String key : subContextMap.keySet()) {
                logContext(subContextMap.get(key));
            }
        }
        LOGGER.logMessage(LogLevel.DEBUG, "?[{0}]?");
    }

    private void logItemMap(Map<String, Object> itemMap) {
        for (String key : itemMap.keySet()) {
            LOGGER.logMessage(LogLevel.DEBUG, "key: {0}, value: {1}", key, itemMap.get(key));
        }
    }

    private static Class<?> getExceptionType(String name) {
        Class<?> exceptionType = exceptionMap.get(name);
        if (exceptionType == null) {
            try {
                exceptionType = Class.forName(name);// TODO:Loader?
                exceptionMap.put(name, exceptionType);
            } catch (ClassNotFoundException e) {
                throw new FlowRuntimeException(e);
            }
        }
        return exceptionType;
    }

    /**
     * ?
     * 
     * @param flow
     * @param context
     * @return
     */
    private Context getNewContext(Flow flow, Context context) {
        Context flowContext = null;
        if (context == null) {
            return null;
        }
        flowContext = context.getSubContextMap().get(flow.getId());
        if (flowContext == null) {
            return getNewContext(flow, context.getParent());
        }
        return flowContext;
    }

    /**
     * 
     * 
     * @param flow
     *            ??
     * @param node
     *            ?end??
     * @param context
     */
    private void execute(Flow flow, Node node, Context context) {

        String nodeId = node.getId(); // ?id
        Context flowContext = context;
        try {
            LOGGER.logMessage(LogLevel.INFO, ":{}", nodeId);
            if (flow.isPrivateContext()) { // ?context?
                flowContext = getNewContext(flow, context);
                if (flowContext == null) {
                    flowContext = new ContextImpl();
                    context.putSubContext(flow.getId(), flowContext);
                }
            }
            Component component = node.getComponent();
            if (component != null) {
                ComponentInterface componentInstance = getComponentInstance(component.getName());
                setProperties(node, componentInstance, flowContext);
                if (!nodeId.equals(DEFAULT_END_NODE)) { // ??
                    componentInstance.execute(flowContext);
                }
                LOGGER.logMessage(LogLevel.INFO, ":{}", nodeId);
            } else {
                LOGGER.logMessage(LogLevel.INFO, ":{}?", nodeId);
            }

        } catch (RuntimeException exception) {
            /**
             * ??
             */
            LOGGER.errorMessage("?[flow:{},node:{}]?", exception, flow.getId(), node.getId());
            if (exceptionNodeProcess(flow, node, context, flowContext, exception)) {
                return;
            }
            // ????
            Node exceptionNode = flow.getNodeMap().get(EXCEPTION_DEAL_NODE);
            if (exceptionNode != null
                    && exceptionNodeProcess(flow, exceptionNode, context, flowContext, exception)) {
                return;
                // executeNextNode(flow, newContext, exceptionNode.getId());
            }
            // ????
            Flow exceptionProcessFlow = this.getFlow(EXCEPTION_DEAL_FLOW);
            if (exceptionProcessFlow != null) {
                exceptionNode = exceptionProcessFlow.getNodeMap().get(EXCEPTION_DEAL_NODE);
                if (exceptionNode != null && exceptionNodeProcess(exceptionProcessFlow, exceptionNode, context,
                        flowContext, exception)) {
                    return;
                }
            }
            throw exception;
        }
        if (nodeId != null && !nodeId.equals(DEFAULT_END_NODE)) {
            // ??????
            String nextNodeId = node.getNextNodeId(context);
            if (nextNodeId == null) {
                int index = flow.getNodes().indexOf(node);
                if (index != flow.getNodes().size() - 1) {
                    nextNodeId = flow.getNodes().get(index + 1).getId();
                } else {
                    nextNodeId = DEFAULT_END_NODE;
                }
            }
            LOGGER.logMessage(LogLevel.INFO, ":{}", nextNodeId);
            executeNextNode(flow, flowContext, nextNodeId);
        }
    }

    private void checkInputParameter(Flow flow, Context context) {
        StringBuffer buf = new StringBuffer();
        if (flow.getInputParameters() != null) {
            for (Parameter parameter : flow.getInputParameters()) {
                if (parameter.isRequired()) {// 
                    // =============20130619begin================
                    // Object value = context.get(parameter.getName());
                    // if (value == null) {//
                    // ClassNameObjectGenerator?
                    // value = getObjectByGenerator(parameter, context);
                    // if (value != null) {// ???
                    // context.put(parameter.getName(), value);
                    // continue;
                    // }
                    // }
                    Object value = Context2ObjectUtil.getObject(parameter, context,
                            this.getClass().getClassLoader());
                    if (value != null) {// ???
                        context.put(parameter.getName(), value);
                        continue;
                    }
                    // =============20130619end================
                    if (value == null) {
                        buf.append("?<");
                        buf.append(parameter.getName());
                        buf.append(">?");
                    }
                }
            }
            if (buf.length() > 0) {
                // buf.insert(0, "?<" + flow.getId() + ">???");
                // throw new FlowRuntimeException(buf.toString());
                throw new FlowRuntimeException("flow.inParamNotExist", flow.getId(), buf.toString());
            }

        }
    }

    // private Object getObjectByGenerator(Parameter parameter, Context context)
    // {
    // String collectionType = parameter.getCollectionType();
    // if (generator == null) {
    // generator = SpringUtil.getBean(
    // GeneratorFileProcessor.CLASSNAME_OBJECT_GENERATOR_BEAN);
    // }
    // if (collectionType != null && !"".equals(collectionType)) {
    // return generator.getObjectCollection(parameter.getName(),
    // collectionType, parameter.getType(), context);
    // } else if (parameter.isArray()) {
    // return generator.getObjectArray(parameter.getName(),
    // parameter.getType(), context);
    // }
    //
    // return generator.getObject(parameter.getName(),parameter.getName(),
    // parameter.getType(),
    // context);
    // }

    private void checkOutputParameter(Flow flow, Context context) {
        StringBuffer buf = new StringBuffer();
        if (flow.getOutputParameters() != null) {
            for (Parameter parameter : flow.getOutputParameters()) {
                if (parameter.isRequired()) {// 
                    Object value = context.get(parameter.getName());
                    if (value == null) {
                        buf.append("?<");
                        buf.append(parameter.getName());
                        buf.append(">?");
                    }
                }
            }
            if (buf.length() > 0) {
                // buf.insert(0, "?<" + flow.getId() + ">???");
                // throw new FlowRuntimeException(buf.toString());
                throw new FlowRuntimeException("flow.outParamNotExist", flow.getId(), buf.toString());
            }
        }
    }

    private boolean exceptionNodeProcess(Flow flow, Node node, Context context, Context newContext,
            Exception exception) {
        List<String> nextExceptionList = node.getNextExceptionList();
        // 20130524???
        for (int i = 0; i < nextExceptionList.size(); i++) {
            String exceptionName = nextExceptionList.get(i);
            if (dealException(exception, context, newContext, node, flow, exceptionName)) {
                return true;
            }
            Throwable t = exception.getCause();
            while (t != null) {
                if (dealException(t, context, newContext, node, flow, exceptionName)) {
                    return true;
                }
                t = t.getCause();
            }

        }
        return false;
    }

    private boolean dealException(Throwable exception, Context context, Context newContext, Node node, Flow flow,
            String exceptionName) {
        if (getExceptionType(exceptionName).isInstance(exception)) {// ?
            String nextNode = node.getNextExceptionNodeMap().get(exceptionName);
            context.put(EXCEPTION_DEAL_FLOW, flow);
            context.put(EXCEPTION_DEAL_NODE_KEY, node);
            context.put(EXCEPTION_KEY, exception);
            executeNextNode(flow, newContext, nextNode);
            LOGGER.errorMessage("??:flow:{},node:{}", exception, flow.getId(), nextNode);
            return true;
        }
        return false;
    }

    private void executeNextNode(Flow flow, Context context, String nextNodeId) {
        String nextExecuteNodeId = nextNodeId;
        int index = nextNodeId.indexOf(':');
        if (index > 0) { // newflowId:newnodeId
            String[] str = nextNodeId.split(":");
            if (str.length > 1) {
                nextExecuteNodeId = str[1];
            } else {
                nextExecuteNodeId = DEFAULT_BEGIN_NODE;
            }
            // ??
            execute(str[0], nextExecuteNodeId, context);
        } else if (!DEFAULT_END_NODE.equals(nextNodeId)) {
            Node nextNode = flow.getNodeMap().get(nextNodeId);
            execute(flow, nextNode, context);
        }
    }

    /**
     * ??
     * 
     * @param node
     * @param componentInstance
     */
    private void setProperties(Node node, ComponentInterface componentInstance, Context context) {
        Map<String, FlowProperty> properties = node.getComponent().getPropertyMap();
        if (properties != null) {
            for (String name : properties.keySet()) {
                FlowProperty property = properties.get(name);
                String value = property.getValue();
                Object object = null;
                // el?el??
                if (FlowProperty.EL_TYPE.equals(property.getType())) {
                    object = FlowElUtil.execute(value, context, this.getClass().getClassLoader());
                } else {// ???
                    object = getObject(property.getType(), value, context);
                }

                try {
                    PropertyUtils.setProperty(componentInstance, name, object);
                } catch (Exception e) {
                    throw new FlowRuntimeException(e);
                }
            }
        }
    }

    private Object getObject(String type, String value, Context context) {
        String str = value;
        if (str instanceof String) {
            str = formater.format(context, str);
        }

        // ??,null
        Object o = null;
        if (str != null) {
            str = str.trim();
            // type?
            if (StringUtil.isEmpty(type)) {
                o = SimpleTypeMatcher.matchType(str);
            } else {
                // type??type??????
                o = ValueUtil.getValue(str, type);
            }

        }
        return o;
    }

    // protected Object getObjectByName(String name, Context context) {
    // Object object = getObject(name, context);
    // if (object == null) {
    // int index = name.indexOf('.');
    // if (index == -1) {
    // object = context.get(name);
    // } else {
    // String k = name.substring(0, index);
    // String p = name.substring(index + 1);
    // object = context.get(k);
    // if (object != null) {
    // try {
    // object = PropertyUtils.getProperty(object, p);
    // } catch (Exception e) {
    // throw new FlowRuntimeException(e);
    // }
    // }
    // }
    // }
    // return object;
    // }

    public void assemble() {
        for (Flow flow : flowIdMap.values()) {
            flow.assemble();
        }
    }

    public void addFlow(Flow flow) {
        if (flow.getId() != null && flowIdMap.get(flow.getId()) != null) {
            LOGGER.logMessage(LogLevel.ERROR, "flow:[id:{0}]??", flow.getId());
        }
        if (flow.getName() != null && flowIdMap.get(flow.getName()) != null) {
            LOGGER.logMessage(LogLevel.ERROR, "flow:[name:{0}]??", flow.getName());
        }
        if (flow.getId() != null) {
            LOGGER.logMessage(LogLevel.INFO, "flow:[id:{0}]", flow.getId());
            flowIdMap.put(flow.getId(), flow);
        }
        if (flow.getName() != null) {
            LOGGER.logMessage(LogLevel.INFO, "flow:[Name:{0}]", flow.getName());
            flowIdMap.put(flow.getName(), flow);
        }
        flow.setFlowExecutor(this);
        setChange(true);
    }

    public void removeFlow(Flow flow) {
        LOGGER.logMessage(LogLevel.INFO, "flow:[id:{0}]", flow.getId());
        flowIdMap.remove(flow.getId());
        LOGGER.logMessage(LogLevel.INFO, "flow:[name:{0}]", flow.getName());
        flowIdMap.remove(flow.getName());
        setChange(true);
    }

    public void removeFlow(String flowId) {
        Flow flow = getFlow(flowId);
        removeFlow(flow);
    }

    public Flow getFlow(String flowId) {

        return flowIdMap.get(flowId);
    }

    public void addComponents(ComponentDefines components) {
        containers.addComponents(components);
    }

    public void removeComponents(ComponentDefines components) {
        containers.removeComponents(components);
    }

    /**
     * ???
     * 
     * @param componentName
     *            ???
     * @return
     */
    public ComponentInterface getComponentInstance(String componentName) {
        ComponentInterface componentInstance = null;
        if (!StringUtil.isBlank(componentName)) {
            componentInstance = containers.getComponentInstance(componentName);
            return componentInstance;
        }
        throw new FlowRuntimeException("flow.componentNotExist", componentName);
        // throw new FlowRuntimeException("??:" + componentName + "?");
    }

    public Context getInputContext(Flow flow, Context context) {
        return getContext(flow.getInputParameters(), context);
    }

    private Context getContext(List<Parameter> parameters, Context context) {
        Context result = new ContextImpl();
        if (parameters != null) {
            for (Parameter parameter : parameters) {
                result.put(parameter.getName(), context.get(parameter.getName()));
            }
        }
        return result;
    }

    public Context getOutputContext(Flow flow, Context context) {
        return getContext(flow.getOutputParameters(), context);
    }

    public void addComponent(ComponentDefine component) {
        containers.addComponent(component);
    }

    public void removeComponent(ComponentDefine component) {
        containers.removeComponent(component);
    }

    public ComponentDefine getComponentDefine(String componentName) {
        return containers.getComponentDefine(componentName);
    }

    public boolean isChange() {
        return change;
    }

    public void setChange(boolean change) {
        this.change = change;
    }

    public List<ComponentDefine> getComponentDefines() {
        return containers.getComponentDefines();
    }

}