📄 rulebuilder.java
字号:
package org.drools.semantics.java;
/*
* Copyright 2005 JBoss Inc
*
* 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.
*/
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.antlr.stringtemplate.StringTemplate;
import org.antlr.stringtemplate.StringTemplateGroup;
import org.antlr.stringtemplate.language.AngleBracketTemplateLexer;
import org.drools.RuntimeDroolsException;
import org.drools.base.ClassFieldExtractor;
import org.drools.base.ClassFieldExtractorCache;
import org.drools.base.ClassObjectType;
import org.drools.base.EvaluatorFactory;
import org.drools.base.FieldFactory;
import org.drools.base.FieldImpl;
import org.drools.compiler.RuleError;
import org.drools.lang.descr.AndDescr;
import org.drools.lang.descr.AttributeDescr;
import org.drools.lang.descr.BoundVariableDescr;
import org.drools.lang.descr.ColumnDescr;
import org.drools.lang.descr.ConditionalElementDescr;
import org.drools.lang.descr.EvalDescr;
import org.drools.lang.descr.ExistsDescr;
import org.drools.lang.descr.FieldBindingDescr;
import org.drools.lang.descr.LiteralDescr;
import org.drools.lang.descr.NotDescr;
import org.drools.lang.descr.OrDescr;
import org.drools.lang.descr.PatternDescr;
import org.drools.lang.descr.PredicateDescr;
import org.drools.lang.descr.QueryDescr;
import org.drools.lang.descr.ReturnValueDescr;
import org.drools.lang.descr.RuleDescr;
import org.drools.rule.And;
import org.drools.rule.BoundVariableConstraint;
import org.drools.rule.Column;
import org.drools.rule.Declaration;
import org.drools.rule.EvalCondition;
import org.drools.rule.Exists;
import org.drools.rule.GroupElement;
import org.drools.rule.LiteralConstraint;
import org.drools.rule.Not;
import org.drools.rule.Or;
import org.drools.rule.Package;
import org.drools.rule.PredicateConstraint;
import org.drools.rule.Query;
import org.drools.rule.ReturnValueConstraint;
import org.drools.rule.Rule;
import org.drools.spi.Evaluator;
import org.drools.spi.FieldExtractor;
import org.drools.spi.FieldValue;
import org.drools.spi.TypeResolver;
/**
* This builds the rule structure from an AST.
* Generates semantic code where necessary if semantics are used.
* This is an internal API.
*/
public class RuleBuilder {
private Package pkg;
private Rule rule;
private RuleDescr ruleDescr;
public String ruleClass;
public List methods;
public Map invokers;
private Map invokerLookups;
private Map descrLookups;
private Map declarations;
private int counter;
private ColumnCounter columnCounter;
private int columnOffset;
private List errors;
private final TypeResolver typeResolver;
private Map notDeclarations;
private static final StringTemplateGroup ruleGroup = new StringTemplateGroup( new InputStreamReader( RuleBuilder.class.getResourceAsStream( "javaRule.stg" ) ),
AngleBracketTemplateLexer.class );
private static final StringTemplateGroup invokerGroup = new StringTemplateGroup( new InputStreamReader( RuleBuilder.class.getResourceAsStream( "javaInvokers.stg" ) ),
AngleBracketTemplateLexer.class );
private static final KnowledgeHelperFixer knowledgeHelperFixer = new KnowledgeHelperFixer();
private static final FunctionFixer functionFixer = new FunctionFixer();
// @todo move to an interface so it can work as a decorator
private final JavaExprAnalyzer analyzer = new JavaExprAnalyzer();
private ClassFieldExtractorCache classFieldExtractorCache;
public RuleBuilder(TypeResolver resolver, ClassFieldExtractorCache cache) {
this.classFieldExtractorCache = cache;
this.typeResolver = resolver;
this.errors = new ArrayList();
}
public Map getInvokers() {
return this.invokers;
}
public Map getDescrLookups() {
return this.descrLookups;
}
public String getRuleClass() {
return this.ruleClass;
}
public Map getInvokerLookups() {
return this.invokerLookups;
}
public List getErrors() {
return this.errors;
}
public Rule getRule() {
if ( !this.errors.isEmpty() ) {
this.rule.setSemanticallyValid( false );
}
return this.rule;
}
public Package getPackage() {
return this.pkg;
}
public synchronized Rule build(final Package pkg,
final RuleDescr ruleDescr) {
this.pkg = pkg;
this.methods = new ArrayList();
this.invokers = new HashMap();
this.invokerLookups = new HashMap();
this.declarations = new HashMap();
this.descrLookups = new HashMap();
this.columnCounter = new ColumnCounter();
this.ruleDescr = ruleDescr;
if ( ruleDescr instanceof QueryDescr ) {
this.rule = new Query( ruleDescr.getName() );
} else {
this.rule = new Rule( ruleDescr.getName() );
}
// Assign attributes
setAttributes( this.rule,
ruleDescr.getAttributes() );
// Build the left hand side
// generate invoker, methods
build( ruleDescr );
return this.rule;
}
private void setAttributes(final Rule rule,
final List attributes) {
for ( final Iterator it = attributes.iterator(); it.hasNext(); ) {
final AttributeDescr attributeDescr = (AttributeDescr) it.next();
final String name = attributeDescr.getName();
if ( name.equals( "salience" ) ) {
rule.setSalience( Integer.parseInt( attributeDescr.getValue() ) );
} else if ( name.equals( "no-loop" ) ) {
if ( attributeDescr.getValue() == null ) {
rule.setNoLoop( true );
} else {
rule.setNoLoop( Boolean.valueOf( attributeDescr.getValue() ).booleanValue() );
}
} else if ( name.equals( "auto-focus" ) ) {
if ( attributeDescr.getValue() == null ) {
rule.setAutoFocus( true );
} else {
rule.setAutoFocus( Boolean.valueOf( attributeDescr.getValue() ).booleanValue() );
}
} else if ( name.equals( "agenda-group" ) ) {
rule.setAgendaGroup( attributeDescr.getValue() );
} else if ( name.equals( "activation-group" ) ) {
rule.setXorGroup( attributeDescr.getValue() );
} else if ( name.equals( "duration" ) ) {
rule.setDuration( Long.parseLong( attributeDescr.getValue() ) );
rule.setAgendaGroup( "" );
} else if ( name.equals( "language" ) ) {
//@todo: we don't currently support multiple languages
}
}
}
private void build(final RuleDescr ruleDescr) {
for ( final Iterator it = ruleDescr.getLhs().getDescrs().iterator(); it.hasNext(); ) {
final Object object = it.next();
if ( object instanceof ConditionalElementDescr ) {
if ( object instanceof AndDescr ) {
final And and = new And();
this.columnCounter.setParent( and );
build( this.rule,
(ConditionalElementDescr) object,
and,
false, // do not decrement offset
false ); // do not decrement first offset
this.rule.addPattern( and );
} else if ( object instanceof OrDescr ) {
final Or or = new Or();
this.columnCounter.setParent( or );
build( this.rule,
(ConditionalElementDescr) object,
or,
true, // when OR is used, offset MUST be decremented
false ); // do not decrement first offset
this.rule.addPattern( or );
} else if ( object instanceof NotDescr ) {
// We cannot have declarations created inside a not visible outside it, so track no declarations so they can be removed
this.notDeclarations = new HashMap();
final Not not = new Not();
this.columnCounter.setParent( not );
build( this.rule,
(ConditionalElementDescr) object,
not,
true, // when NOT is used, offset MUST be decremented
true ); // when NOT is used, offset MUST be decremented for first column
this.rule.addPattern( not );
// remove declarations bound inside not node
for ( final Iterator notIt = this.notDeclarations.keySet().iterator(); notIt.hasNext(); ) {
this.declarations.remove( notIt.next() );
}
this.notDeclarations = null;
} else if ( object instanceof ExistsDescr ) {
// We cannot have declarations created inside a not visible outside it, so track no declarations so they can be removed
this.notDeclarations = new HashMap();
final Exists exists = new Exists();
this.columnCounter.setParent( exists );
build( this.rule,
(ConditionalElementDescr) object,
exists,
true, // when EXIST is used, offset MUST be decremented
true ); // when EXIST is used, offset MUST be decremented for first column
// remove declarations bound inside not node
for ( final Iterator notIt = this.notDeclarations.keySet().iterator(); notIt.hasNext(); ) {
this.declarations.remove( notIt.next() );
}
this.notDeclarations = null;
this.rule.addPattern( exists );
} else if ( object instanceof EvalDescr ) {
final EvalCondition eval = build( (EvalDescr) object );
if ( eval != null ) {
this.rule.addPattern( eval );
}
}
} else if ( object instanceof ColumnDescr ) {
final Column column = build( (ColumnDescr) object );
if ( column != null ) {
this.rule.addPattern( column );
}
}
}
// Build the consequence and generate it's invoker/methods
// generate the main rule from the previously generated methods.
if ( !(ruleDescr instanceof QueryDescr) ) {
// do not build the consequence if we have a query
buildConsequence( ruleDescr );
}
buildRule( ruleDescr );
}
private void build(final Rule rule,
final ConditionalElementDescr descr,
final GroupElement ce,
final boolean decrementOffset,
boolean decrementFirst) {
for ( final Iterator it = descr.getDescrs().iterator(); it.hasNext(); ) {
final Object object = it.next();
if ( object instanceof ConditionalElementDescr ) {
if ( object instanceof AndDescr ) {
final And and = new And();
this.columnCounter.setParent( and );
build( rule,
(ConditionalElementDescr) object,
and,
false, // do not decrement offset
false ); // do not decrement first offset
ce.addChild( and );
} else if ( object instanceof OrDescr ) {
final Or or = new Or();
this.columnCounter.setParent( or );
build( rule,
(ConditionalElementDescr) object,
or,
true, // when OR is used, offset MUST be decremented
false ); // do not decrement first offset
ce.addChild( or );
} else if ( object instanceof NotDescr ) {
final Not not = new Not();
this.columnCounter.setParent( not );
build( rule,
(ConditionalElementDescr) object,
not,
true, // when NOT is used, offset MUST be decremented
true ); // when NOT is used, offset MUST be decremented for first column
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -