Search in sources :

Example 1 with FEELEventBase

use of org.kie.dmn.feel.runtime.events.FEELEventBase in project drools by kiegroup.

the class CustomFEELFunction method invoke.

public FEELFnResult<Object> invoke(EvaluationContext ctx, Object[] params) {
    if (params.length != parameters.size()) {
        return FEELFnResult.ofError(new InvalidInputEvent(Severity.ERROR, "Illegal invocation of function", getName(), getName() + "( " + Arrays.asList(params) + " )", getSignature()));
    }
    FEELEvent capturedException = null;
    try {
        ctx.enterFrame();
        for (int i = 0; i < parameters.size(); i++) {
            ctx.setValue(parameters.get(i), params[i]);
        }
        Object result = this.body.evaluate(ctx);
        return FEELFnResult.ofResult(result);
    } catch (Exception e) {
        capturedException = new FEELEventBase(Severity.ERROR, "Error invoking function", new RuntimeException("Error invoking function " + getSignature() + ".", e));
    } finally {
        ctx.exitFrame();
    }
    return FEELFnResult.ofError(capturedException);
}
Also used : FEELEventBase(org.kie.dmn.feel.runtime.events.FEELEventBase) InvalidInputEvent(org.kie.dmn.feel.runtime.events.InvalidInputEvent) FEELEvent(org.kie.dmn.api.feel.runtime.events.FEELEvent)

Example 2 with FEELEventBase

use of org.kie.dmn.feel.runtime.events.FEELEventBase in project drools by kiegroup.

the class DecisionTableImpl method evaluate.

/**
 * Evaluates this decision table returning the result
 * @param ctx
 * @param params these are the required information items, not to confuse with the columns of the
 *               decision table that are expressions derived from these parameters
 * @return
 */
public FEELFnResult<Object> evaluate(EvaluationContext ctx, Object[] params) {
    if (decisionRules.isEmpty()) {
        return FEELFnResult.ofError(new FEELEventBase(Severity.WARN, "Decision table is empty", null));
    }
    Object[] actualInputs = resolveActualInputs(ctx, feel);
    Either<FEELEvent, Object> actualInputMatch = actualInputsMatchInputValues(ctx, actualInputs);
    if (actualInputMatch.isLeft()) {
        return actualInputMatch.cata(e -> FEELFnResult.ofError(e), e -> FEELFnResult.ofError(null));
    }
    List<DTDecisionRule> matches = findMatches(ctx, actualInputs);
    if (!matches.isEmpty()) {
        List<Object> results = evaluateResults(ctx, feel, actualInputs, matches);
        Map<Integer, String> msgs = checkResults(ctx, matches, results);
        if (msgs.isEmpty()) {
            Object result = hitPolicy.getDti().dti(ctx, this, matches, results);
            return FEELFnResult.ofResult(result);
        } else {
            List<Integer> offending = msgs.keySet().stream().collect(Collectors.toList());
            return FEELFnResult.ofError(new HitPolicyViolationEvent(Severity.ERROR, "Errors found evaluating decision table '" + getName() + "': \n" + (msgs.values().stream().collect(Collectors.joining("\n"))), name, offending));
        }
    } else {
        // check if there is a default value set for the outputs
        if (hasDefaultValues) {
            Object result = defaultToOutput(ctx, feel);
            return FEELFnResult.ofResult(result);
        } else {
            if (hitPolicy.getDefaultValue() != null) {
                return FEELFnResult.ofResult(hitPolicy.getDefaultValue());
            }
            return FEELFnResult.ofError(new HitPolicyViolationEvent(Severity.WARN, "No rule matched for decision table '" + name + "' and no default values were defined. Setting result to null.", name, Collections.EMPTY_LIST));
        }
    }
}
Also used : FEELEventBase(org.kie.dmn.feel.runtime.events.FEELEventBase) FEELEvent(org.kie.dmn.api.feel.runtime.events.FEELEvent) HitPolicyViolationEvent(org.kie.dmn.feel.runtime.events.HitPolicyViolationEvent)

Example 3 with FEELEventBase

use of org.kie.dmn.feel.runtime.events.FEELEventBase in project drools by kiegroup.

the class InvokeFunction method invoke.

@Deprecated
public FEELFnResult<Object> invoke(@ParameterName("ctx") EvaluationContext ctx, @ParameterName("namespace") String namespace, @ParameterName("model name") String modelName, @ParameterName("decision name") String decisionName, @ParameterName("parameters") Map<String, Object> parameters) {
    DMNRuntime dmnRuntime = ctx.getDMNRuntime();
    if (namespace == null) {
        return FEELFnResult.ofError(new InvalidParametersEvent(FEELEvent.Severity.ERROR, "namespace", "cannot be null"));
    }
    if (modelName == null) {
        return FEELFnResult.ofError(new InvalidParametersEvent(FEELEvent.Severity.ERROR, "model name", "cannot be null"));
    }
    if (decisionName == null) {
        return FEELFnResult.ofError(new InvalidParametersEvent(FEELEvent.Severity.ERROR, "decision name", "cannot be null"));
    }
    if (parameters == null) {
        return FEELFnResult.ofError(new InvalidParametersEvent(FEELEvent.Severity.ERROR, "parameters", "cannot be null"));
    }
    FEELEvent capturedException = null;
    try {
        ctx.enterFrame();
        DMNModel dmnModel = dmnRuntime.getModel(namespace, modelName);
        if (dmnModel == null) {
            return FEELFnResult.ofError(new FEELEventBase(FEELEvent.Severity.ERROR, "Cannot find model '" + modelName + "' in namespace " + namespace, null));
        }
        if (dmnModel.getDecisionByName(decisionName) == null) {
            return FEELFnResult.ofError(new FEELEventBase(FEELEvent.Severity.ERROR, "Cannot find decision '" + decisionName + "' in the model", null));
        }
        DMNContext dmnContext = dmnRuntime.newContext();
        dmnContext.getAll().putAll(parameters);
        DMNResult requiredDecisionResult = dmnRuntime.evaluateByName(dmnModel, dmnContext, decisionName);
        if (requiredDecisionResult.hasErrors()) {
            return FEELFnResult.ofError(new FEELEventBase(FEELEvent.Severity.ERROR, "Errors occurred while invoking the external decision: " + requiredDecisionResult.getMessages(), null));
        }
        return FEELFnResult.ofResult(requiredDecisionResult.getContext().get(decisionName));
    } catch (Exception e) {
        capturedException = new FEELEventBase(FEELEvent.Severity.ERROR, "Error invoking function", new RuntimeException("Error invoking function " + getName() + ".", e));
    } finally {
        ctx.exitFrame();
    }
    return FEELFnResult.ofError(capturedException);
}
Also used : DMNResult(org.kie.dmn.api.core.DMNResult) FEELEventBase(org.kie.dmn.feel.runtime.events.FEELEventBase) DMNContext(org.kie.dmn.api.core.DMNContext) InvalidParametersEvent(org.kie.dmn.feel.runtime.events.InvalidParametersEvent) FEELEvent(org.kie.dmn.api.feel.runtime.events.FEELEvent) DMNRuntime(org.kie.dmn.api.core.DMNRuntime) DMNModel(org.kie.dmn.api.core.DMNModel)

Example 4 with FEELEventBase

use of org.kie.dmn.feel.runtime.events.FEELEventBase in project drools by kiegroup.

the class BaseFEELFunction method invokeReflectively.

@Override
@GwtIncompatible
public Object invokeReflectively(EvaluationContext ctx, Object[] params) {
    // use reflection to call the appropriate invoke method
    try {
        boolean isNamedParams = params.length > 0 && params[0] instanceof NamedParameter;
        if (!isCustomFunction()) {
            List<String> available = null;
            if (isNamedParams) {
                available = Stream.of(params).map(p -> ((NamedParameter) p).getName()).collect(Collectors.toList());
            }
            CandidateMethod cm = getCandidateMethod(ctx, params, isNamedParams, available);
            if (cm != null) {
                Object result = cm.apply.invoke(this, cm.actualParams);
                if (result instanceof Either) {
                    @SuppressWarnings("unchecked") Either<FEELEvent, Object> either = (Either<FEELEvent, Object>) result;
                    Object eitherResult = either.cata((left) -> {
                        ctx.notifyEvt(() -> {
                            if (left instanceof InvalidParametersEvent) {
                                InvalidParametersEvent invalidParametersEvent = (InvalidParametersEvent) left;
                                invalidParametersEvent.setNodeName(getName());
                                invalidParametersEvent.setActualParameters(Stream.of(cm.apply.getParameters()).map(p -> p.getAnnotation(ParameterName.class).value()).collect(Collectors.toList()), Arrays.asList(cm.actualParams));
                            }
                            return left;
                        });
                        return null;
                    }, Function.identity());
                    return eitherResult;
                }
                return result;
            } else {
                // CandidateMethod cm could be null also if reflection failed on Platforms not supporting getClass().getDeclaredMethods()
                String ps = getClass().toString();
                logger.error("Unable to find function '" + getName() + "( " + ps.substring(1, ps.length() - 1) + " )'");
                ctx.notifyEvt(() -> {
                    return new FEELEventBase(Severity.ERROR, "Unable to find function '" + getName() + "( " + ps.substring(1, ps.length() - 1) + " )'", null);
                });
            }
        } else {
            if (isNamedParams) {
                params = rearrangeParameters(params, this.getParameters().get(0).stream().map(Param::getName).collect(Collectors.toList()));
            }
            Object result = invoke(ctx, params);
            if (result instanceof Either) {
                @SuppressWarnings("unchecked") Either<FEELEvent, Object> either = (Either<FEELEvent, Object>) result;
                final Object[] usedParams = params;
                Object eitherResult = either.cata((left) -> {
                    ctx.notifyEvt(() -> {
                        if (left instanceof InvalidParametersEvent) {
                            InvalidParametersEvent invalidParametersEvent = (InvalidParametersEvent) left;
                            invalidParametersEvent.setNodeName(getName());
                            invalidParametersEvent.setActualParameters(IntStream.of(0, usedParams.length).mapToObj(i -> "arg" + i).collect(Collectors.toList()), Arrays.asList(usedParams));
                        }
                        return left;
                    });
                    return null;
                }, Function.identity());
                return normalizeResult(eitherResult);
            }
            return normalizeResult(result);
        }
    } catch (Exception e) {
        logger.error("Error trying to call function " + getName() + ".", e);
        ctx.notifyEvt(() -> {
            return new FEELEventBase(Severity.ERROR, "Error trying to call function " + getName() + ".", e);
        });
    }
    return null;
}
Also used : NamedParameter(org.kie.dmn.feel.lang.impl.NamedParameter) InvalidParametersEvent(org.kie.dmn.feel.runtime.events.InvalidParametersEvent) FEELEventBase(org.kie.dmn.feel.runtime.events.FEELEventBase) Either(org.kie.dmn.feel.util.Either) FEELEvent(org.kie.dmn.api.feel.runtime.events.FEELEvent) GwtIncompatible(org.kie.dmn.model.api.GwtIncompatible)

Example 5 with FEELEventBase

use of org.kie.dmn.feel.runtime.events.FEELEventBase in project drools by kiegroup.

the class AbstractCustomFEELFunction method invoke.

public FEELFnResult<Object> invoke(EvaluationContext ctx, Object[] params) {
    if (params.length != parameters.size()) {
        return FEELFnResult.ofError(new InvalidInputEvent(Severity.ERROR, "Illegal invocation of function", getName(), getName() + "( " + Arrays.asList(params) + " )", getSignature()));
    }
    FEELEvent capturedException = null;
    try {
        ctx.enterFrame();
        for (int i = 0; i < parameters.size(); i++) {
            final String paramName = parameters.get(i).name;
            if (parameters.get(i).type.isAssignableValue(params[i])) {
                ctx.setValue(paramName, params[i]);
            } else {
                ctx.setValue(paramName, null);
                ctx.notifyEvt(() -> {
                    InvalidParametersEvent evt = new InvalidParametersEvent(Severity.WARN, paramName, "not conformant");
                    evt.setNodeName(getName());
                    evt.setActualParameters(parameters.stream().map(FEELFunction.Param::getName).collect(Collectors.toList()), Arrays.asList(params));
                    return evt;
                });
            }
        }
        Object result = internalInvoke(ctx);
        return FEELFnResult.ofResult(result);
    } catch (Exception e) {
        capturedException = new FEELEventBase(Severity.ERROR, "Error invoking function", new RuntimeException("Error invoking function " + getSignature() + ".", e));
    } finally {
        ctx.exitFrame();
    }
    return FEELFnResult.ofError(capturedException);
}
Also used : FEELEventBase(org.kie.dmn.feel.runtime.events.FEELEventBase) InvalidInputEvent(org.kie.dmn.feel.runtime.events.InvalidInputEvent) InvalidParametersEvent(org.kie.dmn.feel.runtime.events.InvalidParametersEvent) FEELEvent(org.kie.dmn.api.feel.runtime.events.FEELEvent)

Aggregations

FEELEvent (org.kie.dmn.api.feel.runtime.events.FEELEvent)7 FEELEventBase (org.kie.dmn.feel.runtime.events.FEELEventBase)7 InvalidParametersEvent (org.kie.dmn.feel.runtime.events.InvalidParametersEvent)3 FEEL (org.kie.dmn.feel.FEEL)2 InvalidInputEvent (org.kie.dmn.feel.runtime.events.InvalidInputEvent)2 GwtIncompatible (org.kie.dmn.model.api.GwtIncompatible)2 ArrayList (java.util.ArrayList)1 Collections (java.util.Collections)1 List (java.util.List)1 UUID (java.util.UUID)1 AtomicReference (java.util.concurrent.atomic.AtomicReference)1 Collectors (java.util.stream.Collectors)1 IntStream (java.util.stream.IntStream)1 Test (org.junit.Test)1 DMNContext (org.kie.dmn.api.core.DMNContext)1 DMNModel (org.kie.dmn.api.core.DMNModel)1 DMNResult (org.kie.dmn.api.core.DMNResult)1 DMNRuntime (org.kie.dmn.api.core.DMNRuntime)1 FEELEventListener (org.kie.dmn.api.feel.runtime.events.FEELEventListener)1 CompiledExpression (org.kie.dmn.feel.lang.CompiledExpression)1