Search in sources :

Example 1 with ErrorDetail

use of org.mvel2.ErrorDetail in project jbpm by kiegroup.

the class RuleFlowProcessValidator method validateNodes.

private void validateNodes(Node[] nodes, List<ProcessValidationError> errors, RuleFlowProcess process) {
    String isForCompensation = "isForCompensation";
    for (int i = 0; i < nodes.length; i++) {
        final Node node = nodes[i];
        if (node instanceof StartNode) {
            final StartNode startNode = (StartNode) node;
            if (startNode.getTo() == null) {
                addErrorMessage(process, node, errors, "Start has no outgoing connection.");
            }
            if (startNode.getTimer() != null) {
                validateTimer(startNode.getTimer(), node, process, errors);
            }
        } else if (node instanceof EndNode) {
            final EndNode endNode = (EndNode) node;
            if (endNode.getFrom() == null) {
                addErrorMessage(process, node, errors, "End has no incoming connection.");
            }
            validateCompensationIntermediateOrEndEvent(endNode, process, errors);
        } else if (node instanceof RuleSetNode) {
            final RuleSetNode ruleSetNode = (RuleSetNode) node;
            if (ruleSetNode.getFrom() == null && !acceptsNoIncomingConnections(node)) {
                addErrorMessage(process, node, errors, "RuleSet has no incoming connection.");
            }
            if (ruleSetNode.getTo() == null && !acceptsNoOutgoingConnections(node)) {
                addErrorMessage(process, node, errors, "RuleSet has no outgoing connection.");
            }
            final String language = ruleSetNode.getLanguage();
            if (RuleSetNode.DRL_LANG.equals(language)) {
                final String ruleFlowGroup = ruleSetNode.getRuleFlowGroup();
                if (ruleFlowGroup == null || "".equals(ruleFlowGroup)) {
                    addErrorMessage(process, node, errors, "RuleSet (DRL) has no ruleflow-group.");
                }
            } else if (RuleSetNode.DMN_LANG.equals(language)) {
                final String namespace = ruleSetNode.getNamespace();
                if (namespace == null || "".equals(namespace)) {
                    addErrorMessage(process, node, errors, "RuleSet (DMN) has no namespace.");
                }
                final String model = ruleSetNode.getModel();
                if (model == null || "".equals(model)) {
                    addErrorMessage(process, node, errors, "RuleSet (DMN) has no model.");
                }
            } else {
                addErrorMessage(process, node, errors, "Unsupported rule language '" + language + "'");
            }
            if (ruleSetNode.getTimers() != null) {
                for (Timer timer : ruleSetNode.getTimers().keySet()) {
                    validateTimer(timer, node, process, errors);
                }
            }
        } else if (node instanceof Split) {
            final Split split = (Split) node;
            if (split.getType() == Split.TYPE_UNDEFINED) {
                addErrorMessage(process, node, errors, "Split has no type.");
            }
            if (split.getFrom() == null && !acceptsNoIncomingConnections(node)) {
                addErrorMessage(process, node, errors, "Split has no incoming connection.");
            }
            if (split.getDefaultOutgoingConnections().size() < 2) {
                addErrorMessage(process, node, errors, "Split does not have more than one outgoing connection: " + split.getOutgoingConnections().size() + ".");
            }
            if (split.getType() == Split.TYPE_XOR || split.getType() == Split.TYPE_OR) {
                for (final Iterator<Connection> it = split.getDefaultOutgoingConnections().iterator(); it.hasNext(); ) {
                    final Connection connection = it.next();
                    if (split.getConstraint(connection) == null && !split.isDefault(connection) || (!split.isDefault(connection) && (split.getConstraint(connection).getConstraint() == null || split.getConstraint(connection).getConstraint().trim().length() == 0))) {
                        addErrorMessage(process, node, errors, "Split does not have a constraint for " + connection.toString() + ".");
                    }
                }
            }
        } else if (node instanceof Join) {
            final Join join = (Join) node;
            if (join.getType() == Join.TYPE_UNDEFINED) {
                addErrorMessage(process, node, errors, "Join has no type.");
            }
            if (join.getDefaultIncomingConnections().size() < 2) {
                addErrorMessage(process, node, errors, "Join does not have more than one incoming connection: " + join.getIncomingConnections().size() + ".");
            }
            if (join.getTo() == null && !acceptsNoOutgoingConnections(node)) {
                addErrorMessage(process, node, errors, "Join has no outgoing connection.");
            }
            if (join.getType() == Join.TYPE_N_OF_M) {
                String n = join.getN();
                if (!n.startsWith("#{") || !n.endsWith("}")) {
                    try {
                        new Integer(n);
                    } catch (NumberFormatException e) {
                        addErrorMessage(process, node, errors, "Join has illegal n value: " + n);
                    }
                }
            }
        } else if (node instanceof MilestoneNode) {
            final MilestoneNode milestone = (MilestoneNode) node;
            if (milestone.getFrom() == null && !acceptsNoIncomingConnections(node)) {
                addErrorMessage(process, node, errors, "Milestone has no incoming connection.");
            }
            if (milestone.getTo() == null && !acceptsNoOutgoingConnections(node)) {
                addErrorMessage(process, node, errors, "Milestone has no outgoing connection.");
            }
            if (milestone.getConstraint() == null) {
                addErrorMessage(process, node, errors, "Milestone has no constraint.");
            }
            if (milestone.getTimers() != null) {
                for (Timer timer : milestone.getTimers().keySet()) {
                    validateTimer(timer, node, process, errors);
                }
            }
        } else if (node instanceof StateNode) {
            final StateNode stateNode = (StateNode) node;
            if (stateNode.getDefaultIncomingConnections().size() == 0 && !acceptsNoIncomingConnections(node)) {
                addErrorMessage(process, node, errors, "State has no incoming connection");
            }
        } else if (node instanceof SubProcessNode) {
            final SubProcessNode subProcess = (SubProcessNode) node;
            if (subProcess.getFrom() == null && !acceptsNoIncomingConnections(node)) {
                addErrorMessage(process, node, errors, "SubProcess has no incoming connection.");
            }
            if (subProcess.getTo() == null && !acceptsNoOutgoingConnections(node)) {
                Object compensationObj = subProcess.getMetaData(isForCompensation);
                if (compensationObj == null || !((Boolean) compensationObj)) {
                    addErrorMessage(process, node, errors, "SubProcess has no outgoing connection.");
                }
            }
            if (subProcess.getProcessId() == null && subProcess.getProcessName() == null) {
                addErrorMessage(process, node, errors, "SubProcess has no process id.");
            }
            if (subProcess.getTimers() != null) {
                for (Timer timer : subProcess.getTimers().keySet()) {
                    validateTimer(timer, node, process, errors);
                }
            }
            if (!subProcess.isIndependent() && !subProcess.isWaitForCompletion()) {
                addErrorMessage(process, node, errors, "SubProcess you can only set " + "independent to 'false' only when 'Wait for completion' is set to true.");
            }
        } else if (node instanceof ActionNode) {
            final ActionNode actionNode = (ActionNode) node;
            if (actionNode.getFrom() == null && !acceptsNoIncomingConnections(node)) {
                addErrorMessage(process, node, errors, "Action has no incoming connection.");
            }
            if (actionNode.getTo() == null && !acceptsNoOutgoingConnections(node)) {
                Object compensationObj = actionNode.getMetaData(isForCompensation);
                if (compensationObj == null || !((Boolean) compensationObj)) {
                    addErrorMessage(process, node, errors, "Action has no outgoing connection.");
                }
            }
            if (actionNode.getAction() == null) {
                addErrorMessage(process, node, errors, "Action has no action.");
            } else if (actionNode.getAction() instanceof DroolsConsequenceAction) {
                DroolsConsequenceAction droolsAction = (DroolsConsequenceAction) actionNode.getAction();
                String actionString = droolsAction.getConsequence();
                if (actionString == null) {
                    addErrorMessage(process, node, errors, "Action has empty action.");
                } else if ("mvel".equals(droolsAction.getDialect())) {
                    try {
                        ParserContext parserContext = new ParserContext();
                        // parserContext.setStrictTypeEnforcement(true);
                        ExpressionCompiler compiler = new ExpressionCompiler(actionString, parserContext);
                        compiler.setVerifying(true);
                        compiler.compile();
                        List<ErrorDetail> mvelErrors = parserContext.getErrorList();
                        if (mvelErrors != null) {
                            for (Iterator<ErrorDetail> iterator = mvelErrors.iterator(); iterator.hasNext(); ) {
                                ErrorDetail error = iterator.next();
                                addErrorMessage(process, node, errors, "Action has invalid action: " + error.getMessage() + ".");
                            }
                        }
                    } catch (Throwable t) {
                        addErrorMessage(process, node, errors, "Action has invalid action: " + t.getMessage() + ".");
                    }
                }
                // TODO: validation for "java" and "drools" scripts!
                validateCompensationIntermediateOrEndEvent(actionNode, process, errors);
            }
        } else if (node instanceof WorkItemNode) {
            final WorkItemNode workItemNode = (WorkItemNode) node;
            if (workItemNode.getFrom() == null && !acceptsNoIncomingConnections(node)) {
                addErrorMessage(process, node, errors, "Task has no incoming connection.");
            }
            if (workItemNode.getTo() == null && !acceptsNoOutgoingConnections(node)) {
                Object compensationObj = workItemNode.getMetaData(isForCompensation);
                if (compensationObj == null || !((Boolean) compensationObj)) {
                    addErrorMessage(process, node, errors, "Task has no outgoing connection.");
                }
            }
            if (workItemNode.getWork() == null) {
                addErrorMessage(process, node, errors, "Task has no work specified.");
            } else {
                Work work = workItemNode.getWork();
                if (work.getName() == null || work.getName().trim().length() == 0) {
                    addErrorMessage(process, node, errors, "Task has no task type.");
                }
            }
            if (workItemNode.getTimers() != null) {
                for (Timer timer : workItemNode.getTimers().keySet()) {
                    validateTimer(timer, node, process, errors);
                }
            }
        } else if (node instanceof ForEachNode) {
            final ForEachNode forEachNode = (ForEachNode) node;
            String variableName = forEachNode.getVariableName();
            if (variableName == null || "".equals(variableName)) {
                addErrorMessage(process, node, errors, "ForEach has no variable name");
            }
            String collectionExpression = forEachNode.getCollectionExpression();
            if (collectionExpression == null || "".equals(collectionExpression)) {
                addErrorMessage(process, node, errors, "ForEach has no collection expression");
            }
            if (forEachNode.getDefaultIncomingConnections().size() == 0 && !acceptsNoIncomingConnections(node)) {
                addErrorMessage(process, node, errors, "ForEach has no incoming connection");
            }
            if (forEachNode.getDefaultOutgoingConnections().size() == 0 && !acceptsNoOutgoingConnections(node)) {
                addErrorMessage(process, node, errors, "ForEach has no outgoing connection");
            }
            // TODO: check, if no linked connections, for start and end node(s)
            // if (forEachNode.getLinkedIncomingNode(org.drools.workflow.core.Node.CONNECTION_DEFAULT_TYPE) == null) {
            // errors.add(new ProcessValidationErrorImpl(process,
            // "ForEach node '%s' [%d] has no linked start node"));
            // }
            // if (forEachNode.getLinkedOutgoingNode(org.drools.workflow.core.Node.CONNECTION_DEFAULT_TYPE) == null) {
            // errors.add(new ProcessValidationErrorImpl(process,
            // "ForEach node '%s' [%d] has no linked end node"));
            // }
            validateNodes(forEachNode.getNodes(), errors, process);
        } else if (node instanceof DynamicNode) {
            final DynamicNode dynamicNode = (DynamicNode) node;
            if (dynamicNode.getDefaultIncomingConnections().size() == 0 && !acceptsNoIncomingConnections(dynamicNode)) {
                addErrorMessage(process, node, errors, "Dynamic has no incoming connection");
            }
            if (dynamicNode.getDefaultOutgoingConnections().size() == 0 && !acceptsNoOutgoingConnections(dynamicNode)) {
                addErrorMessage(process, node, errors, "Dynamic has no outgoing connection");
            }
            if ("".equals(dynamicNode.getCompletionExpression()) && !dynamicNode.isAutoComplete()) {
                addErrorMessage(process, node, errors, "Dynamic has no completion condition set");
            }
            validateNodes(dynamicNode.getNodes(), errors, process);
        } else if (node instanceof CompositeNode) {
            final CompositeNode compositeNode = (CompositeNode) node;
            for (Map.Entry<String, NodeAndType> inType : compositeNode.getLinkedIncomingNodes().entrySet()) {
                if (compositeNode.getIncomingConnections(inType.getKey()).size() == 0 && !acceptsNoIncomingConnections(node)) {
                    addErrorMessage(process, node, errors, "Composite has no incoming connection for type " + inType.getKey());
                }
                if (inType.getValue().getNode() == null && !acceptsNoOutgoingConnections(node)) {
                    addErrorMessage(process, node, errors, "Composite has invalid linked incoming node for type " + inType.getKey());
                }
            }
            for (Map.Entry<String, NodeAndType> outType : compositeNode.getLinkedOutgoingNodes().entrySet()) {
                if (compositeNode.getOutgoingConnections(outType.getKey()).size() == 0) {
                    addErrorMessage(process, node, errors, "Composite has no outgoing connection for type " + outType.getKey());
                }
                if (outType.getValue().getNode() == null) {
                    addErrorMessage(process, node, errors, "Composite has invalid linked outgoing node for type " + outType.getKey());
                }
            }
            if (compositeNode instanceof EventSubProcessNode) {
                if (compositeNode.getIncomingConnections().size() > 0) {
                    addErrorMessage(process, node, errors, "Event subprocess is not allowed to have any incoming connections.");
                }
                if (compositeNode.getOutgoingConnections().size() > 0) {
                    addErrorMessage(process, node, errors, "Event subprocess is not allowed to have any outgoing connections.");
                }
                Node[] eventSubProcessNodes = compositeNode.getNodes();
                int startEventCount = 0;
                for (int j = 0; j < eventSubProcessNodes.length; ++j) {
                    if (eventSubProcessNodes[j] instanceof StartNode) {
                        StartNode startNode = (StartNode) eventSubProcessNodes[j];
                        if (++startEventCount == 2) {
                            addErrorMessage(process, compositeNode, errors, "Event subprocess is not allowed to have more than one start node.");
                        }
                        if (startNode.getTriggers() == null || startNode.getTriggers().isEmpty()) {
                            addErrorMessage(process, startNode, errors, "Start in Event SubProcess '" + compositeNode.getName() + "' [" + compositeNode.getId() + "] must contain a trigger (event definition).");
                        }
                    }
                }
            } else {
                Boolean isForCompensationObject = (Boolean) compositeNode.getMetaData("isForCompensation");
                if (compositeNode.getIncomingConnections().size() == 0 && !Boolean.TRUE.equals(isForCompensationObject)) {
                    addErrorMessage(process, node, errors, "Embedded subprocess does not have incoming connection.");
                }
                if (compositeNode.getOutgoingConnections().size() == 0 && !Boolean.TRUE.equals(isForCompensationObject)) {
                    addErrorMessage(process, node, errors, "Embedded subprocess does not have outgoing connection.");
                }
            }
            if (compositeNode.getTimers() != null) {
                for (Timer timer : compositeNode.getTimers().keySet()) {
                    validateTimer(timer, node, process, errors);
                }
            }
            validateNodes(compositeNode.getNodes(), errors, process);
        } else if (node instanceof EventNode) {
            final EventNode eventNode = (EventNode) node;
            if (eventNode.getEventFilters().size() == 0) {
                addErrorMessage(process, node, errors, "Event should specify an event type");
            }
            if (eventNode.getDefaultOutgoingConnections().size() == 0) {
                addErrorMessage(process, node, errors, "Event has no outgoing connection");
            } else {
                List<EventFilter> eventFilters = eventNode.getEventFilters();
                boolean compensationHandler = false;
                for (EventFilter eventFilter : eventFilters) {
                    if (((EventTypeFilter) eventFilter).getType().startsWith("Compensation")) {
                        compensationHandler = true;
                        break;
                    }
                }
                if (compensationHandler && eventNode instanceof BoundaryEventNode) {
                    Connection connection = eventNode.getDefaultOutgoingConnections().get(0);
                    Boolean isAssociation = (Boolean) connection.getMetaData().get("association");
                    if (isAssociation == null) {
                        isAssociation = false;
                    }
                    if (!(eventNode.getDefaultOutgoingConnections().size() == 1 && connection != null && isAssociation)) {
                        addErrorMessage(process, node, errors, "Compensation Boundary Event is only allowed to have 1 association to 1 compensation activity.");
                    }
                }
            }
        } else if (node instanceof FaultNode) {
            final FaultNode faultNode = (FaultNode) node;
            if (faultNode.getFrom() == null && !acceptsNoIncomingConnections(node)) {
                addErrorMessage(process, node, errors, "Fault has no incoming connection.");
            }
            if (faultNode.getFaultName() == null) {
                addErrorMessage(process, node, errors, "Fault has no fault name.");
            }
        } else if (node instanceof TimerNode) {
            TimerNode timerNode = (TimerNode) node;
            if (timerNode.getFrom() == null && !acceptsNoIncomingConnections(node)) {
                addErrorMessage(process, node, errors, "Timer has no incoming connection.");
            }
            if (timerNode.getTo() == null && !acceptsNoOutgoingConnections(node)) {
                addErrorMessage(process, node, errors, "Timer has no outgoing connection.");
            }
            if (timerNode.getTimer() == null) {
                addErrorMessage(process, node, errors, "Timer has no timer specified.");
            } else {
                validateTimer(timerNode.getTimer(), node, process, errors);
            }
        } else if (node instanceof CatchLinkNode) {
        // catchlink validation here, there also are validations in
        // ProcessHandler regarding connection issues
        } else if (node instanceof ThrowLinkNode) {
        // throw validation here, there also are validations in
        // ProcessHandler regarding connection issues
        } else {
            errors.add(new ProcessValidationErrorImpl(process, "Unknown node type '" + node.getClass().getName() + "'"));
        }
    }
}
Also used : DroolsConsequenceAction(org.jbpm.workflow.core.impl.DroolsConsequenceAction) NodeAndType(org.jbpm.workflow.core.node.CompositeNode.NodeAndType) RuleSetNode(org.jbpm.workflow.core.node.RuleSetNode) EventSubProcessNode(org.jbpm.workflow.core.node.EventSubProcessNode) ForEachNode(org.jbpm.workflow.core.node.ForEachNode) BoundaryEventNode(org.jbpm.workflow.core.node.BoundaryEventNode) DynamicNode(org.jbpm.workflow.core.node.DynamicNode) StartNode(org.jbpm.workflow.core.node.StartNode) CompositeNode(org.jbpm.workflow.core.node.CompositeNode) StateNode(org.jbpm.workflow.core.node.StateNode) RuleSetNode(org.jbpm.workflow.core.node.RuleSetNode) SubProcessNode(org.jbpm.workflow.core.node.SubProcessNode) CatchLinkNode(org.jbpm.workflow.core.node.CatchLinkNode) ForEachJoinNode(org.jbpm.workflow.core.node.ForEachNode.ForEachJoinNode) MilestoneNode(org.jbpm.workflow.core.node.MilestoneNode) ThrowLinkNode(org.jbpm.workflow.core.node.ThrowLinkNode) EventSubProcessNode(org.jbpm.workflow.core.node.EventSubProcessNode) TimerNode(org.jbpm.workflow.core.node.TimerNode) FaultNode(org.jbpm.workflow.core.node.FaultNode) WorkItemNode(org.jbpm.workflow.core.node.WorkItemNode) ActionNode(org.jbpm.workflow.core.node.ActionNode) EndNode(org.jbpm.workflow.core.node.EndNode) EventNode(org.jbpm.workflow.core.node.EventNode) Node(org.kie.api.definition.process.Node) ForEachSplitNode(org.jbpm.workflow.core.node.ForEachNode.ForEachSplitNode) StateNode(org.jbpm.workflow.core.node.StateNode) ActionNode(org.jbpm.workflow.core.node.ActionNode) MilestoneNode(org.jbpm.workflow.core.node.MilestoneNode) ErrorDetail(org.mvel2.ErrorDetail) BoundaryEventNode(org.jbpm.workflow.core.node.BoundaryEventNode) EventNode(org.jbpm.workflow.core.node.EventNode) EventTypeFilter(org.jbpm.process.core.event.EventTypeFilter) SubProcessNode(org.jbpm.workflow.core.node.SubProcessNode) EventSubProcessNode(org.jbpm.workflow.core.node.EventSubProcessNode) Iterator(java.util.Iterator) WorkItemNode(org.jbpm.workflow.core.node.WorkItemNode) Work(org.jbpm.process.core.Work) List(java.util.List) ArrayList(java.util.ArrayList) LinkedList(java.util.LinkedList) TimerNode(org.jbpm.workflow.core.node.TimerNode) StartNode(org.jbpm.workflow.core.node.StartNode) CatchLinkNode(org.jbpm.workflow.core.node.CatchLinkNode) Connection(org.kie.api.definition.process.Connection) Join(org.jbpm.workflow.core.node.Join) BoundaryEventNode(org.jbpm.workflow.core.node.BoundaryEventNode) ThrowLinkNode(org.jbpm.workflow.core.node.ThrowLinkNode) EventFilter(org.jbpm.process.core.event.EventFilter) FaultNode(org.jbpm.workflow.core.node.FaultNode) CompositeNode(org.jbpm.workflow.core.node.CompositeNode) EndNode(org.jbpm.workflow.core.node.EndNode) Timer(org.jbpm.process.core.timer.Timer) ProcessValidationErrorImpl(org.jbpm.process.core.validation.impl.ProcessValidationErrorImpl) ExpressionCompiler(org.mvel2.compiler.ExpressionCompiler) ForEachNode(org.jbpm.workflow.core.node.ForEachNode) DynamicNode(org.jbpm.workflow.core.node.DynamicNode) Split(org.jbpm.workflow.core.node.Split) ParserContext(org.mvel2.ParserContext) Map(java.util.Map) HashMap(java.util.HashMap)

Example 2 with ErrorDetail

use of org.mvel2.ErrorDetail in project mvel by mvel.

the class PropertyVerifier method getMethod.

/**
 * Process method
 *
 * @param ctx  - the ingress type
 * @param name - the property component
 * @return known egress type.
 */
private Class getMethod(Class ctx, String name) {
    int st = cursor;
    /**
     * Check to see if this is the first element in the statement.
     */
    if (first) {
        first = false;
        methodCall = true;
        /**
         * It's the first element in the statement, therefore we check to see if there is a static import of a
         * native Java method or an MVEL function.
         */
        if (pCtx.hasImport(name)) {
            Method m = pCtx.getStaticImport(name).getMethod();
            /**
             * Replace the method parameters.
             */
            ctx = m.getDeclaringClass();
            name = m.getName();
        } else {
            Function f = pCtx.getFunction(name);
            if (f != null && f.getEgressType() != null) {
                resolvedExternally = false;
                f.checkArgumentCount(parseParameterList((((cursor = balancedCapture(expr, cursor, end, '(')) - st) > 1 ? ParseTools.subset(expr, st + 1, cursor - st - 1) : new char[0]), 0, -1).size());
                return f.getEgressType();
            } else if (pCtx.hasVarOrInput("this")) {
                if (pCtx.isStrictTypeEnforcement()) {
                    recordTypeParmsForProperty("this");
                }
                ctx = pCtx.getVarOrInputType("this");
                resolvedExternally = false;
            }
        }
    }
    /**
     * Get the arguments for the method.
     */
    String tk;
    if (cursor < end && expr[cursor] == '(' && ((cursor = balancedCapture(expr, cursor, end, '(')) - st) > 1) {
        tk = new String(expr, st + 1, cursor - st - 1);
    } else {
        tk = "";
    }
    cursor++;
    /**
     * Parse out the arguments list.
     */
    Class[] args;
    List<char[]> subtokens = parseParameterList(tk.toCharArray(), 0, -1);
    if (subtokens.size() == 0) {
        args = new Class[0];
        subtokens = Collections.emptyList();
    } else {
        // ParserContext subCtx = pCtx.createSubcontext();
        args = new Class[subtokens.size()];
        /**
         *  Subcompile all the arguments to determine their known types.
         */
        // ExpressionCompiler compiler;
        List<ErrorDetail> errors = pCtx.getErrorList().isEmpty() ? pCtx.getErrorList() : new ArrayList<ErrorDetail>(pCtx.getErrorList());
        CompileException rethrow = null;
        for (int i = 0; i < subtokens.size(); i++) {
            try {
                args[i] = MVEL.analyze(subtokens.get(i), pCtx);
                if ("null".equals(String.valueOf(subtokens.get(i)))) {
                    args[i] = NullType.class;
                }
            } catch (CompileException e) {
                rethrow = ErrorUtil.rewriteIfNeeded(e, expr, this.st);
            }
            if (errors.size() < pCtx.getErrorList().size()) {
                for (ErrorDetail detail : pCtx.getErrorList()) {
                    if (!errors.contains(detail)) {
                        detail.setExpr(expr);
                        detail.setCursor(new String(expr).substring(this.st).indexOf(new String(subtokens.get(i))) + this.st);
                        detail.setColumn(0);
                        detail.setLineNumber(0);
                        detail.calcRowAndColumn();
                    }
                }
            }
            if (rethrow != null) {
                throw rethrow;
            }
        }
    }
    /**
     * If the target object is an instance of java.lang.Class itself then do not
     * adjust the Class scope target.
     */
    Method m;
    if ((m = getBestCandidate(args, name, ctx, ctx.getMethods(), pCtx.isStrongTyping())) == null) {
        if ((m = getBestCandidate(args, name, ctx, ctx.getDeclaredMethods(), pCtx.isStrongTyping())) == null) {
            StringAppender errorBuild = new StringAppender();
            for (int i = 0; i < args.length; i++) {
                errorBuild.append(args[i] != null ? args[i].getName() : null);
                if (i < args.length - 1)
                    errorBuild.append(", ");
            }
            if (("size".equals(name) || "length".equals(name)) && args.length == 0 && ctx.isArray()) {
                return Integer.class;
            }
            if (pCtx.isStrictTypeEnforcement()) {
                throw new CompileException("unable to resolve method using strict-mode: " + ctx.getName() + "." + name + "(" + errorBuild.toString() + ")", expr, tkStart);
            }
            return Object.class;
        }
    }
    /**
     * If we're in strict mode, we look for generic type information.
     */
    if (pCtx.isStrictTypeEnforcement() && m.getGenericReturnType() != null) {
        Map<String, Class> typeArgs = new HashMap<String, Class>();
        Type[] gpt = m.getGenericParameterTypes();
        Class z;
        ParameterizedType pt;
        for (int i = 0; i < gpt.length; i++) {
            if (gpt[i] instanceof ParameterizedType) {
                pt = (ParameterizedType) gpt[i];
                if ((z = pCtx.getImport(new String(subtokens.get(i)))) != null) {
                    /**
                     * We record the value of the type parameter to our typeArgs Map.
                     */
                    if (pt.getRawType().equals(Class.class)) {
                        /**
                         * If this is an instance of Class, we deal with the special parameterization case.
                         */
                        typeArgs.put(pt.getActualTypeArguments()[0].toString(), z);
                    } else {
                        typeArgs.put(gpt[i].toString(), z);
                    }
                }
            }
        }
        if (pCtx.isStrictTypeEnforcement() && ctx.getTypeParameters().length != 0 && pCtx.getLastTypeParameters() != null && pCtx.getLastTypeParameters().length == ctx.getTypeParameters().length) {
            TypeVariable[] typeVariables = ctx.getTypeParameters();
            for (int i = 0; i < typeVariables.length; i++) {
                Type typeArg = pCtx.getLastTypeParameters()[i];
                typeArgs.put(typeVariables[i].getName(), typeArg instanceof Class ? type2Class(pCtx.getLastTypeParameters()[i]) : Object.class);
            }
        }
        /**
         * Get the return type argument
         */
        Type parametricReturnType = m.getGenericReturnType();
        String returnTypeArg = parametricReturnType.toString();
        // push return type parameters onto parser context, only if this is a parametric type
        if (parametricReturnType instanceof ParameterizedType) {
            pCtx.setLastTypeParameters(((ParameterizedType) parametricReturnType).getActualTypeArguments());
        }
        if (paramTypes != null && paramTypes.containsKey(returnTypeArg)) {
            /**
             * If the paramTypes Map contains the known type, return that type.
             */
            return type2Class(paramTypes.get(returnTypeArg));
        } else if (typeArgs.containsKey(returnTypeArg)) {
            /**
             * If the generic type was declared as part of the method, it will be in this
             * Map.
             */
            return typeArgs.get(returnTypeArg);
        }
    }
    if (!Modifier.isPublic(m.getModifiers()) && pCtx.isStrictTypeEnforcement()) {
        StringAppender errorBuild = new StringAppender();
        for (int i = 0; i < args.length; i++) {
            errorBuild.append(args[i] != null ? args[i].getName() : null);
            if (i < args.length - 1)
                errorBuild.append(", ");
        }
        String scope = Modifier.toString(m.getModifiers());
        if (scope.trim().equals(""))
            scope = "<package local>";
        addFatalError("the referenced method is not accessible: " + ctx.getName() + "." + name + "(" + errorBuild.toString() + ")" + " (scope: " + scope + "; required: public", this.tkStart);
    }
    return getReturnType(ctx, m);
}
Also used : HashMap(java.util.HashMap) Method(java.lang.reflect.Method) ErrorDetail(org.mvel2.ErrorDetail) ParameterizedType(java.lang.reflect.ParameterizedType) Function(org.mvel2.ast.Function) ParameterizedType(java.lang.reflect.ParameterizedType) Type(java.lang.reflect.Type) NullType(org.mvel2.util.NullType) TypeVariable(java.lang.reflect.TypeVariable) StringAppender(org.mvel2.util.StringAppender) CompileException(org.mvel2.CompileException)

Example 3 with ErrorDetail

use of org.mvel2.ErrorDetail in project mvel by mikebrock.

the class PropertyVerifier method getMethod.

/**
 * Process method
 *
 * @param ctx  - the ingress type
 * @param name - the property component
 * @return known egress type.
 */
private Class getMethod(Class ctx, String name) {
    int st = cursor;
    /**
     * Check to see if this is the first element in the statement.
     */
    if (first) {
        first = false;
        methodCall = true;
        /**
         * It's the first element in the statement, therefore we check to see if there is a static import of a
         * native Java method or an MVEL function.
         */
        if (pCtx.hasImport(name)) {
            Method m = pCtx.getStaticImport(name).getMethod();
            /**
             * Replace the method parameters.
             */
            ctx = m.getDeclaringClass();
            name = m.getName();
        } else if (pCtx.hasFunction(name)) {
            resolvedExternally = false;
            Function f = pCtx.getFunction(name);
            f.checkArgumentCount(parseParameterList((((cursor = balancedCapture(expr, cursor, end, '(')) - st) > 1 ? ParseTools.subset(expr, st + 1, cursor - st - 1) : new char[0]), 0, -1).size());
            return f.getEgressType();
        } else if (pCtx.hasVarOrInput("this")) {
            if (pCtx.isStrictTypeEnforcement()) {
                recordTypeParmsForProperty("this");
            }
            ctx = pCtx.getVarOrInputType("this");
            resolvedExternally = false;
        }
    }
    /**
     * Get the arguments for the method.
     */
    String tk;
    if (cursor < end && expr[cursor] == '(' && ((cursor = balancedCapture(expr, cursor, end, '(')) - st) > 1) {
        tk = new String(expr, st + 1, cursor - st - 1);
    } else {
        tk = "";
    }
    cursor++;
    /**
     * Parse out the arguments list.
     */
    Class[] args;
    List<char[]> subtokens = parseParameterList(tk.toCharArray(), 0, -1);
    if (subtokens.size() == 0) {
        args = new Class[0];
        subtokens = Collections.emptyList();
    } else {
        // ParserContext subCtx = pCtx.createSubcontext();
        args = new Class[subtokens.size()];
        /**
         *  Subcompile all the arguments to determine their known types.
         */
        // ExpressionCompiler compiler;
        List<ErrorDetail> errors = pCtx.getErrorList().isEmpty() ? pCtx.getErrorList() : new ArrayList<ErrorDetail>(pCtx.getErrorList());
        CompileException rethrow = null;
        for (int i = 0; i < subtokens.size(); i++) {
            try {
                args[i] = MVEL.analyze(subtokens.get(i), pCtx);
                if ("null".equals(String.valueOf(subtokens.get(i)))) {
                    args[i] = NullType.class;
                }
            } catch (CompileException e) {
                rethrow = ErrorUtil.rewriteIfNeeded(e, expr, this.st);
            }
            if (errors.size() < pCtx.getErrorList().size()) {
                for (ErrorDetail detail : pCtx.getErrorList()) {
                    if (!errors.contains(detail)) {
                        detail.setExpr(expr);
                        detail.setCursor(new String(expr).substring(this.st).indexOf(new String(subtokens.get(i))) + this.st);
                        detail.setColumn(0);
                        detail.setLineNumber(0);
                        detail.calcRowAndColumn();
                    }
                }
            }
            if (rethrow != null) {
                throw rethrow;
            }
        }
    }
    /**
     * If the target object is an instance of java.lang.Class itself then do not
     * adjust the Class scope target.
     */
    Method m;
    if ((m = getBestCandidate(args, name, ctx, ctx.getMethods(), pCtx.isStrongTyping())) == null) {
        if ((m = getBestCandidate(args, name, ctx, ctx.getDeclaredMethods(), pCtx.isStrongTyping())) == null) {
            StringAppender errorBuild = new StringAppender();
            for (int i = 0; i < args.length; i++) {
                errorBuild.append(args[i] != null ? args[i].getName() : null);
                if (i < args.length - 1)
                    errorBuild.append(", ");
            }
            if (("size".equals(name) || "length".equals(name)) && args.length == 0 && ctx.isArray()) {
                return Integer.class;
            }
            if (pCtx.isStrictTypeEnforcement()) {
                throw new CompileException("unable to resolve method using strict-mode: " + ctx.getName() + "." + name + "(" + errorBuild.toString() + ")", expr, tkStart);
            }
            return Object.class;
        }
    }
    /**
     * If we're in strict mode, we look for generic type information.
     */
    if (pCtx.isStrictTypeEnforcement() && m.getGenericReturnType() != null) {
        Map<String, Class> typeArgs = new HashMap<String, Class>();
        Type[] gpt = m.getGenericParameterTypes();
        Class z;
        ParameterizedType pt;
        for (int i = 0; i < gpt.length; i++) {
            if (gpt[i] instanceof ParameterizedType) {
                pt = (ParameterizedType) gpt[i];
                if ((z = pCtx.getImport(new String(subtokens.get(i)))) != null) {
                    /**
                     * We record the value of the type parameter to our typeArgs Map.
                     */
                    if (pt.getRawType().equals(Class.class)) {
                        /**
                         * If this is an instance of Class, we deal with the special parameterization case.
                         */
                        typeArgs.put(pt.getActualTypeArguments()[0].toString(), z);
                    } else {
                        typeArgs.put(gpt[i].toString(), z);
                    }
                }
            }
        }
        if (pCtx.isStrictTypeEnforcement() && ctx.getTypeParameters().length != 0 && pCtx.getLastTypeParameters() != null && pCtx.getLastTypeParameters().length == ctx.getTypeParameters().length) {
            TypeVariable[] typeVariables = ctx.getTypeParameters();
            for (int i = 0; i < typeVariables.length; i++) {
                typeArgs.put(typeVariables[i].getName(), (Class) pCtx.getLastTypeParameters()[i]);
            }
        }
        /**
         * Get the return type argument
         */
        Type parametricReturnType = m.getGenericReturnType();
        String returnTypeArg = parametricReturnType.toString();
        // push return type parameters onto parser context, only if this is a parametric type
        if (parametricReturnType instanceof ParameterizedType) {
            pCtx.setLastTypeParameters(((ParameterizedType) parametricReturnType).getActualTypeArguments());
        }
        if (paramTypes != null && paramTypes.containsKey(returnTypeArg)) {
            /**
             * If the paramTypes Map contains the known type, return that type.
             */
            return (Class) paramTypes.get(returnTypeArg);
        } else if (typeArgs.containsKey(returnTypeArg)) {
            /**
             * If the generic type was declared as part of the method, it will be in this
             * Map.
             */
            return typeArgs.get(returnTypeArg);
        }
    }
    if (!Modifier.isPublic(m.getModifiers())) {
        StringAppender errorBuild = new StringAppender();
        for (int i = 0; i < args.length; i++) {
            errorBuild.append(args[i] != null ? args[i].getName() : null);
            if (i < args.length - 1)
                errorBuild.append(", ");
        }
        String scope = Modifier.toString(m.getModifiers());
        if (scope.trim().equals(""))
            scope = "<package local>";
        addFatalError("the referenced method is not accessible: " + ctx.getName() + "." + name + "(" + errorBuild.toString() + ")" + " (scope: " + scope + "; required: public", this.tkStart);
    }
    return m.getReturnType();
}
Also used : Function(org.mvel2.ast.Function) NullType(org.mvel2.util.NullType) StringAppender(org.mvel2.util.StringAppender)

Example 4 with ErrorDetail

use of org.mvel2.ErrorDetail in project mvel by mvel.

the class ExpressionCompiler method compile.

public CompiledExpression compile() {
    try {
        this.debugSymbols = pCtx.isDebugSymbols();
        return _compile();
    } finally {
        if (pCtx.isFatalError()) {
            StringAppender err = new StringAppender();
            Iterator<ErrorDetail> iter = pCtx.getErrorList().iterator();
            ErrorDetail e;
            while (iter.hasNext()) {
                e = iter.next();
                e = ErrorUtil.rewriteIfNeeded(e, expr, cursor);
                if (e.getExpr() != expr) {
                    iter.remove();
                } else {
                    err.append("\n - ").append("(").append(e.getLineNumber()).append(",").append(e.getColumn()).append(")").append(" ").append(e.getMessage());
                }
            }
            // noinspection ThrowFromFinallyBlock
            throw new CompileException("Failed to compileShared: " + pCtx.getErrorList().size() + " compilation error(s): " + err.toString(), pCtx.getErrorList(), expr, cursor, pCtx);
        }
    }
}
Also used : ErrorDetail(org.mvel2.ErrorDetail) StringAppender(org.mvel2.util.StringAppender) CompileException(org.mvel2.CompileException)

Aggregations

ErrorDetail (org.mvel2.ErrorDetail)3 HashMap (java.util.HashMap)2 StringAppender (org.mvel2.util.StringAppender)2 Method (java.lang.reflect.Method)1 ParameterizedType (java.lang.reflect.ParameterizedType)1 Type (java.lang.reflect.Type)1 TypeVariable (java.lang.reflect.TypeVariable)1 ArrayList (java.util.ArrayList)1 Iterator (java.util.Iterator)1 LinkedList (java.util.LinkedList)1 List (java.util.List)1 Map (java.util.Map)1 Work (org.jbpm.process.core.Work)1 EventFilter (org.jbpm.process.core.event.EventFilter)1 EventTypeFilter (org.jbpm.process.core.event.EventTypeFilter)1 Timer (org.jbpm.process.core.timer.Timer)1 ProcessValidationErrorImpl (org.jbpm.process.core.validation.impl.ProcessValidationErrorImpl)1 DroolsConsequenceAction (org.jbpm.workflow.core.impl.DroolsConsequenceAction)1 ActionNode (org.jbpm.workflow.core.node.ActionNode)1 BoundaryEventNode (org.jbpm.workflow.core.node.BoundaryEventNode)1