/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates.
*
* Licensed 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.kie.dmn.core.ast;
import org.kie.dmn.api.core.DMNContext;
import org.kie.dmn.api.core.DMNMessage;
import org.kie.dmn.api.core.DMNResult;
import org.kie.dmn.api.core.DMNType;
import org.kie.dmn.core.api.DMNExpressionEvaluator;
import org.kie.dmn.core.api.EvaluatorResult;
import org.kie.dmn.core.api.EvaluatorResult.ResultType;
import org.kie.dmn.api.core.event.DMNRuntimeEventManager;
import org.kie.dmn.core.impl.DMNContextImpl;
import org.kie.dmn.core.impl.DMNResultImpl;
import org.kie.dmn.core.util.Msg;
import org.kie.dmn.core.util.MsgUtil;
import org.kie.dmn.model.v1_1.Context;
import org.kie.dmn.model.v1_1.ContextEntry;
import org.kie.dmn.model.v1_1.FunctionDefinition;
import org.kie.dmn.model.v1_1.LiteralExpression;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
public class DMNContextEvaluator
implements DMNExpressionEvaluator {
private static final Logger logger = LoggerFactory.getLogger( DMNContextEvaluator.class );
public static final String RESULT_ENTRY = "__RESULT__";
private final String name;
private final Context contextDef;
private List<ContextEntryDef> entries = new ArrayList<>();
public DMNContextEvaluator(String name, Context contextDef) {
this.name = name;
this.contextDef = contextDef;
}
public void addEntry(String name, DMNType type, DMNExpressionEvaluator evaluator, ContextEntry ce) {
this.entries.add( new ContextEntryDef( name, type, evaluator, ce ) );
}
public List<ContextEntryDef> getEntries() {
return this.entries;
}
@Override
public EvaluatorResult evaluate(DMNRuntimeEventManager eventManager, DMNResult dmnr) {
DMNResultImpl result = (DMNResultImpl) dmnr;
// when this evaluator is executed, it should either return a Map of key/value pairs
// where keys are the name of the entries and values are the result of the evaluations
// OR if a default result is implemented, it should return the result instead
Map<String, Object> results = new HashMap<>();
DMNContext previousContext = result.getContext();
DMNContextImpl dmnContext = (DMNContextImpl) previousContext.clone();
result.setContext( dmnContext );
try {
for ( ContextEntryDef ed : entries ) {
try {
EvaluatorResult er = ed.getEvaluator().evaluate( eventManager, result );
if ( er.getResultType() == ResultType.SUCCESS ) {
Object value = er.getResult();
if( ! ed.getType().isCollection() && value instanceof Collection &&
((Collection)value).size()==1 ) {
// spec defines that "a=[a]", i.e., singleton collections should be treated as the single element
// and vice-versa
value = ((Collection)value).toArray()[0];
}
if ( ! (ed.getContextEntry().getExpression() instanceof FunctionDefinition) ) {
// checking directly the result type...
if ( ed.getType() != null && !ed.getType().isAssignableValue(value) ) {
MsgUtil.reportMessage( logger,
DMNMessage.Severity.ERROR,
contextDef,
result,
null,
null,
Msg.ERROR_EVAL_NODE_RESULT_WRONG_TYPE,
ed.getName(),
ed.getType(),
value);
return new EvaluatorResultImpl( results, ResultType.FAILURE );
}
} else {
// TODO ...will need calculation/inference of function return type.
}
results.put( ed.getName(), value );
dmnContext.set( ed.getName(), value );
} else {
MsgUtil.reportMessage( logger,
DMNMessage.Severity.ERROR,
contextDef,
result,
null,
null,
Msg.ERR_EVAL_CTX_ENTRY_ON_CTX,
ed.getName(),
name );
return new EvaluatorResultImpl( results, ResultType.FAILURE );
}
} catch ( Exception e ) {
logger.error( "Error invoking expression for node '" + name + "'.", e );
return new EvaluatorResultImpl( results, ResultType.FAILURE );
}
}
} finally {
result.setContext( previousContext );
}
if( results.containsKey( RESULT_ENTRY ) ) {
return new EvaluatorResultImpl( results.get( RESULT_ENTRY ), ResultType.SUCCESS );
} else {
return new EvaluatorResultImpl( results, ResultType.SUCCESS );
}
}
public static class ContextEntryDef {
private String name;
private DMNType type;
private DMNExpressionEvaluator evaluator;
private ContextEntry ce;
public ContextEntryDef(String name, DMNType type, DMNExpressionEvaluator evaluator, ContextEntry ce) {
this.name = name;
this.type = type;
this.evaluator = evaluator;
this.ce = ce;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public DMNType getType() {
return type;
}
public void setType(DMNType type) {
this.type = type;
}
public DMNExpressionEvaluator getEvaluator() {
return evaluator;
}
public void setEvaluator(DMNExpressionEvaluator evaluator) {
this.evaluator = evaluator;
}
public ContextEntry getContextEntry() {
return ce;
}
public void setContextEntry(ContextEntry ce) {
this.ce = ce;
}
}
}