Package org.drools.core.spi

Source Code of org.drools.core.spi.DeclarationScopeResolver

/*
* 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.core.spi;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Stack;

import org.drools.core.base.ClassObjectType;
import org.drools.core.definitions.InternalKnowledgePackage;
import org.drools.core.definitions.rule.impl.RuleImpl;
import org.drools.core.rule.Declaration;
import org.drools.core.rule.GroupElement;
import org.drools.core.rule.Pattern;
import org.drools.core.rule.RuleConditionElement;

/**
* A class capable of resolving a declaration in the current build context
*/
public class DeclarationScopeResolver {
    private static final Stack<RuleConditionElement> EMPTY_STACK = new Stack<RuleConditionElement>();
    private Map<String, Class<?>>                    map;
    private Stack<RuleConditionElement>              buildStack;
    private InternalKnowledgePackage                 pkg;

    public DeclarationScopeResolver(final Map<String, Class<?>> maps) {
        this( maps,
              EMPTY_STACK );
    }

    public DeclarationScopeResolver(final Map<String, Class<?>> map,
                                    final Stack<RuleConditionElement> buildStack) {
        this.map = map;
        if ( buildStack == null ) {
            this.buildStack = EMPTY_STACK;
        } else {
            this.buildStack = buildStack;
        }
    }

    public void setPackage(InternalKnowledgePackage pkg) {
        this.pkg = pkg;
    }

    private Declaration getExtendedDeclaration(RuleImpl 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(RuleImpl 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 RuleImpl rule,
                                      final String identifier) {
        // it may be a local bound variable
        for ( int i = this.buildStack.size() - 1; i >= 0; i-- ) {
            final Declaration declaration = 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
        if ( this.map.containsKey( (identifier) ) ) {
            Class<?> cls = this.map.get( identifier );
            ClassObjectType classObjectType = new ClassObjectType( cls );

            Declaration declaration;
            final Pattern dummy = new Pattern( 0,
                                               classObjectType );

            InternalReadAccessor globalExtractor = getReadAcessor( identifier,
                                                                   classObjectType );
            declaration = new Declaration( identifier,
                                           globalExtractor,
                                           dummy );
            if ( pkg != null ) {

                // 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,
                                                                     ( AcceptsClassObjectType ) globalExtractor );
            }
            return declaration;
        }
        return null;
    }

    public static InternalReadAccessor getReadAcessor(String identifier,
                                                      ObjectType objectType) {
        Class returnType = ((ClassObjectType) objectType).getClassType();

        if (Number.class.isAssignableFrom( returnType ) ||
                ( returnType == byte.class ||
                  returnType == short.class ||
                  returnType == int.class ||
                  returnType == long.class ||
                  returnType == float.class ||
                  returnType == double.class ) ) {
            return new GlobalNumberExtractor(identifier,
                                             objectType);
         } else if Date.class.isAssignableFrom( returnType) ) {
          return new GlobalDateExtractor(identifier,
                                         objectType);
        } else {
          return new GlobalExtractor(identifier,
                                     objectType);
        }
    }

    public boolean available(RuleImpl rule,
                             final String name) {
        for ( int i = this.buildStack.size() - 1; i >= 0; i-- ) {
            final Declaration declaration = buildStack.get( i ).getInnerDeclarations().get( name );
            if ( declaration != null ) {
                return true;
            }
        }
        if ( this.map.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(RuleImpl rule,
                                final String name,
                                final String type) {
        if ( this.map.containsKey( (name) ) ) {
            return true;
        }

        for ( int i = this.buildStack.size() - 1; i >= 0; i-- ) {
            final RuleConditionElement rce = buildStack.get( i );
            final Declaration declaration = rce.getInnerDeclarations().get( name );
            if ( declaration != null ) {
                // if it is an OR and it is duplicated, we can stop looking for duplication now
                // as it is a separate logical branch
                boolean inOr = ((rce instanceof GroupElement) && ((GroupElement) rce).isOr());
                if ( ! inOr || type == null ) {
                    return ! inOr;
                }
                return ! declaration.getExtractor().getExtractToClass().getName().equals( type );
            }
        }
        // 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 Map<String, Declaration> getDeclarations(RuleImpl rule) {
        return getDeclarations(rule, RuleImpl.DEFAULT_CONSEQUENCE_NAME);
    }

    /**
     * Return all declarations scoped to the current
     * RuleConditionElement in the build stack
     *
     * @return
     */
    public Map<String, Declaration> getDeclarations(RuleImpl rule, String consequenceName) {
        final Map<String, Declaration> declarations = new HashMap<String, Declaration>();
        for (RuleConditionElement aBuildStack : this.buildStack) {
            // if we are inside of an OR we don't want each previous stack entry added because we can't see those variables
            if (aBuildStack instanceof GroupElement && ((GroupElement)aBuildStack).getType() == GroupElement.Type.OR) {
                continue;
            }

            // this may be optimized in the future to only re-add elements at
            // scope breaks, like "NOT" and "EXISTS"
            Map<String,Declaration> innerDeclarations = aBuildStack instanceof GroupElement ?
                    ((GroupElement)aBuildStack).getInnerDeclarations(consequenceName) :
                    aBuildStack.getInnerDeclarations();
            declarations.putAll(innerDeclarations);
        }
        if ( null != rule.getParent() ) {
            return getAllExtendedDeclaration( rule.getParent(),
                                              (HashMap<String, Declaration>) declarations );
        }
        return declarations;
    }

    public Map<String,Class<?>> getDeclarationClasses(RuleImpl rule) {
        final Map<String, Declaration> declarations = getDeclarations( rule );
        return getDeclarationClasses( declarations );
    }

    public static Map<String,Class<?>> getDeclarationClasses( final Map<String, Declaration> declarations) {
        final Map<String, Class<?>> classes = new HashMap<String, Class<?>>();
        for ( Map.Entry<String, Declaration> decl : declarations.entrySet() ) {
            InternalReadAccessor ira = decl.getValue().getExtractor();
            // FIXME when would the IRA be null?
            if( ira != null ) {
                classes.put( decl.getKey(), ira.getExtractToClass() );
            }
        }
        return classes;
    }

    public Pattern findPatternByIndex(int index) {
        if ( !this.buildStack.isEmpty() ) {
            return findPatternInNestedElements( index, 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;
    }
}
TOP

Related Classes of org.drools.core.spi.DeclarationScopeResolver

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.