directory-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From elecha...@apache.org
Subject svn commit: r234313 [1/2] - in /directory/asn1/branches/asn1-new-ber/ber/src/java/org/apache/asn1/ber: digester/ digester/rules/ primitives/
Date Sun, 21 Aug 2005 18:46:38 GMT
Author: elecharny
Date: Sun Aug 21 11:46:27 2005
New Revision: 234313

URL: http://svn.apache.org/viewcvs?rev=234313&view=rev
Log:
created

Added:
    directory/asn1/branches/asn1-new-ber/ber/src/java/org/apache/asn1/ber/digester/
    directory/asn1/branches/asn1-new-ber/ber/src/java/org/apache/asn1/ber/digester/AbstractRule.java
    directory/asn1/branches/asn1-new-ber/ber/src/java/org/apache/asn1/ber/digester/BERDigester.java
    directory/asn1/branches/asn1-new-ber/ber/src/java/org/apache/asn1/ber/digester/BERDigesterLoggingMonitor.java
    directory/asn1/branches/asn1-new-ber/ber/src/java/org/apache/asn1/ber/digester/BERDigesterMonitor.java
    directory/asn1/branches/asn1-new-ber/ber/src/java/org/apache/asn1/ber/digester/Rule.java
    directory/asn1/branches/asn1-new-ber/ber/src/java/org/apache/asn1/ber/digester/RuleRegistration.java
    directory/asn1/branches/asn1-new-ber/ber/src/java/org/apache/asn1/ber/digester/Rules.java
    directory/asn1/branches/asn1-new-ber/ber/src/java/org/apache/asn1/ber/digester/RulesBase.java
    directory/asn1/branches/asn1-new-ber/ber/src/java/org/apache/asn1/ber/digester/TagNode.java
    directory/asn1/branches/asn1-new-ber/ber/src/java/org/apache/asn1/ber/digester/TagTree.java
    directory/asn1/branches/asn1-new-ber/ber/src/java/org/apache/asn1/ber/digester/rules/
    directory/asn1/branches/asn1-new-ber/ber/src/java/org/apache/asn1/ber/digester/rules/ByteAccumulator.java
    directory/asn1/branches/asn1-new-ber/ber/src/java/org/apache/asn1/ber/digester/rules/ObjectCreateRule.java
    directory/asn1/branches/asn1-new-ber/ber/src/java/org/apache/asn1/ber/digester/rules/Octets2StringRule.java
    directory/asn1/branches/asn1-new-ber/ber/src/java/org/apache/asn1/ber/digester/rules/PopOnFinish.java
    directory/asn1/branches/asn1-new-ber/ber/src/java/org/apache/asn1/ber/digester/rules/PrimitiveBooleanRule.java
    directory/asn1/branches/asn1-new-ber/ber/src/java/org/apache/asn1/ber/digester/rules/PrimitiveEnumDecodeRule.java
    directory/asn1/branches/asn1-new-ber/ber/src/java/org/apache/asn1/ber/digester/rules/PrimitiveIntDecodeRule.java
    directory/asn1/branches/asn1-new-ber/ber/src/java/org/apache/asn1/ber/digester/rules/PrimitiveOctetStringRule.java
    directory/asn1/branches/asn1-new-ber/ber/src/java/org/apache/asn1/ber/primitives/
    directory/asn1/branches/asn1-new-ber/ber/src/java/org/apache/asn1/ber/primitives/ContextSpecificTag.java
    directory/asn1/branches/asn1-new-ber/ber/src/java/org/apache/asn1/ber/primitives/PrimitiveUtils.java
    directory/asn1/branches/asn1-new-ber/ber/src/java/org/apache/asn1/ber/primitives/UniversalTag.java

Added: directory/asn1/branches/asn1-new-ber/ber/src/java/org/apache/asn1/ber/digester/AbstractRule.java
URL: http://svn.apache.org/viewcvs/directory/asn1/branches/asn1-new-ber/ber/src/java/org/apache/asn1/ber/digester/AbstractRule.java?rev=234313&view=auto
==============================================================================
--- directory/asn1/branches/asn1-new-ber/ber/src/java/org/apache/asn1/ber/digester/AbstractRule.java (added)
+++ directory/asn1/branches/asn1-new-ber/ber/src/java/org/apache/asn1/ber/digester/AbstractRule.java Sun Aug 21 11:46:27 2005
@@ -0,0 +1,91 @@
+/*
+ *   Copyright 2004 The Apache Software Foundation
+ *
+ *   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.apache.asn1.ber.digester ;
+
+
+import java.nio.ByteBuffer;
+
+import org.apache.asn1.ber.TypeClass;
+
+
+/**
+ * A rule base class.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">
+ * Apache Directory Project</a>
+ * @version $Rev: 157644 $
+ */
+public abstract class AbstractRule implements Rule
+{
+    private BERDigester digester = null ;
+
+    
+    /* (non-Javadoc)
+     * @see org.apache.snickers.ber.rulesBase.Rule#getDigester()
+     */
+    public BERDigester getDigester()
+    {
+        return digester ;
+    }
+    
+    
+    /* (non-Javadoc)
+     * @see org.apache.snickers.ber.rulesBase.Rule#setDigester(
+     * org.apache.snickers.ber.rulesBase.BERDigester)
+     */
+    public void setDigester( BERDigester digester )
+    {
+        this.digester = digester ;
+    }
+
+    
+    /* (non-Javadoc)
+     * @see org.apache.snickers.ber.Rule#tag(int, boolean, 
+     * org.apache.asn1.ber.TypeClass)
+     */
+    public void tag( int id, boolean isPrimitive, TypeClass typeClass )
+    {
+        // do nothing base class
+    }
+
+    
+    /* (non-Javadoc)
+     * @see org.apache.snickers.ber.Rule#length(int)
+     */
+    public void length( int length )
+    {
+        // do nothing base class
+    }
+
+    
+    /* (non-Javadoc)
+     * @see org.apache.snickers.ber.Rule#value(java.nio.ByteBuffer)
+     */
+    public void value( ByteBuffer buf )
+    {
+        // do nothing base class
+    }
+
+    
+    /* (non-Javadoc)
+     * @see org.apache.snickers.ber.Rule#finish()
+     */
+    public void finish()
+    {
+        // do nothing base class
+    }
+}

Added: directory/asn1/branches/asn1-new-ber/ber/src/java/org/apache/asn1/ber/digester/BERDigester.java
URL: http://svn.apache.org/viewcvs/directory/asn1/branches/asn1-new-ber/ber/src/java/org/apache/asn1/ber/digester/BERDigester.java?rev=234313&view=auto
==============================================================================
--- directory/asn1/branches/asn1-new-ber/ber/src/java/org/apache/asn1/ber/digester/BERDigester.java (added)
+++ directory/asn1/branches/asn1-new-ber/ber/src/java/org/apache/asn1/ber/digester/BERDigester.java Sun Aug 21 11:46:27 2005
@@ -0,0 +1,1153 @@
+/*
+ *   Copyright 2004 The Apache Software Foundation
+ *
+ *   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.apache.asn1.ber.digester ;
+
+
+import java.nio.ByteBuffer;
+import java.util.Collections;
+import java.util.EmptyStackException;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.asn1.ber.BERDecoder;
+import org.apache.asn1.ber.BERDecoderCallback;
+import org.apache.asn1.ber.Tuple;
+import org.apache.asn1.ber.TypeClass;
+import org.apache.asn1.codec.DecoderException;
+import org.apache.asn1.codec.stateful.AbstractStatefulDecoder;
+import org.apache.asn1.codec.stateful.StatefulDecoder;
+import org.apache.commons.collections.ArrayStack;
+import org.apache.commons.collections.primitives.BooleanStack;
+import org.apache.commons.collections.primitives.ByteStack;
+import org.apache.commons.collections.primitives.CharStack;
+import org.apache.commons.collections.primitives.DoubleStack;
+import org.apache.commons.collections.primitives.FloatStack;
+import org.apache.commons.collections.primitives.IntStack;
+import org.apache.commons.collections.primitives.LongStack;
+import org.apache.commons.collections.primitives.ShortStack;
+
+
+/**
+ * A special BER TLV event rulesBase.  This class was inspired by the XML
+ * rulesBase in Jakarta Commons.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">
+ * Apache Directory Project</a>
+ * @version $Rev: 157644 $
+ */
+public class BERDigester extends AbstractStatefulDecoder
+{
+    /**
+     * For now this corresponds to a tag of class Universal with an id
+     * of 15.  This has been reserved for future use but to my knowledge
+     * currently it is not being used for anything specifically.  Hence
+     * we use it as the return value instead of throwing an empty stack
+     * exception when the top of the tag stack is requested.
+     */
+    public static final int NO_TOP_TAG = 0x0f000000 ;
+
+    /** the underlying decoder used by this rulesBase */
+    private BERDecoder decoder ;
+    /** the object stack where rules push and pop ASN.1 POJO stubs */
+    private ArrayStack objectStack ;
+    /** the primitive boolean stack where rules push and pop booleans */
+    private BooleanStack booleanStack ;
+    /** the primitive char stack where rules push and pop chars */
+    private CharStack charStack ;
+    /** the primitive float stack where rules push and pop floats */
+    private FloatStack floatStack ;
+    /** the primitive double stack where rules push and pop doubles */
+    private DoubleStack doubleStack ;
+    /** the primitive int stack where rules push and pop ints */
+    private IntStack intStack ;
+    /** the primitive byte stack where rules push and pop bytes */
+    private ByteStack byteStack ;
+    /** the primitive long stack where rules push and pop longs */
+    private LongStack longStack ;
+    /** the primitive short stack where rules push and shorts */
+    private ShortStack shortStack ;
+    /** the tag stack used to store the nesting pattern */
+    private IntStack tagStack ;
+    /** the rules base used by this digester */
+    private Rules rules ;
+    /** the currently matched rules */
+    private List matched ;
+    /**
+     * The class loader to use for instantiating application objects.
+     * If not specified, the context class loader, or the class loader
+     * used to load Digester itself, is used, based on the value of the
+     * <code>useContextClassLoader</code> variable.
+     */
+    private ClassLoader classLoader = null ;
+    /**
+     * Do we want to use the Context ClassLoader when loading classes
+     * for instantiating new objects.  Default is <code>false</code>.
+     */
+    private boolean useContextClassLoader = false ;
+    /**
+     * The "root" element of the stack (in other words, the last object
+     * that was popped.
+     */
+    private Object root = null ;
+    /** The monitor used by this digester */
+    private BERDigesterMonitor monitor = null ;
+
+
+    /**
+     * Creates a BER TLV event rulesBase.
+     */
+    public BERDigester()
+    {
+        this.rules = new RulesBase() ;
+        this.rules.setDigester( this ) ;
+        this.tagStack = new IntStack() ;
+        this.objectStack = new ArrayStack() ;
+        this.booleanStack = new BooleanStack() ;
+        this.charStack = new CharStack() ;
+        this.byteStack = new ByteStack() ;
+        this.shortStack = new ShortStack() ;
+        this.intStack = new IntStack() ;
+        this.longStack = new LongStack() ;
+        this.floatStack = new FloatStack() ;
+        this.doubleStack = new DoubleStack() ;
+        this.decoder = new BERDecoder() ;
+        this.decoder.setCallback( new DigesterCallback() ) ;
+        this.monitor = new BERDigesterLoggingMonitor() ;
+    }
+    
+    
+    // ------------------------------------------------------------------------
+    // StatefulDecoder implementation
+    // ------------------------------------------------------------------------
+
+
+    /* (non-Javadoc)
+     * @see org.apache.asn1.codec.stateful.StatefulDecoder
+     * #decode(java.lang.Object)
+     */
+    public void decode( Object encoded ) throws DecoderException
+    {
+        decoder.decode( encoded ) ;
+    }
+
+
+    // ------------------------------------------------------------------------
+    // BERDecoderCallback implementation
+    // ------------------------------------------------------------------------
+
+
+    class DigesterCallback implements BERDecoderCallback
+    {
+        /* (non-Javadoc)
+         * @see org.apache.asn1.ber.BERDecoderCallback#tagDecoded(
+         * org.apache.asn1.ber.Tuple)
+         */
+        public void tagDecoded( Tuple tlv )
+        {
+            tagStack.push( tlv.getRawPrimitiveTag() ) ;
+            matched = rules.match( tagStack ) ;
+            fireTagEvent( tlv.getId(), tlv.isPrimitive(), tlv.getTypeClass() ) ;
+        }
+
+
+        /* (non-Javadoc)
+         * @see org.apache.asn1.ber.BERDecoderCallback#lengthDecoded(
+         * org.apache.asn1.ber.Tuple)
+         */
+        public void lengthDecoded( Tuple tlv )
+        {
+            fireLengthEvent( tlv.getLength() ) ;
+        }
+
+
+        /* (non-Javadoc)
+         * @see org.apache.asn1.ber.BERDecoderCallback#partialValueDecoded(
+         * org.apache.asn1.ber.Tuple)
+         */
+        public void partialValueDecoded( Tuple tlv )
+        {
+            fireValueEvent( tlv.getLastValueChunk() ) ;
+        }
+
+
+        /* (non-Javadoc)
+         * @see org.apache.asn1.codec.stateful.DecoderCallback#decodeOccurred(
+         * org.apache.asn1.codec.stateful.StatefulDecoder, java.lang.Object)
+         */
+        public void decodeOccurred( StatefulDecoder decoder, Object decoded )
+        {
+            /*
+             * must reset the matched rules here because the nested TLVs
+             * overwrite the matched rules of a constructed TLV so it must
+             * be set once again
+             */
+            matched = rules.match( tagStack ) ;
+            fireFinishEvent() ;
+            tagStack.pop() ;
+            
+            if ( BERDigester.this.tagStack.empty() )
+            {
+                BERDigester.this.decodeOccurred( getRoot() ) ;
+            }
+        }
+    }
+
+
+    // ------------------------------------------------------------------------
+    // Digester like methods
+    // ------------------------------------------------------------------------
+
+
+    /**
+     * Register a new <code>Rule</code> matching the specified pattern.
+     *
+     * @param pattern tag nesting pattern
+     * @param rule the Rule to add to this BERDigester
+     */
+    public void addRule( int[] pattern, Rule rule )
+    {
+        rules.add( pattern, rule ) ;
+        rule.setDigester( this ) ;
+    }
+               
+    
+    /**
+     * Return the Rules implementation object containing our rules collection 
+     * and associated matching policy.
+     * 
+     * @return the entire set of rules
+     */
+    public Rules getRules()
+    {
+        return rules ;
+    }
+             
+
+    /**
+     * Clear the current contents of the object stack.
+     */
+    public void clear()
+    {
+        root = null ;
+        tagStack.clear() ;
+        objectStack.clear() ;
+        booleanStack.clear() ;
+        byteStack.clear() ;
+        shortStack.clear() ;
+        intStack.clear() ;
+        longStack.clear() ;
+        floatStack.clear() ;
+        doubleStack.clear() ;
+    }
+
+
+    // ------------------------------------------------------------------------
+    // Stack Operations
+    // ------------------------------------------------------------------------
+
+
+    /**
+     * Return the current depth of the object stack.
+     * 
+     * @return the size of the object stack
+     */
+    public int getCount()
+    {
+        return objectStack.size() ;
+    }
+    
+    
+    /**
+     * Return the top object on the stack without removing it.
+     * 
+     * @return the top object
+     * @throws EmptyStackException if there are no objects on the stack
+     */
+    public Object peek() 
+    {
+        return ( objectStack.peek() ) ;
+    }
+    
+    
+    /**
+     * Return the n'th object down the stack, where 0 is the top element and 
+     * [getCount()-1] is the bottom element.
+     * 
+     * @param n the element index
+     * @return the element at the index
+     * @throws EmptyStackException if there are no objects on the stack
+     * @throws IndexOutOfBoundsException if the index is out of bounds
+     */
+    public Object peek( int n )
+    {
+        return ( objectStack.peek( n ) ) ;
+    }
+              
+    
+    /**
+     * Pop the top object off of the stack, and return it.
+     * 
+     * @return the top object off of the stack
+     * @throws EmptyStackException if there are no objects on the stack
+     */
+    public Object pop()
+    {
+        return ( objectStack.pop() ) ;
+    }
+              
+    
+    /**
+     * Push a new object onto the top of the object stack.
+     * 
+     * @param object the object to push onto the stack
+     */
+    public void push( Object object )
+    {
+        if ( objectStack.size() == 0 ) 
+        {
+            root = object ;
+        }
+
+        objectStack.push( object ) ;
+    }
+
+
+    // ------------------------------------------------------------------------
+    // Primitive boolean Stack Operations
+    // ------------------------------------------------------------------------
+
+
+    /**
+     * Return the current depth of the boolean stack.
+     *
+     * @return the size of the boolean stack
+     */
+    public int getBooleanCount()
+    {
+        return booleanStack.size() ;
+    }
+
+
+    /**
+     * Return the top boolean on the stack without removing it.
+     *
+     * @return the top boolean
+     * @throws EmptyStackException if there are no more boolean elements left
+     */
+    public boolean peekBoolean()
+    {
+        return ( booleanStack.peek() ) ;
+    }
+
+
+    /**
+     * Return the n'th boolean down the stack, where 0 is the top element and
+     * [getCount()-1] is the bottom element.
+     *
+     * @param n the element index
+     * @return the element at the index
+     * @throws EmptyStackException if there are no more boolean elements left
+     * @throws IndexOutOfBoundsException if the index is out of bounds
+     */
+    public boolean peekBoolean( int n )
+    {
+        return ( booleanStack.peek( n ) ) ;
+    }
+
+
+    /**
+     * Pop the top boolean off of the stack, and return it.
+     *
+     * @return the top boolean off of the stack
+     * @throws EmptyStackException if the stack is empty
+     */
+    public boolean popBoolean()
+    {
+        return ( booleanStack.pop() ) ;
+    }
+
+
+    /**
+     * Push a new boolean onto the top of the boolean stack.
+     *
+     * @param bit the boolean to push onto the stack
+     */
+    public void pushBoolean( boolean bit )
+    {
+        booleanStack.push( bit ) ;
+    }
+
+
+    // ------------------------------------------------------------------------
+    // Primitive char Stack Operations
+    // ------------------------------------------------------------------------
+
+
+    /**
+     * Return the current depth of the char stack.
+     *
+     * @return the size of the char stack
+     */
+    public int getCharCount()
+    {
+        return charStack.size() ;
+    }
+
+
+    /**
+     * Return the top char on the stack without removing it.
+     *
+     * @return the top char
+     * @throws EmptyStackException if there are no more char elements left
+     */
+    public char peekChar()
+    {
+        return ( charStack.peek() ) ;
+    }
+
+
+    /**
+     * Return the n'th char down the stack, where 0 is the top element and
+     * [getCount()-1] is the bottom element.
+     *
+     * @param n the element index
+     * @return the element at the index
+     * @throws EmptyStackException if there are no more char elements left
+     * @throws IndexOutOfBoundsException if the index is out of bounds
+     */
+    public char peekChar( int n )
+    {
+        return ( charStack.peek( n ) ) ;
+    }
+
+
+    /**
+     * Pop the top char off of the stack, and return it.
+     *
+     * @return the top char off of the stack
+     * @throws EmptyStackException if the stack is empty
+     */
+    public char popChar()
+    {
+        return ( charStack.pop() ) ;
+    }
+
+
+    /**
+     * Push a new char onto the top of the char stack.
+     *
+     * @param ch the char to push onto the stack
+     */
+    public void pushChar( char ch )
+    {
+        charStack.push( ch ) ;
+    }
+
+
+    // ------------------------------------------------------------------------
+    // Primitive byte Stack Operations
+    // ------------------------------------------------------------------------
+
+
+    /**
+     * Return the current depth of the byte stack.
+     *
+     * @return the size of the byte stack
+     */
+    public int getByteCount()
+    {
+        return byteStack.size() ;
+    }
+
+
+    /**
+     * Return the top byte on the stack without removing it.
+     *
+     * @return the top byte
+     * @throws EmptyStackException if there are no more byte elements left
+     */
+    public byte peekByte()
+    {
+        return ( byteStack.peek() ) ;
+    }
+
+
+    /**
+     * Return the n'th byte down the stack, where 0 is the top element and
+     * [getCount()-1] is the bottom element.
+     *
+     * @param n the element index
+     * @return the element at the index
+     * @throws EmptyStackException if there are no more byte elements left
+     * @throws IndexOutOfBoundsException if the index is out of bounds
+     */
+    public byte peekByte( int n )
+    {
+        return ( byteStack.peek( n ) ) ;
+    }
+
+
+    /**
+     * Pop the top byte off of the stack, and return it.
+     *
+     * @return the top byte off of the stack
+     * @throws EmptyStackException if the stack is empty
+     */
+    public byte popByte()
+    {
+        return ( byteStack.pop() ) ;
+    }
+
+
+    /**
+     * Push a new byte onto the top of the byte stack.
+     *
+     * @param bite the byte to push onto the stack
+     */
+    public void pushByte( byte bite )
+    {
+        byteStack.push( bite ) ;
+    }
+
+
+    // ------------------------------------------------------------------------
+    // Primitive short Stack Operations
+    // ------------------------------------------------------------------------
+
+
+    /**
+     * Return the current depth of the short stack.
+     *
+     * @return the size of the short stack
+     */
+    public int getShortCount()
+    {
+        return shortStack.size() ;
+    }
+
+
+    /**
+     * Return the top short on the stack without removing it.
+     *
+     * @return the top short
+     * @throws EmptyStackException if there are no more short elements left
+     */
+    public short peekShort()
+    {
+        return ( shortStack.peek() ) ;
+    }
+
+
+    /**
+     * Return the n'th short down the stack, where 0 is the top element and
+     * [getCount()-1] is the bottom element.
+     *
+     * @param n the element index
+     * @return the element at the index
+     * @throws EmptyStackException if there are no more short elements left
+     * @throws IndexOutOfBoundsException if the index is out of bounds
+     */
+    public short peekShort( int n )
+    {
+        return ( shortStack.peek( n ) ) ;
+    }
+
+
+    /**
+     * Pop the top short off of the stack, and return it.
+     *
+     * @return the top short off of the stack
+     * @throws EmptyStackException if the stack is empty
+     */
+    public short popShort()
+    {
+        return ( shortStack.pop() ) ;
+    }
+
+
+    /**
+     * Push a new short onto the top of the short stack.
+     *
+     * @param element the short to push onto the stack
+     */
+    public void pushShort( short element )
+    {
+        shortStack.push( element ) ;
+    }
+
+
+    // ------------------------------------------------------------------------
+    // Primitive int Stack Operations
+    // ------------------------------------------------------------------------
+
+
+    /**
+     * Return the current depth of the int stack.
+     *
+     * @return the size of the int stack
+     */
+    public int getIntCount()
+    {
+        return intStack.size() ;
+    }
+
+
+    /**
+     * Return the top int on the stack without removing it.
+     *
+     * @return the top int
+     * @throws EmptyStackException if there are no more int elements left
+     */
+    public int peekInt()
+    {
+        return ( intStack.peek() ) ;
+    }
+
+
+    /**
+     * Return the n'th int down the stack, where 0 is the top element and
+     * [getCount()-1] is the bottom element.
+     *
+     * @param n the element index
+     * @return the element at the index
+     * @throws EmptyStackException if there are no more int elements left
+     * @throws IndexOutOfBoundsException if the index is out of bounds
+     */
+    public int peekInt( int n )
+    {
+        return ( intStack.peek( n ) ) ;
+    }
+
+
+    /**
+     * Pop the top int off of the stack, and return it.
+     *
+     * @return the top int off of the stack
+     * @throws EmptyStackException if the stack is empty
+     */
+    public int popInt()
+    {
+        return ( intStack.pop() ) ;
+    }
+
+
+    /**
+     * Push a new int onto the top of the int stack.
+     *
+     * @param element the int to push onto the stack
+     */
+    public void pushInt( int element )
+    {
+        intStack.push( element ) ;
+    }
+
+
+    // ------------------------------------------------------------------------
+    // Primitive long Stack Operations
+    // ------------------------------------------------------------------------
+
+
+    /**
+     * Return the current depth of the long stack.
+     *
+     * @return the size of the long stack
+     */
+    public int getLongCount()
+    {
+        return longStack.size() ;
+    }
+
+
+    /**
+     * Return the top long on the stack without removing it.
+     *
+     * @return the top long
+     * @throws EmptyStackException if there are no more long elements left
+     */
+    public long peekLong()
+    {
+        return ( longStack.peek() ) ;
+    }
+
+
+    /**
+     * Return the n'th long down the stack, where 0 is the top element and
+     * [getCount()-1] is the bottom element.
+     *
+     * @param n the element index
+     * @return the element at the index
+     * @throws EmptyStackException if there are no more long elements left
+     * @throws IndexOutOfBoundsException if the index is out of bounds
+     */
+    public long peekLong( int n )
+    {
+        return ( longStack.peek( n ) ) ;
+    }
+
+
+    /**
+     * Pop the top long off of the stack, and return it.
+     *
+     * @return the top long off of the stack
+     * @throws EmptyStackException if the stack is empty
+     */
+    public long popLong()
+    {
+        return ( longStack.pop() ) ;
+    }
+
+
+    /**
+     * Push a new long onto the top of the long stack.
+     *
+     * @param element the long to push onto the stack
+     */
+    public void pushLong( long element )
+    {
+        longStack.push( element ) ;
+    }
+
+
+    // ------------------------------------------------------------------------
+    // Primitive float Stack Operations
+    // ------------------------------------------------------------------------
+
+
+    /**
+     * Return the current depth of the float stack.
+     *
+     * @return the size of the float stack
+     */
+    public int getFloatCount()
+    {
+        return floatStack.size() ;
+    }
+
+
+    /**
+     * Return the top float on the stack without removing it.
+     *
+     * @return the top float
+     * @throws EmptyStackException if there are no more float elements left
+     */
+    public float peekFloat()
+    {
+        return ( floatStack.peek() ) ;
+    }
+
+
+    /**
+     * Return the n'th float down the stack, where 0 is the top element and
+     * [getCount()-1] is the bottom element.
+     *
+     * @param n the element index
+     * @return the element at the index
+     * @throws EmptyStackException if there are no more float elements left
+     * @throws IndexOutOfBoundsException if the index is out of bounds
+     */
+    public float peekFloat( int n )
+    {
+        return ( floatStack.peek( n ) ) ;
+    }
+
+
+    /**
+     * Pop the top float off of the stack, and return it.
+     *
+     * @return the top float off of the stack
+     * @throws EmptyStackException if the stack is empty
+     */
+    public float popFloat()
+    {
+        return ( floatStack.pop() ) ;
+    }
+
+
+    /**
+     * Push a new float onto the top of the float stack.
+     *
+     * @param element the float to push onto the stack
+     */
+    public void pushFloat( float element )
+    {
+        floatStack.push( element ) ;
+    }
+
+
+    // ------------------------------------------------------------------------
+    // Primitive double Stack Operations
+    // ------------------------------------------------------------------------
+
+
+    /**
+     * Return the current depth of the double stack.
+     *
+     * @return the size of the double stack
+     */
+    public int getDoubleCount()
+    {
+        return doubleStack.size() ;
+    }
+
+
+    /**
+     * Return the top double on the stack without removing it.
+     *
+     * @return the top double
+     * @throws EmptyStackException if there are no more double elements left
+     */
+    public double peekDouble()
+    {
+        return ( doubleStack.peek() ) ;
+    }
+
+
+    /**
+     * Return the n'th double down the stack, where 0 is the top element and
+     * [getCount()-1] is the bottom element.
+     *
+     * @param n the element index
+     * @return the element at the index
+     * @throws EmptyStackException if there are no more double elements left
+     * @throws IndexOutOfBoundsException if the index is out of bounds
+     */
+    public double peekDouble( int n )
+    {
+        return ( doubleStack.peek( n ) ) ;
+    }
+
+
+    /**
+     * Pop the top double off of the stack, and return it.
+     *
+     * @return the top double off of the stack
+     * @throws EmptyStackException if the stack is empty
+     */
+    public double popDouble()
+    {
+        return ( doubleStack.pop() ) ;
+    }
+
+
+    /**
+     * Push a new double onto the top of the double stack.
+     *
+     * @param element the double to push onto the stack
+     */
+    public void pushDouble( double element )
+    {
+        doubleStack.push( element ) ;
+    }
+
+
+    /**
+     * This method allows you to access the root object that has been
+     * created after decoding.
+     * 
+     * @return the root object that has been created after decoding or null if 
+     * the rulesBase has not decoded any PDUs yet.
+     */
+    public Object getRoot()
+    {
+        return this.root ;
+    }
+    
+
+    /**
+     * Set the Rules implementation object containing our rules collection 
+     * and associated matching policy.
+     * 
+     * @param rules the rules to add to this rulesBase
+     */
+    public void setRules( Rules rules )
+    {
+        this.rules = rules ;
+        this.rules.setDigester( this ) ;
+    }
+    
+    
+    // ------------------------------------------------------------------------
+    // Read Only Tag Stack (Primitive IntStack) Operations
+    // ------------------------------------------------------------------------
+
+
+    /**
+     * Return the current depth of the Tag stack.
+     *
+     * @return the size of the Tag stack
+     */
+    public int getTagCount()
+    {
+        return tagStack.size() ;
+    }
+
+
+    /**
+     * Return the n'th tag down the Tag stack, where 0 is the top element and
+     * [getCount()-1] is the bottom element.
+     *
+     * @param n the Tag index
+     * @return the Tag at the index
+     * @throws EmptyStackException if there are no more int Tags left
+     * @throws IndexOutOfBoundsException if the index is out of bounds
+     */
+    public int getTag( int n )
+    {
+        return ( tagStack.peek( n ) ) ;
+    }
+
+
+    /**
+     * Gets the raw int for the tag of the TLV currently being processed hence
+     * the tag on the top of the stack.  The tag's int has the primitive flag
+     * dubbed out so it appears to represent a primitive TLV even when the TLV
+     * may be constructed.
+     * 
+     * @return the raw int for the tag of the TLV currently being processed, or
+     * NO_TOP_TAG if there is no TLV currently being processed.
+     */
+    public int getTopTag()
+    {
+        if ( tagStack.size() <= 0 )
+        {
+            return NO_TOP_TAG ;
+        }
+
+        return tagStack.peek() ;
+    }
+
+    
+    // ------------------------------------------------------------------------
+    // ClassLoader Related Methods
+    // ------------------------------------------------------------------------
+
+
+    /**
+     * Return the class loader to be used for instantiating application objects
+     * when required.  This is determined based upon the following rules:
+     * <ul>
+     * <li>The class loader set by <code>setClassLoader()</code>, if any</li>
+     * <li>The thread context class loader, if it exists and the
+     *     <code>useContextClassLoader</code> property is set to true</li>
+     * <li>The class loader used to load the Digester class itself.
+     * </ul>
+     */
+    public ClassLoader getClassLoader() 
+    {
+        if ( classLoader != null ) 
+        {
+            return ( classLoader ) ;
+        }
+
+        if ( useContextClassLoader) 
+        {
+            ClassLoader classLoader = Thread.currentThread()
+                    .getContextClassLoader() ;
+
+            if ( classLoader != null )
+            {
+                return ( classLoader ) ;
+            }
+        }
+
+        return ( getClass().getClassLoader() ) ;
+    }
+
+
+    /**
+     * Set the class loader to be used for instantiating application objects
+     * when required.
+     *
+     * @param classLoader The new class loader to use, or <code>null</code>
+     *  to revert to the standard rules
+     */
+    public void setClassLoader( ClassLoader classLoader ) 
+    {
+        this.classLoader = classLoader ;
+    }
+
+
+    /**
+     * Return the boolean as to whether the context classloader should be used.
+     */
+    public boolean getUseContextClassLoader() 
+    {
+        return useContextClassLoader ;
+    }
+
+
+    /**
+     * Determine whether to use the Context ClassLoader (the one found by
+     * calling <code>Thread.currentThread().getContextClassLoader()</code>)
+     * to resolve/load classes that are defined in various rules.  If not
+     * using Context ClassLoader, then the class-loading defaults to
+     * using the calling-class' ClassLoader.
+     *
+     * @param use determines whether to use Context ClassLoader.
+     */
+    public void setUseContextClassLoader( boolean use ) 
+    {
+        useContextClassLoader = use ; 
+    }
+
+
+    // ------------------------------------------------------------------------
+    // Event fireing routines that trigger rules
+    // ------------------------------------------------------------------------
+    
+    
+    void fireTagEvent( int id, boolean isPrimitive, TypeClass typeClass )
+    {
+        Iterator rules = null ;
+
+        if ( matched == null )
+        {
+            rules = Collections.EMPTY_LIST.iterator() ;
+        }
+        else
+        {
+            rules = matched.iterator() ;
+        }
+
+        while ( rules.hasNext() )
+        {
+            Rule rule = ( Rule ) rules.next() ;
+            
+            try 
+            {
+                rule.tag( id, isPrimitive, typeClass ) ;
+            } 
+            catch ( RuntimeException e ) 
+            {
+                monitor.ruleFailed( this, rule, "Rule.tag() threw exception", e ) ;
+                throw e ;
+            }
+            catch ( Error e ) 
+            {
+                monitor.ruleFailed( this, rule, "Rule.tag() threw error", e ) ;
+                throw e ;
+            }
+        }
+    }
+    
+    
+    void fireLengthEvent( int length )
+    {
+        Iterator rules = null ;
+
+        if ( matched == null )
+        {
+            rules = Collections.EMPTY_LIST.iterator() ;
+        }
+        else
+        {
+            rules = matched.iterator() ;
+        }
+
+        while ( rules.hasNext() )
+        {
+            Rule rule = ( Rule ) rules.next() ;
+            
+            try 
+            {
+                rule.length( length ) ;
+            } 
+            catch ( RuntimeException e )
+            {
+                monitor.ruleFailed( this, rule, "Rule.length() threw exception", e ) ;
+                throw e ;
+            }
+            catch ( Error e ) 
+            {
+                monitor.ruleFailed( this, rule, "Rule.length() threw error", e ) ;
+                throw e ;
+            }
+        }
+    }
+    
+    
+    void fireValueEvent( ByteBuffer buf )
+    {
+        Iterator rules = null ;
+
+        if ( matched == null )
+        {
+            rules = Collections.EMPTY_LIST.iterator() ;
+        }
+        else
+        {
+            rules = matched.iterator() ;
+        }
+
+        while ( rules.hasNext() )
+        {
+            Rule rule = ( Rule ) rules.next() ;
+            
+            try 
+            {
+                rule.value( buf ) ;
+
+                // need to rewind the buffer after rule exhausts it
+                buf.rewind() ;
+            }
+            catch ( RuntimeException e )
+            {
+                monitor.ruleFailed( this, rule, "Rule.value() threw exception", e ) ;
+                throw e ;
+            }
+            catch ( Error e ) 
+            {
+                monitor.ruleFailed( this, rule, "Rule.value() threw exception", e ) ;
+                throw e ;
+            }
+        }
+    }
+    
+    
+    void fireFinishEvent()
+    {
+        Rule rule = null ;
+        HashSet seen = null ;
+
+        if ( matched != null )
+        {
+            seen = new HashSet() ;
+            
+            for ( int i = 0; i < matched.size(); i++ ) 
+            {
+                try
+                {
+                    rule = ( Rule ) matched.get( i ) ;
+                    rule.finish() ;
+                    monitor.ruleCompleted( this, rule ) ;
+                    seen.add( rule ) ;
+                } 
+                catch ( RuntimeException e )
+                {
+                    monitor.ruleFailed( this, rule, "Rule.finish() threw exception", e ) ;
+                    throw e ;
+                }
+                catch ( Error e ) 
+                {
+                    monitor.ruleFailed( this, rule, "Rule.finish() threw error", e ) ;
+                    throw e ;
+                }
+            }
+        }
+    }
+}

Added: directory/asn1/branches/asn1-new-ber/ber/src/java/org/apache/asn1/ber/digester/BERDigesterLoggingMonitor.java
URL: http://svn.apache.org/viewcvs/directory/asn1/branches/asn1-new-ber/ber/src/java/org/apache/asn1/ber/digester/BERDigesterLoggingMonitor.java?rev=234313&view=auto
==============================================================================
--- directory/asn1/branches/asn1-new-ber/ber/src/java/org/apache/asn1/ber/digester/BERDigesterLoggingMonitor.java (added)
+++ directory/asn1/branches/asn1-new-ber/ber/src/java/org/apache/asn1/ber/digester/BERDigesterLoggingMonitor.java Sun Aug 21 11:46:27 2005
@@ -0,0 +1,70 @@
+/*
+ *   Copyright 2004 The Apache Software Foundation
+ *
+ *   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.apache.asn1.ber.digester ;
+
+
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+
+
+/**
+ * A logging BER digestor monitor.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev: 231081 $
+ */
+public class BERDigesterLoggingMonitor implements BERDigesterMonitor
+{
+    /** logging facility for the digester */
+    private static Logger log = LoggerFactory.getLogger( "BERDigester" ) ;
+
+
+    /**
+     * Callback used to log a rule callback failure when triggered by the
+     * digester.
+     *
+     * @param digester the digester triggering the rule
+     * @param rule     the rule that failed
+     * @param msg      a message regarding the failure
+     * @param fault    the fault that caused the failure
+     */
+    public void ruleFailed( BERDigester digester, Rule rule, String msg,
+                            Throwable fault )
+    {
+        if ( log.isErrorEnabled() )
+        {
+            log.error( "Error while triggering rule " + rule
+                    + " with digester " + digester + ": " + msg, fault ) ;
+        }
+    }
+
+
+    /**
+     * Callback used to monitor successful rule firing.
+     *
+     * @param digester the digester triggering the rule
+     * @param rule     the rule that completed firing successfully
+     */
+    public void ruleCompleted( BERDigester digester, Rule rule )
+    {
+        if ( log.isDebugEnabled() )
+        {
+            log.debug( "Rule " + rule + " fired successfully by digester "
+                    + digester ) ;
+        }
+    }
+}

Added: directory/asn1/branches/asn1-new-ber/ber/src/java/org/apache/asn1/ber/digester/BERDigesterMonitor.java
URL: http://svn.apache.org/viewcvs/directory/asn1/branches/asn1-new-ber/ber/src/java/org/apache/asn1/ber/digester/BERDigesterMonitor.java?rev=234313&view=auto
==============================================================================
--- directory/asn1/branches/asn1-new-ber/ber/src/java/org/apache/asn1/ber/digester/BERDigesterMonitor.java (added)
+++ directory/asn1/branches/asn1-new-ber/ber/src/java/org/apache/asn1/ber/digester/BERDigesterMonitor.java Sun Aug 21 11:46:27 2005
@@ -0,0 +1,49 @@
+/*
+ *   Copyright 2004 The Apache Software Foundation
+ *
+ *   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.apache.asn1.ber.digester ;
+
+
+
+
+/**
+ * The monitor interface for a BER digester.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev: 157644 $
+ */
+public interface BERDigesterMonitor
+{
+    /**
+     * Callback used to monitor rule callback failures on triggered
+     * rules.
+     *
+     * @param digester the digester triggering the rule
+     * @param rule the rule that failed
+     * @param msg a message regarding the failure
+     * @param fault the fault that caused the failure
+     */
+    void ruleFailed( BERDigester digester, Rule rule, String msg,
+                     Throwable fault ) ;
+
+    /**
+     * Callback used to monitor successful rule firing.
+     *
+     * @param digester the digester triggering the rule
+     * @param rule the rule that completed firing successfully
+     */
+    void ruleCompleted( BERDigester digester, Rule rule ) ;
+}

Added: directory/asn1/branches/asn1-new-ber/ber/src/java/org/apache/asn1/ber/digester/Rule.java
URL: http://svn.apache.org/viewcvs/directory/asn1/branches/asn1-new-ber/ber/src/java/org/apache/asn1/ber/digester/Rule.java?rev=234313&view=auto
==============================================================================
--- directory/asn1/branches/asn1-new-ber/ber/src/java/org/apache/asn1/ber/digester/Rule.java (added)
+++ directory/asn1/branches/asn1-new-ber/ber/src/java/org/apache/asn1/ber/digester/Rule.java Sun Aug 21 11:46:27 2005
@@ -0,0 +1,77 @@
+/*
+ *   Copyright 2004 The Apache Software Foundation
+ *
+ *   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.apache.asn1.ber.digester ;
+
+
+import java.nio.ByteBuffer;
+
+import org.apache.asn1.ber.TypeClass;
+
+
+/**
+ * A BER event processing rule.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">
+ * Apache Directory Project</a>
+ * @version $Rev: 157644 $
+ */
+public interface Rule
+{
+    /**
+     * Get the <code>BERDigester</code> with which this <code>Rule</code> has
+     * been associated.
+     * 
+     * @return the associated rulesBase
+     */
+    BERDigester getDigester() ;
+    
+    /**
+     * Set the <code>BERDigester</code> with which this <code>Rule</code> will
+     * be associated.
+     * 
+     * @param digester the rulesBase to associate this rule with
+     */
+    void setDigester( BERDigester digester ) ;
+    
+    /**
+     * Called when the tag of the matched TLV is encountered.
+     * 
+     * @param id the tag's id 
+     * @param isPrimitive whether tlv is primitive or constructed
+     * @param typeClass the tag's type class
+     */
+    void tag( int id, boolean isPrimitive, TypeClass typeClass ) ;
+    
+    /**
+     * Called when the length of a TLV is encountered.
+     * 
+     * @param length the length in bytes of the value
+     */
+    void length( int length ) ;
+    
+    /**
+     * Called when a peice of the value is available.
+     * 
+     * @param buf a portion of the value
+     */
+    void value( ByteBuffer buf ) ;
+    
+    /**
+     * Called when the tlv has been completely consumed.
+     */
+    void finish() ;
+}

Added: directory/asn1/branches/asn1-new-ber/ber/src/java/org/apache/asn1/ber/digester/RuleRegistration.java
URL: http://svn.apache.org/viewcvs/directory/asn1/branches/asn1-new-ber/ber/src/java/org/apache/asn1/ber/digester/RuleRegistration.java?rev=234313&view=auto
==============================================================================
--- directory/asn1/branches/asn1-new-ber/ber/src/java/org/apache/asn1/ber/digester/RuleRegistration.java (added)
+++ directory/asn1/branches/asn1-new-ber/ber/src/java/org/apache/asn1/ber/digester/RuleRegistration.java Sun Aug 21 11:46:27 2005
@@ -0,0 +1,71 @@
+/*
+ *   Copyright 2004 The Apache Software Foundation
+ *
+ *   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.apache.asn1.ber.digester;
+
+
+
+
+/**
+ * Document this class.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory
+ *         Project</a>
+ * @version $Rev: 157644 $
+ */
+public class RuleRegistration
+{
+    /** the pattern that is used to register a rule with */
+    private final int[] pattern;
+    /** the rule registered with the pattern */
+    private final Rule rule;
+
+
+    /**
+     * Create a new rule registration used to track the rules and patterns that
+     * are registered with the digester.
+     *
+     * @param pattern the pattern used to register a rule with
+     * @param rule the rule registered with the pattern
+     */
+    public RuleRegistration( int[] pattern, Rule rule )
+    {
+        this.rule = rule;
+        this.pattern = pattern;
+    }
+
+
+    /**
+     * Gets the pattern used to register a rule.
+     *
+     * @return the pattern that is used to register a rule
+     */
+    public int[] getPattern()
+    {
+        return pattern;
+    }
+
+
+    /**
+     * Gets the rule registered with the pattern.
+     *
+     * @return the rule registered with the pattern
+     */
+    public Rule getRule()
+    {
+        return rule;
+    }
+}

Added: directory/asn1/branches/asn1-new-ber/ber/src/java/org/apache/asn1/ber/digester/Rules.java
URL: http://svn.apache.org/viewcvs/directory/asn1/branches/asn1-new-ber/ber/src/java/org/apache/asn1/ber/digester/Rules.java?rev=234313&view=auto
==============================================================================
--- directory/asn1/branches/asn1-new-ber/ber/src/java/org/apache/asn1/ber/digester/Rules.java (added)
+++ directory/asn1/branches/asn1-new-ber/ber/src/java/org/apache/asn1/ber/digester/Rules.java Sun Aug 21 11:46:27 2005
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * 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.apache.asn1.ber.digester ;
+
+
+import java.util.List;
+
+import org.apache.commons.collections.primitives.IntStack;
+
+
+/**
+ * Public interface defining a collection of Rule instances (and corresponding
+ * matching patterns) plus an implementation of a matching policy that selects
+ * the rules that match a particular pattern of nested elements discovered
+ * during parsing.  The interface has been inspired by the rulesBase equivalent.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">
+ * Apache Directory Project</a>
+ * @version $Rev: 157644 $
+ */
+public interface Rules 
+{
+    /**
+     * Get the <code>BERDigester</code> instance with which this <code>Rules
+     * </code> instance is associated.
+     * 
+     * @return the BERDigester associated with this Rules instance
+     */
+    public BERDigester getDigester() ;
+
+    /**
+     * Get the <code>BERDigester</code> instance with which this <code>Rules
+     * </code> instance is associated.
+     * 
+     * @param digester the new BERDigester to be associated with this Rules 
+     * instance
+     */
+    public void setDigester( BERDigester digester ) ;
+
+    /**
+     * Register a new Rule instance matching the specified pattern.
+     *
+     * @param pattern Tag nesting pattern to be matched for this Rule
+     * @param rule Rule instance to be registered
+     */
+    public void add( int[] pattern, Rule rule ) ;
+
+    /**
+     * Clear all existing Rule instance registrations.
+     */
+    public void clear() ;
+
+    /**
+     * Return a List of all registered Rule instances that match the specified
+     * nesting pattern, or a zero-length List if there are no matches.  If more
+     * than one Rule instance matches, they <strong>must</strong> be returned
+     * in the order originally registered through the <code>add()</code>
+     * method.
+     *
+     * @param pattern Nesting pattern to be matched
+     */
+    public List match( int[] pattern ) ;
+
+    /**
+     * Return a List of all registered Rule instances that match the specified
+     * nesting pattern, or a zero-length List if there are no matches.  If more
+     * than one Rule instance matches, they <strong>must</strong> be returned
+     * in the order originally registered through the <code>add()</code>
+     * method.  The IntStack argument should not be affected by the match call.
+     *
+     * @param pattern Nesting pattern to be matched
+     */
+    public List match( IntStack pattern ) ;
+    
+    /**
+     * Return a List of all registered Rule instances, or a zero-length List
+     * if there are no registered Rule instances.  If more than one Rule
+     * instance has been registered, they <strong>must</strong> be returned
+     * in the order originally registered through the <code>add()</code>
+     * method.
+     */
+    public List rules() ;
+}

Added: directory/asn1/branches/asn1-new-ber/ber/src/java/org/apache/asn1/ber/digester/RulesBase.java
URL: http://svn.apache.org/viewcvs/directory/asn1/branches/asn1-new-ber/ber/src/java/org/apache/asn1/ber/digester/RulesBase.java?rev=234313&view=auto
==============================================================================
--- directory/asn1/branches/asn1-new-ber/ber/src/java/org/apache/asn1/ber/digester/RulesBase.java (added)
+++ directory/asn1/branches/asn1-new-ber/ber/src/java/org/apache/asn1/ber/digester/RulesBase.java Sun Aug 21 11:46:27 2005
@@ -0,0 +1,116 @@
+/*
+ *   Copyright 2004 The Apache Software Foundation
+ *
+ *   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.apache.asn1.ber.digester ;
+
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.commons.collections.primitives.IntStack;
+
+
+/**
+ * A base Rules implementation using a fast pattern match.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">
+ * Apache Directory Project</a>
+ * @version $Rev: 157644 $
+ */
+public class RulesBase implements Rules
+{
+    private TagTree tagTree ;
+    private ArrayList rules ;
+    private BERDigester digester ;
+    
+    
+    /**
+     * Creates a base Rules instance.
+     */
+    public RulesBase()
+    {
+        tagTree = new TagTree() ;
+        rules = new ArrayList() ;
+    }
+    
+    
+    /* (non-Javadoc)
+     * @see org.apache.snickers.ber.rulesBase.Rules#setDigester(
+     * org.apache.snickers.ber.rulesBase.BERDigester)
+     */
+    public void setDigester( BERDigester digester )
+    {
+        this.digester = digester ;
+    }
+    
+    
+    /* (non-Javadoc)
+     * @see org.apache.snickers.ber.rulesBase.Rules#getDigester()
+     */
+    public BERDigester getDigester()
+    {
+        return digester ;
+    }
+    
+    
+    /* (non-Javadoc)
+     * @see org.apache.snickers.ber.rulesBase.Rules#add(int[],
+     * org.apache.snickers.ber.rulesBase.Rule)
+     */
+    public void add( int[] pattern, Rule rule )
+    {
+        tagTree.addRule( pattern, rule ) ;
+        rules.add( rule ) ;
+    }
+
+    
+    /* (non-Javadoc)
+     * @see org.apache.snickers.ber.rulesBase.Rules#clear()
+     */
+    public void clear()
+    {
+        tagTree = new TagTree() ;
+        rules.clear() ;
+    }
+    
+
+    /* (non-Javadoc)
+     * @see org.apache.snickers.ber.rulesBase.Rules#match(int[])
+     */
+    public List match( int[] pattern )
+    {
+        return tagTree.match( new IntStack( pattern ) ) ;
+    }
+    
+
+    /* (non-Javadoc)
+     * @see org.apache.snickers.ber.rulesBase.Rules#match(int[])
+     */
+    public List match( IntStack pattern )
+    {
+        return tagTree.match( pattern ) ;
+    }
+    
+
+    /* (non-Javadoc)
+     * @see org.apache.snickers.ber.rulesBase.Rules#rules()
+     */
+    public List rules()
+    {
+        return Collections.unmodifiableList( rules ) ;
+    }
+}

Added: directory/asn1/branches/asn1-new-ber/ber/src/java/org/apache/asn1/ber/digester/TagNode.java
URL: http://svn.apache.org/viewcvs/directory/asn1/branches/asn1-new-ber/ber/src/java/org/apache/asn1/ber/digester/TagNode.java?rev=234313&view=auto
==============================================================================
--- directory/asn1/branches/asn1-new-ber/ber/src/java/org/apache/asn1/ber/digester/TagNode.java (added)
+++ directory/asn1/branches/asn1-new-ber/ber/src/java/org/apache/asn1/ber/digester/TagNode.java Sun Aug 21 11:46:27 2005
@@ -0,0 +1,112 @@
+/*
+ *   Copyright 2004 The Apache Software Foundation
+ *
+ *   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.apache.asn1.ber.digester ;
+
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+
+
+/**
+ * A speed (verses size) optimized data structure to match tag patterns.  
+ * As tuples are pushed and popped off of the decoder's stack and the tag 
+ * nesting path changes this tree is traversed.  A position member of type
+ * TagNode is used to track the current position in this tree.  If the nesting
+ * does not correspond to a valid node then it is null and thus underfined so
+ * no rules are correlated with the position.  When a node is located and set
+ * the rules contained in that node are triggered.
+ *   
+ * @author <a href="mailto:dev@directory.apache.org">
+ * Apache Directory Project</a>
+ * @version $Rev: 157644 $
+ */
+public class TagNode
+{
+    private Integer tag ;
+    private int depth ;
+    private HashMap children = new HashMap( 3 ) ;
+    private ArrayList rules = new ArrayList( 3 ) ;
+    
+    
+    TagNode( Integer tag )
+    {
+        this.tag = tag ;
+    }
+    
+    
+    void addNode( TagNode node )
+    {
+        children.put( node.getTag(), node ) ;
+        node.setDepth( depth + 1 ) ;
+    }
+    
+    
+    void addRule( Rule rule )
+    {
+        rules.add( rule ) ;
+    }
+    
+    
+    void setDepth( int depth )
+    {
+        this.depth = depth ;
+    }
+    
+    
+    public Integer getTag() 
+    {
+        return tag ;
+    }
+    
+    
+    public int getDepth()
+    {
+        return depth ;
+    }
+    
+    
+    public List getRules()
+    {
+        return rules ;
+    }
+    
+    
+    public boolean hasChild( Integer tag )
+    {
+        return children.containsKey( tag ) ;
+    }
+
+
+    public boolean isLeaf()
+    {
+        return children.isEmpty() ;
+    }
+
+
+    public Iterator getChildren()
+    {
+        return children.values().iterator() ;
+    }
+
+
+    public TagNode getChild( Integer tag )
+    {
+        return ( TagNode ) children.get( tag ) ;
+    }
+}

Added: directory/asn1/branches/asn1-new-ber/ber/src/java/org/apache/asn1/ber/digester/TagTree.java
URL: http://svn.apache.org/viewcvs/directory/asn1/branches/asn1-new-ber/ber/src/java/org/apache/asn1/ber/digester/TagTree.java?rev=234313&view=auto
==============================================================================
--- directory/asn1/branches/asn1-new-ber/ber/src/java/org/apache/asn1/ber/digester/TagTree.java (added)
+++ directory/asn1/branches/asn1-new-ber/ber/src/java/org/apache/asn1/ber/digester/TagTree.java Sun Aug 21 11:46:27 2005
@@ -0,0 +1,629 @@
+/*
+ *   Copyright 2004 The Apache Software Foundation
+ *
+ *   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.apache.asn1.ber.digester ;
+
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Stack;
+
+import org.apache.commons.collections.primitives.IntStack;
+import org.apache.commons.lang.Validate;
+
+
+/**
+ * A disjointed tree of tag patterns with and without wild cards.
+ *
+ * @todo find and start using a hash table keyed by primitive int instead of
+ * an Integer
+ *
+ * @author <a href="mailto:dev@directory.apache.org">
+ * Apache Directory Project</a>
+ * @version $Rev: 157644 $
+ */
+public class TagTree
+{
+    /** the wild card tag value as an integer = UNIVERSAL 2,097,151 (2^21-1) */
+    public static final int WILDCARD = 0x1FFFFFFF ;
+
+    /** a map of tag nodes for normal patterns */
+    private HashMap normNodes = new HashMap( 3 ) ;
+    /** a map of tag nodes for wild carded patterns */
+    private HashMap wildNodes = new HashMap( 3 ) ;
+    /** the list of normal rule regs with rule and pattern in order */
+    private ArrayList normRegistrations = new ArrayList() ;
+    /** the list of wild carded rule regs with rule and pattern in order */
+    private ArrayList wildRegistrations = new ArrayList() ;
+
+
+    // ------------------------------------------------------------------------
+    // Methods used to add rules to trees
+    // ------------------------------------------------------------------------
+
+
+    /**
+     * Adds a Rule to this TagTree in a manner based on whether the pattern
+     * contains a wild card in front or not.
+     *
+     * @param pattern the pattern of nested tags
+     * @param rule the rule to add for the pattern
+     */
+    public void addRule( int[] pattern, Rule rule )
+    {
+        if ( pattern[0] == WILDCARD )
+        {
+            wildRegistrations.add( new RuleRegistration( pattern, rule ) ) ;
+            addWildRule( pattern, rule ) ;
+        }
+        else
+        {
+            normRegistrations.add( new RuleRegistration( pattern, rule ) ) ;
+            addNormalRule( pattern, rule ) ;
+        }
+    }
+
+
+    /**
+     * Adds a Rule to this TagTree.
+     * 
+     * @param pattern the pattern of nested tags
+     * @param rule the rule to add for the pattern
+     */
+    private void addNormalRule( int[] pattern, Rule rule )
+    {
+        Integer tag = null ;
+        TagNode node = null ;
+        Stack stack = new Stack() ;
+
+        Validate.notNull( rule, "cannot add null rule" ) ;
+        Validate.notNull( pattern, "cannot add rule with null pattern" ) ;
+        Validate.isTrue( pattern.length > 0, 
+                "cannot add rule with empty pattern" ) ;
+
+        tag = new Integer( pattern[0] ) ;
+        if ( normNodes.containsKey( tag ) )
+        {
+            node = ( TagNode ) normNodes.get( tag ) ;
+            stack.push( node.getTag() ) ;
+        }
+        else
+        {
+            node = new TagNode( tag ) ;
+            normNodes.put( tag, node ) ;
+            stack.push( node.getTag() ) ;
+            addWildRulesToNewNormalNode( node, stack ) ;
+        }
+        
+        for ( int ii = 1; ii < pattern.length; ii++ )
+        {    
+            Integer childTag = new Integer( pattern[ii] ) ;
+            TagNode childNode = node.getChild( childTag ) ;
+            
+            if ( childNode == null )
+            {
+                childNode = new TagNode( childTag ) ;
+                node.addNode( childNode ) ;
+                stack.push( childNode.getTag() ) ;
+                addWildRulesToNewNormalNode( childNode, stack ) ;
+            }
+            else
+            {
+                stack.push( childNode.getTag() ) ;
+            }
+
+            node = childNode ;
+            tag = childTag ;
+        }
+        
+        node.addRule( rule ) ;
+    }
+
+
+    /**
+     * Adds a Rule using a pattern with a wild card in front to this TagTree.
+     *
+     * @param pattern the pattern of nested tags with starting wild card
+     * @param rule the rule to add for the pattern
+     */
+    private void addWildRule( int[] pattern, Rule rule )
+    {
+        Validate.notNull( pattern,
+                "Attempting to register rule " + rule
+                + " with null pattern" ) ;
+        Validate.isTrue( pattern.length > 0,
+                "Attempting to register rule " + rule
+                + " with zero length pattern" ) ;
+        Validate.isTrue( pattern[0] == WILDCARD,
+                "Expected rule " + rule
+                + " pattern to have front wild card but it did not" ) ;
+        Validate.isTrue( pattern.length > 1,
+                "Cannot register only wild card \"*\" pattern for rule "
+                + rule ) ;
+
+        /*
+         * Adds the rule associated with the registration to the normal tag
+         * tree which involves a recursive descent on the normal tree.
+         */
+        TagNode node = null ;
+        Iterator list = normNodes.values().iterator() ;
+        while ( list.hasNext() )
+        {
+            node = ( TagNode ) list.next() ;
+            addWildRuleToNormalTree( pattern, rule, new Stack(), node ) ;
+        }
+
+        /*
+         * first just lay down the new branch without adding the rule
+         * next do a recursive drilldown testing for rule addition to all nodes
+         */
+        Integer tag = new Integer( pattern[pattern.length-1] ) ;
+        if ( wildNodes.containsKey( tag ) )
+        {
+            node = ( TagNode ) wildNodes.get( tag ) ;
+        }
+        else
+        {
+            node = new TagNode( tag ) ;
+            wildNodes.put( tag, node ) ;
+        }
+
+        for( int ii = pattern.length - 2; ii >= 1; ii-- )
+        {
+            Integer childTag = new Integer( pattern[ii] ) ;
+            TagNode childNode = node.getChild( childTag ) ;
+
+            if ( childNode == null )
+            {
+                childNode = new TagNode( childTag ) ;
+                node.addNode( childNode ) ;
+            }
+
+            node = childNode ;
+            tag = childTag ;
+        }
+
+        /*
+         * Recusively drill down each branch of the wild tree checking at each
+         * node to see if we need to add the new rule based on the pattern
+         */
+        list = wildNodes.values().iterator() ;
+        while( list.hasNext() )
+        {
+            node = ( TagNode ) list.next() ;
+            addWildRuleToWildTree( pattern, rule, new Stack(), node ) ;
+        }
+    }
+
+
+    /**
+     * Adds wild carded rules to new nodes being added to the tag tree with
+     * normal patterns without wild cards.
+     *
+     * @param node the new node added to the tree of normal tags
+     * @param stack a stack of nodes encountered while walking the tree
+     */
+    private void addWildRulesToNewNormalNode( TagNode node, Stack stack )
+    {
+        for ( int jj = 0; jj < wildRegistrations.size(); jj++ )
+        {
+            RuleRegistration reg = ( RuleRegistration )
+                    wildRegistrations.get( jj ) ;
+
+            if ( isTailMatch( reg.getPattern(), stack ) )
+            {
+                node.addRule( reg.getRule() ) ;
+            }
+        }
+    }
+
+
+    /**
+     * Adds rules registered via wild cards to the wild TagTree to all
+     * nodes matching the pattern.  This method performs depth first recursion
+     * building a stack of TagNodes as dives into the TagTree.  At each point
+     * the pattern with the wild card is tested against the contents of the
+     * stack to see if it matches the nesting pattern, if it does then the
+     * rule is added to the current node.
+     *
+     * @param pattern the matching pattern with front wild card
+     * @param rule the rule registered with the pattern
+     * @param stack the stack storing the depth first nesting pattern
+     * @param node the current node scrutinized for a match by the pattern, and
+     * the current position of the depth first search
+     */
+    private void addWildRuleToWildTree( int[] pattern, Rule rule,
+                                        Stack stack, TagNode node )
+    {
+        stack.push( node.getTag() ) ;
+
+        if ( isReverseTailMatch( pattern, stack ) )
+        {
+            if ( ! node.getRules().contains( rule ) )
+            {
+                node.addRule( rule ) ;
+            }
+        }
+
+        if ( ! node.isLeaf() )
+        {
+            Iterator children = node.getChildren() ;
+            while( children.hasNext() )
+            {
+                addWildRuleToWildTree( pattern, rule, stack,
+                        ( TagNode ) children.next() ) ;
+            }
+        }
+
+        stack.pop() ;
+    }
+
+
+    /**
+     * Called by depth first search used to add rules of wild card patterns to
+     * the wild TagTree.  This method compares a stack of Integers to a
+     * pattern.  The stack must have as many or more than pattern.length - 1
+     * elements to match.  Elements from the second element of the pattern to
+     * the last element are compared with the bottom stack element up to the
+     * top.  This is the reverse order because of the inverse paths in the
+     * pattern tree with wild cards.
+     *
+     * @param pattern the pattern with a wild card at position 0
+     * @param stack the nesting stack representing the depth first search path
+     * @return true if the elements [n-1] in the pattern match the bottom most
+     * elements in the stack where n+1 is length of the pattern array.
+     */
+    private boolean isReverseTailMatch( int[] pattern, Stack stack )
+    {
+        if ( stack.size() < pattern.length - 1 )
+        {
+            return false ;
+        }
+
+        for( int ii = pattern.length - 1, jj = 0 ; ii >= 1; ii--, jj++ )
+        {
+            if ( pattern[ii] != ( ( Integer ) stack.get( jj ) ).intValue() )
+            {
+                return false ;
+            }
+        }
+
+        return true ;
+    }
+
+
+    /**
+     * Adds rules registered via wild cards to the nodes within a branch of the
+     * normal TagTree.  All nodes matching the pattern with wild cards has the
+     * rule added to it.  This method performs depth first recursion building
+     * a stack of TagNodes as it dives into the TagTree.  At each point the
+     * pattern with the wild card is tested against the contents of the
+     * stack to see if it matches the nesting pattern, if it does then the
+     * rule is added to the current node.
+     *
+     * @param pattern the matching pattern with front wild card
+     * @param rule the rule registered with the pattern
+     * @param stack the stack storing the depth first nesting pattern
+     * @param node the current node scrutinized for a match by the pattern, and
+     * the current position of the depth first search
+     */
+    private void addWildRuleToNormalTree( int[] pattern, Rule rule,
+                                          Stack stack, TagNode node )
+    {
+        stack.push( node.getTag() ) ;
+
+        if ( isTailMatch( pattern, stack ) && node.isLeaf() )
+        {
+            if ( ! node.getRules().contains( rule ) )
+            {
+                node.addRule( rule ) ;
+            }
+        }
+
+        if ( ! node.isLeaf() )
+        {
+            Iterator children = node.getChildren() ;
+            while( children.hasNext() )
+            {
+                addWildRuleToNormalTree( pattern, rule, stack,
+                        ( TagNode ) children.next() ) ;
+            }
+        }
+
+        stack.pop() ;
+    }
+
+
+    /**
+     * Called by depth first search used to add rules of wild card patterns to
+     * the normal TagTree.  This method compares a stack of Integers to a
+     * pattern.  The stack must have as many or more than pattern.length - 1
+     * elements to match.  From the tail of the pattern to the second element
+     * is compared with the topmost stack element down.
+     *
+     * @param pattern the pattern with a wild card at position 0
+     * @param stack the nesting stack representing the depth first search path
+     * @return true if the elements [n-1] in the pattern match the topmost
+     * elements in the stack where n+1 is length of the pattern array.
+     */
+    private boolean isTailMatch( int[] pattern, Stack stack )
+    {
+        if ( stack.size() < pattern.length - 1 )
+        {
+            return false ;
+        }
+
+        for( int ii = pattern.length - 1, jj = stack.size() - 1; ii >= 1;
+             ii--, jj-- )
+        {
+            if ( pattern[ii] != ( ( Integer ) stack.get( jj ) ).intValue() )
+            {
+                return false ;
+            }
+        }
+
+        return true ;
+    }
+
+
+    // ------------------------------------------------------------------------
+    // Methods used for matching a stack or a int[]
+    // ------------------------------------------------------------------------
+
+
+    public List match( IntStack stack )
+    {
+        TagNode node = getNode( stack ) ;
+        
+        if ( node == null )
+        {
+            return Collections.EMPTY_LIST ;
+        }
+        
+        return node.getRules() ;
+    }
+    
+    
+    public TagNode getNode( IntStack stack )
+    {
+        TagNode node = getNormalNode( stack ) ;
+
+        if ( node == null )
+        {
+            node = getWildNode( stack ) ;
+        }
+
+        return node ;
+    }
+
+
+    public List match( int[] pattern )
+    {
+        TagNode node = getNode( pattern ) ;
+
+        if ( node == null )
+        {
+            return Collections.EMPTY_LIST ;
+        }
+
+        return node.getRules() ;
+    }
+
+
+    public TagNode getNode( int[] pattern )
+    {
+        TagNode node = getNormalNode( pattern ) ;
+
+        if ( node == null )
+        {
+            node = getWildNode( pattern ) ;
+        }
+
+        return node ;
+    }
+
+
+    private TagNode getNormalNode( IntStack stack )
+    {
+        Integer tag = null ;
+        TagNode node = null ;
+
+        Validate.notNull( stack, "cannot match using null pattern" ) ;
+        Validate.isTrue( !stack.empty(), "cannot match with empty pattern" ) ;
+
+        tag = new Integer( stack.get( 0 ) ) ;
+        if ( normNodes.containsKey( tag ) )
+        {
+            node = ( TagNode ) normNodes.get( tag ) ;
+        }
+        else
+        {
+            return null ;
+        }
+        
+        for ( int ii = 1; ii < stack.size(); ii++ )
+        {    
+            Integer childTag = new Integer( stack.get( ii ) ) ;
+            TagNode childNode = node.getChild( childTag ) ;
+            
+            if ( childNode == null )
+            {
+                return null ;
+            }
+            
+            node = childNode ;
+            tag = childTag ;
+        }
+        
+        return node ;
+    }
+
+
+    private TagNode getNormalNode( int[] pattern )
+    {
+        Integer tag = null ;
+        TagNode node = null ;
+
+        Validate.notNull( pattern, "cannot match using null pattern" ) ;
+        Validate.isTrue( pattern.length > 0, 
+                "cannot match with empty pattern" ) ;
+
+        tag = new Integer( pattern[0] ) ;
+        if ( normNodes.containsKey( tag ) )
+        {
+            node = ( TagNode ) normNodes.get( tag ) ;
+        }
+        else
+        {
+            return null ;
+        }
+        
+        for ( int ii = 1; ii < pattern.length; ii++ )
+        {    
+            Integer childTag = new Integer( pattern[ii] ) ;
+            TagNode childNode = node.getChild( childTag ) ;
+            
+            if ( childNode == null )
+            {
+                return null ;
+            }
+            
+            node = childNode ;
+            tag = childTag ;
+        }
+        
+        return node ;
+    }
+
+
+    /**
+     * Gets a node matching a pattern with a wild card from this TagTree.
+     *
+     * @param pattern the wild card pattern as an int array
+     * @return the matching wild card node if any
+     */
+    private TagNode getWildNode( int[] pattern )
+    {
+        Integer tag = null ;
+        TagNode node = null ;
+
+        /*
+         * Restrict empty pattern, and zero length patterns.
+         */
+        Validate.notNull( pattern,
+                "cannot match using null pattern" ) ;
+        Validate.isTrue( pattern.length > 0,
+                "cannot match with empty pattern" ) ;
+
+        /*
+         * Begin reverse walk by looking up the node corresponding
+         * to the last pattern element.  Return null if it does not exit.
+         */
+        tag = new Integer( pattern[pattern.length - 1] ) ;
+        if ( wildNodes.containsKey( tag ) )
+        {
+            node = ( TagNode ) wildNodes.get( tag ) ;
+        }
+        else
+        {
+            return null ;
+        }
+
+        /*
+         * Walk using the second to last [pattern.length-2] element down to
+         * the first element at index 0 in the pattern.
+         */
+        for ( int ii = pattern.length-2; ii >= 0; ii-- )
+        {
+            Integer childTag = new Integer( pattern[ii] ) ;
+            TagNode childNode = node.getChild( childTag ) ;
+
+            /*
+             * If no more children are present and we're about to walk off of
+             * the tree then we return the last node we have seen here.
+             */
+            if ( childNode == null )
+            {
+                return node ;
+            }
+
+            node = childNode ;
+            tag = childTag ;
+        }
+
+        return node ;
+    }
+
+
+    /**
+     * Gets a node matching a pattern with a wild card from this TagTree.
+     *
+     * @param stack the wild card pattern as a stack
+     * @return the matching wild card node if any
+     */
+    private TagNode getWildNode( IntStack stack )
+    {
+        Integer tag = null ;
+        TagNode node = null ;
+
+        /*
+         * Restrict empty pattern, and zero length patterns.
+         */
+        Validate.notNull( stack, "cannot match using null pattern" ) ;
+        Validate.isTrue( !stack.empty(), "cannot match with empty pattern" ) ;
+
+        /*
+         * Begin reverse walk by looking up the node corresponding
+         * to the bottom stack element.  Return null if it does not exit.
+         */
+        tag = new Integer( stack.get( stack.size() - 1 ) ) ;
+        if ( wildNodes.containsKey( tag ) )
+        {
+            node = ( TagNode ) wildNodes.get( tag ) ;
+        }
+        else
+        {
+            return null ;
+        }
+
+        /*
+         * Walk using the element above the bottom [stack.size()-2] up to
+         * the top element at index 0 in the stack.
+         */
+        for ( int ii = stack.size() - 2; ii >= 0; ii-- )
+        {
+            Integer childTag = new Integer( stack.get( ii ) ) ;
+            TagNode childNode = node.getChild( childTag ) ;
+
+            /*
+             * If no more children are present and we're about to walk off of
+             * the tree then we return the last node we have seen here.
+             */
+            if ( childNode == null )
+            {
+                return node ;
+            }
+
+            node = childNode ;
+            tag = childTag ;
+        }
+
+        return node ;
+    }
+}



Mime
View raw message