/**
* Copyright 2010 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.
*/
package org.drools.spi;
import java.util.HashMap;
import java.util.Map;
import java.util.Stack;
import org.drools.base.ClassObjectType;
import org.drools.rule.Declaration;
import org.drools.rule.GroupElement;
import org.drools.rule.Package;
import org.drools.rule.Pattern;
import org.drools.rule.Rule;
import org.drools.rule.RuleConditionElement;
import org.drools.spi.InternalReadAccessor;
/**
* A class capable of resolving a declaration in the current build context
*
* @author etirelli
*/
public class DeclarationScopeResolver {
private static final Stack<RuleConditionElement> EMPTY_STACK = new Stack<RuleConditionElement>();
private Map<String, Class< ? >>[] maps;
private Stack<RuleConditionElement> buildStack;
private Package pkg;
public DeclarationScopeResolver(final Map<String, Class< ? >>[] maps) {
this( maps,
EMPTY_STACK );
}
public DeclarationScopeResolver(final Map<String, Class< ? >>[] maps,
final Stack<RuleConditionElement> buildStack) {
this.maps = maps;
if ( buildStack == null ) {
this.buildStack = EMPTY_STACK;
} else {
this.buildStack = buildStack;
}
}
public void setPackage(Package pkg) {
this.pkg = pkg;
}
private Declaration getExtendedDeclaration(Rule rule,
String identifier) {
if ( rule.getLhs().getInnerDeclarations().containsKey( identifier ) ) {
return (Declaration) rule.getLhs().getInnerDeclarations().get( identifier );
} else if ( null != rule.getParent() ) {
return getExtendedDeclaration( rule.getParent(),
identifier );
}
return null;
}
private HashMap<String, Declaration> getAllExtendedDeclaration(Rule rule,
HashMap<String, Declaration> dec) {
dec.putAll( ((RuleConditionElement) rule.getLhs()).getInnerDeclarations() );
if ( null != rule.getParent() ) {
return getAllExtendedDeclaration( rule.getParent(),
dec );
}
return dec;
}
public Declaration getDeclaration(final Rule rule,
final String identifier) {
// it may be a local bound variable
for ( int i = this.buildStack.size() - 1; i >= 0; i-- ) {
final Declaration declaration = (Declaration) ((RuleConditionElement) this.buildStack.get( i )).getInnerDeclarations().get( identifier );
if ( declaration != null ) {
return declaration;
}
}
// look at parent rules
if ( rule != null && rule.getParent() != null ) {
// recursive algorithm for each parent
// -> lhs.getInnerDeclarations()
Declaration parentDeclaration = getExtendedDeclaration( rule.getParent(),
identifier );
if ( null != parentDeclaration ) {
return parentDeclaration;
}
}
// it may be a global or something
for ( int i = 0, length = this.maps.length; i < length; i++ ) {
if ( this.maps[i].containsKey( (identifier) ) ) {
if ( pkg != null ) {
Class<?> cls = (Class<?>) this.maps[i].get( identifier );
ClassObjectType classObjectType = new ClassObjectType( cls );
Declaration declaration = null;
final Pattern dummy = new Pattern( 0,
classObjectType );
GlobalExtractor globalExtractor = new GlobalExtractor( identifier,
classObjectType );
declaration = new Declaration( identifier,
globalExtractor,
dummy );
// make sure dummy and globalExtractor are wired up to correct ClassObjectType
// and set as targets for rewiring
pkg.getClassFieldAccessorStore().getClassObjectType( classObjectType,
dummy );
pkg.getClassFieldAccessorStore().getClassObjectType( classObjectType,
globalExtractor );
return declaration;
} else {
throw new UnsupportedOperationException( "This shoudln't happen outside of PackageBuilder" );
}
}
}
return null;
}
public boolean available(Rule rule,
final String name) {
for ( int i = this.buildStack.size() - 1; i >= 0; i-- ) {
final Declaration declaration = (Declaration) ((RuleConditionElement) this.buildStack.get( i )).getInnerDeclarations().get( name );
if ( declaration != null ) {
return true;
}
}
for ( int i = 0, length = this.maps.length; i < length; i++ ) {
if ( this.maps[i].containsKey( (name) ) ) {
return true;
}
}
// look at parent rules
if ( rule != null && rule.getParent() != null ) {
// recursive algorithm for each parent
// -> lhs.getInnerDeclarations()
Declaration parentDeclaration = getExtendedDeclaration( rule.getParent(),
name );
if ( null != parentDeclaration ) {
return true;
}
}
return false;
}
public boolean isDuplicated(Rule rule,
final String name) {
for ( int i = 0, length = this.maps.length; i < length; i++ ) {
if ( this.maps[i].containsKey( (name) ) ) {
return true;
}
}
for ( int i = this.buildStack.size() - 1; i >= 0; i-- ) {
final RuleConditionElement rce = (RuleConditionElement) this.buildStack.get( i );
final Declaration declaration = (Declaration) rce.getInnerDeclarations().get( name );
if ( declaration != null ) {
if ( (rce instanceof GroupElement) && ((GroupElement) rce).isOr() ) {
// if it is an OR and it is duplicated, we can stop looking for duplication now
// as it is a separate logical branch
return false;
}
return true;
}
}
// look at parent rules
if ( rule != null && rule.getParent() != null ) {
// recursive algorithm for each parent
// -> lhs.getInnerDeclarations()
Declaration parentDeclaration = getExtendedDeclaration( rule.getParent(),
name );
if ( null != parentDeclaration ) {
return true;
}
}
return false;
}
/**
* Return all declarations scoped to the current
* RuleConditionElement in the build stack
*
* @return
*/
public Map<String, Declaration> getDeclarations(Rule rule) {
final Map<String, Declaration> declarations = new HashMap<String, Declaration>();
for ( int i = 0; i < this.buildStack.size(); i++ ) {
// this may be optimized in the future to only re-add elements at
// scope breaks, like "NOT" and "EXISTS"
declarations.putAll( ((RuleConditionElement) this.buildStack.get( i )).getInnerDeclarations() );
}
if ( null != rule.getParent() ) {
return getAllExtendedDeclaration( rule.getParent(),
(HashMap<String, Declaration>) declarations );
}
return declarations;
}
public Map<String,Class<?>> getDeclarationClasses(Rule rule) {
final Map<String, Declaration> declarations = getDeclarations( rule );
final Map<String, Class<?>> classes = new HashMap<String, Class<?>>();
for ( Map.Entry<String, Declaration> decl : declarations.entrySet() ) {
InternalReadAccessor ira = decl.getValue().getExtractor();
if( ira != null )
classes.put( decl.getKey(), ira.getExtractToClass() );
}
return classes;
}
public Pattern findPatternByIndex(int index) {
if ( !this.buildStack.isEmpty() ) {
return findPatternInNestedElements( index,
(RuleConditionElement) this.buildStack.get( 0 ) );
}
return null;
}
private Pattern findPatternInNestedElements(final int index,
final RuleConditionElement rce) {
for ( RuleConditionElement element : rce.getNestedElements() ) {
if ( element instanceof Pattern ) {
Pattern p = (Pattern) element;
if ( p.getIndex() == index ) {
return p;
}
} else if ( !element.isPatternScopeDelimiter() ) {
Pattern p = findPatternInNestedElements( index,
element );
if ( p != null ) {
return p;
}
}
}
return null;
}
}