/*
* 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.drools.core.rule;
import org.drools.core.base.DroolsQuery;
import org.drools.core.base.extractors.ArrayElementReader;
import org.drools.core.common.InternalWorkingMemory;
import org.drools.core.reteoo.LeftTuple;
import org.drools.core.util.MVELSafeHelper;
import org.kie.api.runtime.rule.Variable;
import org.mvel2.MVEL;
import org.mvel2.ParserContext;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.drools.core.rule.QueryArgument.Declr.evaluateDeclaration;
public interface QueryArgument extends Externalizable {
QueryArgument normalize(ClassLoader classLoader);
Object getValue( InternalWorkingMemory wm, LeftTuple leftTuple);
class Declr implements QueryArgument {
private Declaration declaration;
public Declr() { }
public Declr( Declaration declaration ) {
this.declaration = declaration;
}
@Override
public Object getValue( InternalWorkingMemory wm, LeftTuple leftTuple ) {
return evaluateDeclaration( wm, leftTuple, declaration );
}
static Object evaluateDeclaration( InternalWorkingMemory wm, LeftTuple leftTuple, Declaration declaration ) {
Object tupleObject = leftTuple.get( declaration ).getObject();
if ( tupleObject instanceof DroolsQuery && declaration.getExtractor() instanceof ArrayElementReader &&
( (DroolsQuery) tupleObject ).getVariables()[declaration.getExtractor().getIndex()] != null ) {
return Variable.v;
}
return declaration.getValue( wm, tupleObject );
}
@Override
public QueryArgument normalize(ClassLoader classLoader) {
return this;
}
@Override
public void writeExternal( ObjectOutput out ) throws IOException {
out.writeObject( declaration );
}
@Override
public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException {
declaration = (Declaration) in.readObject();
}
public Declaration getDeclaration() {
return declaration;
}
public Class<?> getArgumentClass() {
return declaration.getDeclarationClass();
}
}
class Expression implements QueryArgument {
private List<Declaration> declarations;
private String expression;
private ParserContext parserContext;
private transient Class<?> argumentClass;
private transient Serializable mvelExpr;
public Expression() { }
public Expression( List<Declaration> declarations, String expression, ParserContext parserContext ) {
this.declarations = declarations;
this.expression = expression;
this.parserContext = parserContext;
init();
}
private void init() {
Map<String, Class> inputs = new HashMap<String, Class>();
for (Declaration d : declarations) {
inputs.put(d.getBindingName(), d.getDeclarationClass());
}
parserContext.setInputs(inputs);
this.argumentClass = MVEL.analyze( expression, parserContext );
this.mvelExpr = MVEL.compileExpression( expression, parserContext );
}
@Override
public Object getValue( InternalWorkingMemory wm, LeftTuple leftTuple ) {
Map<String, Object> vars = new HashMap<String, Object>();
for (Declaration d : declarations) {
vars.put(d.getBindingName(), evaluateDeclaration( wm, leftTuple, d ));
}
return MVELSafeHelper.getEvaluator().executeExpression( this.mvelExpr, vars );
}
@Override
public QueryArgument normalize( ClassLoader classLoader ) {
parserContext.getParserConfiguration().setClassLoader( classLoader );
return new Expression( declarations, expression, parserContext );
}
@Override
public void writeExternal( ObjectOutput out ) throws IOException {
out.writeObject( declarations );
out.writeObject( expression );
out.writeObject( parserContext );
}
@Override
public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException {
declarations = (List<Declaration>) in.readObject();
expression = (String) in.readObject();
parserContext = (ParserContext) in.readObject();
init();
}
}
class Literal implements QueryArgument {
private Object value;
public Literal() { }
public Literal( Object value ) {
this.value = value;
}
@Override
public Object getValue( InternalWorkingMemory wm, LeftTuple leftTuple) {
return value;
}
@Override
public QueryArgument normalize(ClassLoader classLoader) {
try {
return value instanceof Class ? new Literal(classLoader.loadClass(((Class)value).getName())) : this;
} catch (ClassNotFoundException e) {
throw new RuntimeException( e );
}
}
@Override
public void writeExternal( ObjectOutput out ) throws IOException {
out.writeObject( value );
}
@Override
public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException {
value = in.readObject();
}
}
Var VAR = new Var();
class Var implements QueryArgument {
@Override
public Object getValue( InternalWorkingMemory wm, LeftTuple leftTuple) {
return Variable.v;
}
@Override
public QueryArgument normalize(ClassLoader classLoader) {
return this;
}
@Override
public void writeExternal( ObjectOutput out ) throws IOException { }
@Override
public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException { }
}
Null NULL = new Null();
class Null implements QueryArgument {
@Override
public Object getValue( InternalWorkingMemory wm, LeftTuple leftTuple) {
return null;
}
@Override
public QueryArgument normalize(ClassLoader classLoader) {
return this;
}
@Override
public void writeExternal( ObjectOutput out ) throws IOException { }
@Override
public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException { }
}
}