directory-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From akaras...@apache.org
Subject svn commit: rev 9724 - in incubator/directory/snickers/trunk: ber/src/java/org/apache/snickers/asn ber/src/java/org/apache/snickers/ber codec-stateful/src/java/org/apache/commons/codec/stateful codec-stateful/src/test codec-stateful/src/test/org codec-stateful/src/test/org/apache codec-stateful/src/test/org/apache/commons codec-stateful/src/test/org/apache/commons/codec codec-stateful/src/test/org/apache/commons/codec/stateful xdocs xdocs/ber-codec xdocs/codec-stateful xdocs/images xdocs/stub-compiler
Date Wed, 24 Mar 2004 00:00:23 GMT
Author: akarasulu
Date: Tue Mar 23 16:00:22 2004
New Revision: 9724

Added:
   incubator/directory/snickers/trunk/codec-stateful/src/java/org/apache/commons/codec/stateful/DecoderStack.java
  (contents, props changed)
   incubator/directory/snickers/trunk/codec-stateful/src/java/org/apache/commons/codec/stateful/package.html
  (contents, props changed)
   incubator/directory/snickers/trunk/codec-stateful/src/test/
   incubator/directory/snickers/trunk/codec-stateful/src/test/org/
   incubator/directory/snickers/trunk/codec-stateful/src/test/org/apache/
   incubator/directory/snickers/trunk/codec-stateful/src/test/org/apache/commons/
   incubator/directory/snickers/trunk/codec-stateful/src/test/org/apache/commons/codec/
   incubator/directory/snickers/trunk/codec-stateful/src/test/org/apache/commons/codec/stateful/
   incubator/directory/snickers/trunk/codec-stateful/src/test/org/apache/commons/codec/stateful/DecoderStackTest.java
  (contents, props changed)
   incubator/directory/snickers/trunk/xdocs/codec-stateful/
   incubator/directory/snickers/trunk/xdocs/codec-stateful/index.xml   (contents, props changed)
   incubator/directory/snickers/trunk/xdocs/codec-stateful/navigation.xml   (contents, props
changed)
   incubator/directory/snickers/trunk/xdocs/images/
Modified:
   incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/asn/Primitive.java
   incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/ber/package.html
   incubator/directory/snickers/trunk/codec-stateful/src/java/org/apache/commons/codec/stateful/CallbackHistory.java
   incubator/directory/snickers/trunk/codec-stateful/src/java/org/apache/commons/codec/stateful/DecoderCallback.java
   incubator/directory/snickers/trunk/xdocs/ber-codec/design.xml
   incubator/directory/snickers/trunk/xdocs/ber-codec/navigation.xml
   incubator/directory/snickers/trunk/xdocs/navigation.xml
   incubator/directory/snickers/trunk/xdocs/stub-compiler/navigation.xml
Log:
Added documentation and extra DecoderStack class for chaining decoders as 
well as a test case for it.


Modified: incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/asn/Primitive.java
==============================================================================
--- incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/asn/Primitive.java
(original)
+++ incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/asn/Primitive.java
Tue Mar 23 16:00:22 2004
@@ -58,11 +58,36 @@
  * @version $Rev$
  */
 public interface Primitive {
-    public final int BOOLEAN = 1;
-    public final int INTEGER = 2;
-    public final int BITSTRING = 3;
-    public final int OCTETSTRING = 4;
-    public final int NULL = 5;
-    public final int OBJECTIDENTIFIER = 6;
-    public final int ENUMERATION = 10;
+    public final int RESERVED0 = 1 ;
+    public final int BOOLEAN = 1 ;
+    public final int INTEGER = 2 ;
+    public final int BITSTRING = 3 ;
+    public final int OCTETSTRING = 4 ;
+    public final int NULL = 5 ;
+    public final int OBJECTIDENTIFIER = 6 ;
+    public final int OBJECTDESCRIPTOR = 7 ;
+    public final int EXTERNALINSTANCEOF = 8 ;
+    public final int REAL = 9 ;
+    public final int ENUMERATION = 10 ;
+    public final int EMBEDDEDPDV = 11 ;
+    public final int UTF8STRING = 12 ;
+    public final int RELATIVEOID = 13 ;
+    public final int RESERVED1 = 14 ;
+    public final int RESERVED2 = 15 ;
+    public final int SEQUENCEOF = 16 ;
+    public final int SETOF = 17 ;
+    public final int NUMERICSTRING = 18 ;
+    public final int PRINTABLESTRING = 19 ;
+    public final int TELETEXSTRING = 20 ;
+    public final int VIDEOTEXSTRING = 21 ;
+    public final int IA5STRING = 22 ;
+    public final int UTCTIME = 23 ;
+    public final int GENERALIZEDTIME = 24 ;
+    public final int GRAPHICSTRING = 25 ;
+    public final int VISIBLESTRING = 26 ;
+    public final int GENERALSTRING = 27 ;
+    public final int UNIVERSALSTRING = 28 ;
+    public final int CHARACTERSTRING = 29 ;
+    public final int BMPSTRING = 30 ;
+    public final int RESERVED3 = 31 ;
 }

Modified: incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/ber/package.html
==============================================================================
--- incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/ber/package.html	(original)
+++ incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/ber/package.html	Tue
Mar 23 16:00:22 2004
@@ -1,40 +1,43 @@
-<p>
-  The decoder must be aware of it's current state.  The following states are
-  possible in between TLV tuples:
-</p>  
-<ol>
-  <li>
-    Composing Tag - The decoder starts in this mode.  This is the mode for
-    collecting bytes for the Tag of the TLV in scope.  Bytes are copied into
-    a temporary Tag byte buffer until the Tag data is complete.  Once the 
-    bytes are complete and the Tag int is generated along with a couple of other
-    values (boolean isPrimitive and TypeClassEnum), the Tag byte buffer is
-    cleared and the state switches to the composing length state.  If the Tag
-    data is incomplete and not available until the next chunk of data arrives
-    via another decode call, we remain suspended in this state collecting the 
-    tag bytes.  There are no pushes onto any of the stacks during this state.
-  </li>
-  <li>
-    Composing Length - The decoder starts reading data into a Length byte 
-    buffer until the Length data is complete whether the length data is the 
-    short, long or indeterminate form.  Once the bytes for the length are arrive
-    and the Length int is generated, the Length byte buffer is cleared.  If
-    the Tag represents a primitive type the state switches to the composing 
-    value state.  If the TLV is constructed, the tag and the length are pushed 
-    onto their respective stacks.  The state then switches to the composing Tag
-    state.  If the length data is incomplete and not available until the next 
-    chunk of data arrives via another decode call, we remain suspended in this 
-    state.
-  </li>
-  <li>
-    Composing Value - The decoder is in this mode because the TLV is 
-    primitive.  In this state only two forms of length are valid: the short
-    and long lengths.  In either case we just read the number of bytes 
-    specified for the length during the length composing state.  If the value
-    data is incomplete and not avaiable until the next chunk of data arrives
-    via another decode call we remain suspended in this state.  We transit
-    to the composing Tag state from this state when the value data arrives.
-    Before transiting to the composing Tag state the stacks are popped and
-    the TLV is delivered as a completion event to the callback.
-  </li>
-</ol>
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<!--
+ *   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.
+-->
+</head>
+<body bgcolor="white">
+
+Provides the codec foundation for Basic Encoding Rules based on a Tag, Length 
+and Value (TLV) field tuple.
+
+
+<h2>Package Specification</h2>
+
+<ul>
+  <li><a href="">##### REFER TO ANY FRAMEMAKER SPECIFICATION HERE #####</a>
+</ul>
+
+<h2>Related Documentation</h2>
+
+For overviews, tutorials, examples, guides, and tool documentation, please see:
+<ul>
+  <li><a href="http://incubator.apache.org/directory/subprojects/snickers/index.html">Snickers
Project</a>
+  <li><a href="http://incubator.apache.org/directory/subprojects/snickers/ber-codec/index.html">Snickers
BER Codecs</a>
+</ul>
+
+<!-- Put @see and @since tags down here. -->
+
+</body>
+</html>

Modified: incubator/directory/snickers/trunk/codec-stateful/src/java/org/apache/commons/codec/stateful/CallbackHistory.java
==============================================================================
--- incubator/directory/snickers/trunk/codec-stateful/src/java/org/apache/commons/codec/stateful/CallbackHistory.java
(original)
+++ incubator/directory/snickers/trunk/codec-stateful/src/java/org/apache/commons/codec/stateful/CallbackHistory.java
Tue Mar 23 16:00:22 2004
@@ -23,7 +23,8 @@
 /**
  * A convenience callback which collects decoded objects to audit a decoder's 
  * activity.  The callback also comes in handy when data is to be pushed 
- * through a decoder and grabed immediately afterwords.
+ * through a decoder and grabed immediately afterwords to serialize decoder
+ * operation.
  *
  * @author <a href="mailto:directory-dev@incubator.apache.org">
  * Apache Directory Project</a>
@@ -37,6 +38,15 @@
     private final int length ;
     
 
+    /**
+     * Creates an auditing callback that manages a history of indefinate length.
+     */
+    public CallbackHistory()
+    {
+        this( -1 ) ;
+    }
+    
+    
     /**
      * Creates an auditing callback that manages a history of fixed or 
      * indefinate length.  If the length is fixed the history effectively 

Modified: incubator/directory/snickers/trunk/codec-stateful/src/java/org/apache/commons/codec/stateful/DecoderCallback.java
==============================================================================
--- incubator/directory/snickers/trunk/codec-stateful/src/java/org/apache/commons/codec/stateful/DecoderCallback.java
(original)
+++ incubator/directory/snickers/trunk/codec-stateful/src/java/org/apache/commons/codec/stateful/DecoderCallback.java
Tue Mar 23 16:00:22 2004
@@ -16,6 +16,7 @@
  */
 package org.apache.commons.codec.stateful ;
 
+
 /**
  * Callback interface for stateful decoder callbacks.
  *

Added: incubator/directory/snickers/trunk/codec-stateful/src/java/org/apache/commons/codec/stateful/DecoderStack.java
==============================================================================
--- (empty file)
+++ incubator/directory/snickers/trunk/codec-stateful/src/java/org/apache/commons/codec/stateful/DecoderStack.java
Tue Mar 23 16:00:22 2004
@@ -0,0 +1,214 @@
+/*
+ *   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.commons.codec.stateful ;
+
+
+import java.util.Stack ;
+
+import org.apache.commons.codec.DecoderException ;
+
+
+/**
+ * A stack of decoders used for the additive application of multiple decoders 
+ * forming a linear staged decoder pipeline.
+ *
+ * @author <a href="mailto:directory-dev@incubator.apache.org">
+ * Apache Directory Project</a>
+ * @version $Rev$
+ */
+public class DecoderStack extends AbstractStatefulDecoder
+{
+    /** 
+     * the top decoder callback which calls this decoders callback
+     * @todo determine if this is even necessary - can't we just use cb   
+     */
+    private final DecoderCallback topcb ;
+    /** a stack of StatefulDecoders */
+    private Stack decoders = new Stack() ;
+    
+    
+    /**
+     * Creates an empty stack of chained decoders. 
+     */
+    public DecoderStack()
+    {
+        topcb = new DecoderCallback()
+        {
+            public void decodeOccurred( StatefulDecoder decoder,Object decoded )
+            {
+                DecoderStack.this.decodeOccurred( decoded ) ;
+            }
+        };
+    }
+    
+    
+    /**
+     * Pushs a new terminal decoder onto the top of this DecoderStack.  The 
+     * old top decoder is chained to feed its decoded object to the new top
+     * decoder.  The new pushed decoder will report decode events to this
+     * DecoderStacks callback.
+     * 
+     * @param decoder the terminal decoder to push onto this stack
+     */
+    public synchronized void push( StatefulDecoder decoder )
+    {
+        decoder.setCallback( topcb ) ;
+
+        if( ! decoders.isEmpty() )
+        {
+            StatefulDecoder top = ( StatefulDecoder ) decoders.peek() ;
+            ChainingCallback chaining = new ChainingCallback( top, decoder ) ;
+            top.setCallback( chaining ) ;
+        }
+        
+        decoders.push( decoder ) ;
+    }
+    
+    
+    /**
+     * Pops the terminal decoder off of this DecoderStack.  The popped decoder
+     * has its callback cleared.  If the stack is empty nothing happens and this
+     * StatefulDecoder, the DecoderStack, is returned to protect against null.
+     * 
+     * @return the top decoder that was popped, or this DecoderStack
+     */
+    public synchronized StatefulDecoder pop()
+    {
+        if ( decoders.isEmpty() )
+        {
+            return this ;
+        }
+        
+        StatefulDecoder popped = ( StatefulDecoder ) decoders.pop() ;
+        popped.setCallback( null ) ;
+        
+        if ( ! decoders.isEmpty() )
+        {
+            StatefulDecoder top = ( StatefulDecoder ) decoders.peek() ;
+            top.setCallback( this.topcb ) ;
+        }
+        
+        return popped ;
+    }
+
+    
+    /**
+     * Decodes an encoded object by calling decode on the decoder at the bottom
+     * of the stack.  Callbacks are chained to feed the output of one decoder
+     * into the input decode method of another.  If the stack is empty then the
+     * arguement is delivered without change to this StatefulDecoder's callback.
+     * 
+     * @see org.apache.commons.codec.stateful.StatefulDecoder#
+     * decode(java.lang.Object)
+     */
+    public synchronized void decode( Object encoded ) throws DecoderException
+    {
+        if ( decoders.isEmpty() )
+        {
+            decodeOccurred( encoded ) ;
+            return ;
+        }
+        
+        ( ( StatefulDecoder ) decoders.get( 0 ) ).decode( encoded ) ;
+    }
+    
+    
+    /**
+     * Gets whether or not this stack is empty.
+     * 
+     * @return true if the stack is empty, false otherwise
+     */
+    public boolean isEmpty()
+    {
+        return decoders.isEmpty() ;
+    }
+    
+    
+    /**
+     * Clears the stack popping all decoders setting their callbacks to null.
+     */
+    public synchronized void clear()
+    {
+        while ( ! decoders.isEmpty() )
+        {
+            pop() ;
+        }
+    }
+    
+    
+    /**
+     * A callback used to chain decoders.
+     *
+     * @author <a href="mailto:directory-dev@incubator.apache.org">
+     * Apache Directory Project</a>
+     * @version $Rev$
+     */
+    class ChainingCallback implements DecoderCallback
+    {
+        /** the source decoder calling this callback */
+        private StatefulDecoder sink ;
+        /** the sink decoder recieving the src's decoded object */
+        private StatefulDecoder src ;
+        
+        /**
+         * Creates a callback that chains the output of a src decoder to the 
+         * input of a sink decoder.  No side-effects occur like setting the 
+         * callback of the src so this ChainingCallback must be set explicity
+         * as the src decoders callback.
+         * 
+         * @param src the source decoder calling this callback
+         * @param sink the sink decoder recieving the src's decoded object
+         */
+        ChainingCallback( StatefulDecoder src, StatefulDecoder sink )
+        {
+            this.src = src ;
+            this.sink = sink ;
+        }
+        
+        
+        /**
+         * Calls the {@link decode(Object)} method of the sink if the decoder 
+         * argument is the source.  Any failures that occur during the sink's 
+         * decode operation are reported to the monitor first then rethrown as
+         * runtime exceptions with the root cause set to the faulting exception.
+         * 
+         * @see org.apache.commons.codec.stateful.DecoderCallback#decodeOccurred
+         * (org.apache.commons.codec.stateful.StatefulDecoder, java.lang.Object)
+         */
+        public void decodeOccurred( StatefulDecoder decoder, Object decoded )
+        {
+            if ( decoder != src )
+            {
+                return ;
+            }
+            
+            try
+            {
+                sink.decode( decoded ) ;
+            }
+            catch( DecoderException e )
+            {
+                if ( getDecoderMonitor() != null )
+                {    
+                    getDecoderMonitor().fatalError( DecoderStack.this, e ) ;
+                }
+                
+                throw new RuntimeException( e ) ;
+            }
+        }
+    }
+}

Added: incubator/directory/snickers/trunk/codec-stateful/src/java/org/apache/commons/codec/stateful/package.html
==============================================================================
--- (empty file)
+++ incubator/directory/snickers/trunk/codec-stateful/src/java/org/apache/commons/codec/stateful/package.html
Tue Mar 23 16:00:22 2004
@@ -0,0 +1,43 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<!--
+ *   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.
+-->
+</head>
+<body bgcolor="white">
+
+Provides the fundamental stateful codec interfaces.
+
+
+<h2>Package Specification</h2>
+
+<ul>
+  <li><a href="">##### REFER TO ANY SPECIFICATIONS HERE #####</a>
+</ul>
+
+<h2>Related Documentation</h2>
+
+For overviews, tutorials, examples, guides, and tool documentation, please see:
+<ul>
+  <li><a href="http://incubator.apache.org/directory/subprojects/snickers/index.html">Snickers
Project</a>
+  <li><a href="http://incubator.apache.org/directory/subprojects/snickers/codec-stateful/index.html">Stateful
Codecs</a>
+  <li><a href="http://incubator.apache.org/directory/subprojects/snickers/ber-codec/index.html">Snickers
BER Codecs</a>
+</ul>
+
+<!-- Put @see and @since tags down here. -->
+
+</body>
+</html>

Added: incubator/directory/snickers/trunk/codec-stateful/src/test/org/apache/commons/codec/stateful/DecoderStackTest.java
==============================================================================
--- (empty file)
+++ incubator/directory/snickers/trunk/codec-stateful/src/test/org/apache/commons/codec/stateful/DecoderStackTest.java
Tue Mar 23 16:00:22 2004
@@ -0,0 +1,235 @@
+/*
+ *   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.commons.codec.stateful ;
+
+
+import org.apache.commons.codec.DecoderException ;
+
+import junit.framework.TestCase ;
+
+
+/**
+ * Tests the DecoderStack.
+ *
+ * @author <a href="mailto:directory-dev@incubator.apache.org">
+ * Apache Directory Project</a>
+ * @version $Rev$
+ */
+public class DecoderStackTest extends TestCase
+{
+    /**
+     * Constructor for DecoderStackTest.
+     * @param arg0
+     */
+    public DecoderStackTest( String arg0 )
+    {
+        super( arg0 ) ;
+    }
+
+    
+    /**
+     * Tests the push method.
+     */
+    public void testPush()
+    {
+        DecoderStack stack = new DecoderStack() ;
+        assertNotNull( stack ) ;
+        assertTrue( "expecting empty stack after creation", stack.isEmpty() ) ;
+        PassThroDecoder decoder = new PassThroDecoder() ;
+        stack.push( decoder ) ;
+        assertFalse( "expecting non-empty stack after push", stack.isEmpty() ) ;
+    }
+
+    
+    /**
+     * Tests the pop method.
+     */
+    public void testPop()
+    {
+        DecoderStack stack = new DecoderStack() ;
+        assertNotNull( stack ) ;
+        assertTrue( "expecting empty stack after creation", stack.isEmpty() ) ;
+        PassThroDecoder decoder = new PassThroDecoder() ;
+        stack.push( decoder ) ;
+        assertFalse( "expecting non-empty stack after push", stack.isEmpty() ) ;
+        StatefulDecoder popped = stack.pop() ;
+        assertTrue( "expecting empty stack after last pop", stack.isEmpty() ) ;
+        assertNotNull( popped ) ;
+        assertSame( "expecting last popped == last pushed", popped, decoder ) ;
+        StatefulDecoder empty = stack.pop() ;
+        assertNotNull( "expecting empty pop to be non-null", empty ) ; 
+        assertNotSame( "expecting empty pop != last popped", popped, empty ) ;
+        assertSame( "expecting empty pop == stack decoder", stack, empty ) ;
+        assertTrue( "expecting empty stack after empty pop", stack.isEmpty() ) ;
+    }
+
+    
+    public void testDecode() throws Exception
+    {
+        DecoderStack stack = new DecoderStack() ;
+        CallbackHistory history = new CallbackHistory() ;
+        stack.setCallback( history ) ;
+        assertNotNull( stack ) ;
+        assertTrue( "expecting empty stack after creation", stack.isEmpty() ) ;
+        PassThroDecoder decoder = new PassThroDecoder() ;
+        stack.push( decoder ) ;
+        stack.decode( new Integer(0) ) ;
+        assertEquals( new Integer(0), history.getMostRecent() ) ;
+        
+        assertFalse( "expecting non-empty stack after push", stack.isEmpty() ) ;
+
+        stack.push( new IncrementingDecoder() ) ;
+        stack.decode( new Integer(0) ) ;
+        assertEquals( new Integer(1), history.getMostRecent() ) ;
+
+        stack.push( new IncrementingDecoder() ) ;
+        stack.decode( new Integer(0) ) ;
+        assertEquals( new Integer(2), history.getMostRecent() ) ;
+
+        stack.push( new IncrementingDecoder() ) ;
+        stack.decode( new Integer(0) ) ;
+        assertEquals( new Integer(3), history.getMostRecent() ) ;
+
+        stack.push( new IncrementingDecoder() ) ;
+        stack.decode( new Integer(0) ) ;
+        assertEquals( new Integer(4), history.getMostRecent() ) ;
+
+        stack.push( new IncrementingDecoder() ) ;
+        stack.decode( new Integer(0) ) ;
+        assertEquals( new Integer(5), history.getMostRecent() ) ;
+
+        stack.push( new IncrementingDecoder() ) ;
+        stack.decode( new Integer(0) ) ;
+        assertEquals( new Integer(6), history.getMostRecent() ) ;
+
+        stack.push( new IncrementingDecoder() ) ;
+        stack.decode( new Integer(0) ) ;
+        assertEquals( new Integer(7), history.getMostRecent() ) ;
+
+        // start popping and decrementing now
+
+        stack.pop() ;
+        stack.decode( new Integer(0) ) ;
+        assertEquals( new Integer(6), history.getMostRecent() ) ;
+
+        stack.pop() ;
+        stack.decode( new Integer(0) ) ;
+        assertEquals( new Integer(5), history.getMostRecent() ) ;
+
+        stack.pop() ;
+        stack.decode( new Integer(0) ) ;
+        assertEquals( new Integer(4), history.getMostRecent() ) ;
+
+        stack.pop() ;
+        stack.decode( new Integer(0) ) ;
+        assertEquals( new Integer(3), history.getMostRecent() ) ;
+
+        stack.pop() ;
+        stack.decode( new Integer(0) ) ;
+        assertEquals( new Integer(2), history.getMostRecent() ) ;
+
+        stack.pop() ;
+        stack.decode( new Integer(0) ) ;
+        assertEquals( new Integer(1), history.getMostRecent() ) ;
+
+        stack.pop() ;
+        stack.decode( new Integer(0) ) ;
+        assertEquals( new Integer(0), history.getMostRecent() ) ;
+
+        assertFalse( "expecting stack with passthrodecoder", stack.isEmpty() ) ;
+        
+        stack.pop() ;
+        stack.decode( new Integer(0) ) ;
+        assertEquals( new Integer(0), history.getMostRecent() ) ;
+
+        assertTrue( "expecting empty stack after last pop", stack.isEmpty() ) ;
+        
+        stack.pop() ;
+        stack.decode( new Integer(0) ) ;
+        assertEquals( new Integer(0), history.getMostRecent() ) ;
+
+        assertTrue( "expecting empty stack after empty pop", stack.isEmpty() ) ;
+    }
+    
+    
+    public void testFailure() throws Exception
+    {
+        DecoderStack stack = new DecoderStack() ;
+        CallbackHistory history = new CallbackHistory() ;
+        stack.setCallback( history ) ;
+        assertNotNull( stack ) ;
+        assertTrue( "expecting empty stack after creation", stack.isEmpty() ) ;
+        PassThroDecoder decoder = new PassThroDecoder() ;
+        stack.push( decoder ) ;
+        
+        stack.push( new FaultingDecoder() ) ;
+        
+        try
+        {
+            stack.decode( new Object() ) ;
+            fail( "should never reach here due to exception throws" ) ;
+        }
+        catch( RuntimeException e )
+        {
+            assertNotNull( e ) ;
+            assertTrue( "testing keyword should be in the message",
+                    e.getMessage().indexOf("testing") > 0 ) ;
+            assertTrue( "RuntimeException cause should be a DecoderException",
+                    e.getCause().getClass().equals( DecoderException.class ) ) ;
+        }
+    }
+    
+    
+    /**
+     * A do nothing decoder.
+     */
+    class PassThroDecoder extends AbstractStatefulDecoder
+    {
+        public void decode( Object encoded ) throws DecoderException
+        {
+            super.decodeOccurred( encoded ) ;
+        }
+    }
+
+
+    /**
+     * A decoder that increments an Integer passed in as an argument.  We're 
+     * using this for verifying the additive (hehe) effects of decoder chaining.
+     */
+    class IncrementingDecoder extends AbstractStatefulDecoder
+    {
+        public void decode( Object encoded ) throws DecoderException
+        {
+            Integer value = ( Integer ) encoded ;
+            value = new Integer( value.intValue() + 1 ) ;
+            super.decodeOccurred( value ) ;
+        }
+    }
+
+
+    /**
+     * A decoder that throws an exception on decode calls.  We're using this 
+     * for verifying the failure of the chain.
+     */
+    class FaultingDecoder extends AbstractStatefulDecoder
+    {
+        public void decode( Object encoded ) throws DecoderException
+        {
+            throw new DecoderException( "testing" ) ;
+        }
+    }
+}

Modified: incubator/directory/snickers/trunk/xdocs/ber-codec/design.xml
==============================================================================
--- incubator/directory/snickers/trunk/xdocs/ber-codec/design.xml	(original)
+++ incubator/directory/snickers/trunk/xdocs/ber-codec/design.xml	Tue Mar 23 16:00:22 2004
@@ -121,5 +121,48 @@
         More to come soon ...
       </p>
     </section>
+
+<!-- Some extra material
+    <p>
+  The decoder must be aware of it's current state.  The following states are
+  possible in between TLV tuples:
+</p>  
+<ol>
+  <li>
+    Composing Tag - The decoder starts in this mode.  This is the mode for
+    collecting bytes for the Tag of the TLV in scope.  Bytes are copied into
+    a temporary Tag byte buffer until the Tag data is complete.  Once the 
+    bytes are complete and the Tag int is generated along with a couple of other
+    values (boolean isPrimitive and TypeClassEnum), the Tag byte buffer is
+    cleared and the state switches to the composing length state.  If the Tag
+    data is incomplete and not available until the next chunk of data arrives
+    via another decode call, we remain suspended in this state collecting the 
+    tag bytes.  There are no pushes onto any of the stacks during this state.
+  </li>
+  <li>
+    Composing Length - The decoder starts reading data into a Length byte 
+    buffer until the Length data is complete whether the length data is the 
+    short, long or indeterminate form.  Once the bytes for the length are arrive
+    and the Length int is generated, the Length byte buffer is cleared.  If
+    the Tag represents a primitive type the state switches to the composing 
+    value state.  If the TLV is constructed, the tag and the length are pushed 
+    onto their respective stacks.  The state then switches to the composing Tag
+    state.  If the length data is incomplete and not available until the next 
+    chunk of data arrives via another decode call, we remain suspended in this 
+    state.
+  </li>
+  <li>
+    Composing Value - The decoder is in this mode because the TLV is 
+    primitive.  In this state only two forms of length are valid: the short
+    and long lengths.  In either case we just read the number of bytes 
+    specified for the length during the length composing state.  If the value
+    data is incomplete and not avaiable until the next chunk of data arrives
+    via another decode call we remain suspended in this state.  We transit
+    to the composing Tag state from this state when the value data arrives.
+    Before transiting to the composing Tag state the stacks are popped and
+    the TLV is delivered as a completion event to the callback.
+  </li>
+</ol>
+  -->
   </body>
 </document>

Modified: incubator/directory/snickers/trunk/xdocs/ber-codec/navigation.xml
==============================================================================
--- incubator/directory/snickers/trunk/xdocs/ber-codec/navigation.xml	(original)
+++ incubator/directory/snickers/trunk/xdocs/ber-codec/navigation.xml	Tue Mar 23 16:00:22
2004
@@ -27,6 +27,7 @@
         <item name="Janus" href="../janus/index.html"/>
         <item name="Naming" href="../naming/index.html"/>
         <item name="Snickers" href="/index.html">
+          <item name="Stateful Codecs" href="/codec-stateful/index.html"/>
           <item name="BER Codec" href="/ber-codec/index.html"/>
           <item name="Stub Compiler" href="/stub-compiler/index.html"/>
         </item>

Added: incubator/directory/snickers/trunk/xdocs/codec-stateful/index.xml
==============================================================================
--- (empty file)
+++ incubator/directory/snickers/trunk/xdocs/codec-stateful/index.xml	Tue Mar 23 16:00:22
2004
@@ -0,0 +1,235 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document>
+  <properties>
+    <author email="akarasulu@apache.org">Alex Karasulu</author>
+    <title>Stateful Codecs</title>
+  </properties>
+  <body>
+    <section name="Introduction">
+      <p>
+        Stateful encoder and decoder pairs, or codecs for short, maintain state 
+        between respective operations.  By maintaining state in the codec all 
+        the data needed for the operation not be available at one time.  This 
+        leads to codecs with significantly reduced active footprints which are 
+        constant in size regardless of the size of the substrates they operate
+        upon.
+      </p>
+      
+      <p>
+        Furthermore Stateful codecs operate on data as it arrives instead of in
+        one shot.  This way the computational requirements are spread out over
+        time as the substrate is made available.
+      </p>
+      
+      <p>
+        Stateful codecs must be handled with care since they maintain the state
+        of an operation.  Stateful codecs must be dedicated to a serial 
+        stream of substrate objects whatever that may be.  This makes them ideal
+        for streams which have long lifespans however sensitive to the loss of 
+        data which may retard their state and require a reset.
+      </p>
+    </section>
+    
+    <section name="StatefulDecoder Usage">
+      <p>
+        StatefulDecoders use callbacks to notify the successful decode of a
+        unit of encoded substrate.  Other than this the definition of what a
+        'unit of encoded substrate' is depends on the codec's decoder 
+        implementation.  The definition may be size constrained or be a function
+        of context.
+      </p>
+      
+      <p>
+        Basically you give a decoder some of the substrate every so often
+        as more of the substrate is made available, then when a unit of 
+        encoded substrate has been decoded, the decoder notifies those 
+        concerned by invoking the callback.  
+      </p>
+      
+      <p>
+        A demonstration of how a StatefulDecoder works is illustrated below:
+      </p>
+      
+      <source>
+StatefulDecoder decoder = new SomeConcreteDecoder( 512 ) ;
+DecoderCallback cb = new DecoderCallback() {
+  decodeOccurred( StatefulDecoder decoder, Object decoded ) {
+      // do something with the decoded object
+  }
+};
+decoder.setCallback( cb ) ;
+      </source>
+      
+      <p>
+        The StatefulDecoder uses a callback to deliver decoded objects which 
+        are the decoded 'unit of encoded substrate'.  StatefulDecoders are ideal
+        for use in high performance servers based on non-blocking IO.   Often
+        StatefulDecoders will be used with a Selector in a loop to detect input
+        made available.  As the substrate arrives, it can be fed to the decoder
+        intermittantly.  Finally the callback delivers the decoded units of 
+        encoded substrate.  Below there is a trivialized example of how 
+        a StatefulDecoder can be used to decoded the substrate as it arrives 
+        fragmented by the tcp/ip stack:
+      </p>
+      
+      <source>
+while ( true ) {
+  ...
+  SelectionKey key = ( SelectionKey ) list.next() ;
+  if ( key.isReadable() ) {
+    SocketChannel channel = ( SocketChannel ) l_key.channel() ;
+    channel.read( buf ) ;
+    buf.flip() ;
+    decoder.decode( buf ) ;
+  }
+  ...
+}
+      </source>
+      
+      <p>
+        As you can see from the code fragment the decode() returns anything with
+        a void return type.  Because the callback is used to deliver the 
+        finished product when it is ready, the decode operation can occur 
+        asynchronously in another thread or stage of a server if so desired.  
+        This is what makes StatefulDecoders so simple yet powerful.
+      </p>
+    </section>
+    
+    <section name="Strengths and Weaknesses">
+      <p>
+        As can be seen from the section above and some of the characteristics 
+        of StatefulDecoders, they are ideal for building network servers.  These
+        decoders waste very little memory per request, cannot be overloaded by
+        massive requests which may be used for DoS attacks, and they process the
+        substrate as it arrives in chucks instead of in one prolonged CPU and 
+        memory intensive step.
+      </p>
+      
+      <p>
+        Servers with a high degree of concurrency need to keep overheads low.
+        StatefulDecoders certainly help achieve that end by keeping the
+        active processing footprint low with a constant size regardless of the 
+        size of the substrate.
+      </p>
+      
+      <p>
+        The cost of creating a decoder for every new connection is usually very
+        minimal however we cannot forsee every possible implementation.  
+        Regardless of the cost associated with dedicating a StatefulDecoder to
+        each new connection, stateful protocol servers will always pay a lesser
+        price.  The longer the life of the connection, the more worth while it
+        is to create a StatefulDecoder and thereby have it amortize over the 
+        life of the connection.
+      </p>
+      
+      <p>
+        StatefulDecoders are much more complex for implementors.  They are 
+        basically state driven automata which change their state with the
+        arrival of data.  Furthermoe it is very difficult for StatefulDecoders
+        to gracefully recover from corrupt or lost input.
+      </p>
+    </section>
+    
+    <section name="StatefulDecoder Chaining/Stacking">
+      <p>
+        StatefulDecoders can easily be chained or stacked to operate on a 
+        substrate stream.  This is achieved by having the callback of one 
+        decoder feed the <code>decode(Object)</code> method of another.  Hence
+        the decoded byproduct of one decoder is the encoded substrate of 
+        another.
+      </p>
+      
+      <p>
+        Because the occurence of chaining may be common and several folks have
+        already expressed their interest in it we have devised a special 
+        StatefulDecoder implementation called a DecoderStack.  It itself is 
+        a decoder however other decoders can be pushed onto it.  When empty
+        without any decoders in the stack it operates in pass-thro mode.  When
+        StatefulDecoders are pushed decode operations invoke a chain of decoders
+        starting with the bottom most in the stack going up to the top.  The
+        final callback is the callback registered with the DecoderStack.
+      </p>
+      
+      <p>
+        Below is an example of how this DecoderStack is used.  The example is
+        taken from one of the JUnit test cases for DecoderStack:
+      </p>
+
+      <source>
+public void testDecode() {
+  DecoderStack stack = new DecoderStack() ;
+  CallbackHistory history = new CallbackHistory() ;
+  stack.setCallback( history ) ;
+  stack.push( decoder ) ;
+  stack.decode( new Integer(0) ) ;
+  assertEquals( new Integer(0), history.getMostRecent() ) ;
+        
+  stack.push( new IncrementingDecoder() ) ;
+  stack.decode( new Integer(0) ) ;
+  assertEquals( new Integer(1), history.getMostRecent() ) ;
+
+  stack.push( new IncrementingDecoder() ) ;
+  stack.decode( new Integer(0) ) ;
+  assertEquals( new Integer(2), history.getMostRecent() ) ;
+}
+...
+
+class IncrementingDecoder extends AbstractStatefulDecoder
+{
+  public void decode( Object encoded ) throws DecoderException
+  {
+    Integer value = ( Integer ) encoded ;
+    value = new Integer( value.intValue() + 1 ) ;
+    super.decodeOccurred( value ) ;
+  }
+}
+      </source>      
+    </section>
+    
+    <section name="Recommendations to Implementors">
+      <p>
+        Keep it simple and rely on chaining to divide and concur complex 
+        decoders into several trivial decoders.  Besides simple chaining,  
+        situations will warrent the use of a choice driven decoder.  Such a 
+        decoder chooses which subordinate decoder to use based on its
+        current state.  For example in the simple BER byte stream to TLV 
+        decoder in Snickers, their is a TagDecoder, a LengthDecoder and
+        several Value decoders that are swapped in and out when the top 
+        BERDecoder switches state or detects a new primitive datatype.
+      </p>
+      
+      <p>
+        When reading encoded data from buffers, keep in mind that there are 
+        5 different possible configurations to the contents of arriving data 
+        with respect to the unit of encoded substrate:
+      </p>
+      
+      <ul>
+        <li>
+          it contains a single complete discrete unit of encoded substrate
+        </li>
+        <li>
+          it contains many discrete and complete units of encoded substrate
+        </li>
+        <li>
+          it contains a partial fragment of a unit of encoded substrate
+        </li>
+        <li>
+          it contains two partial fragments of a unit of encoded substrate with
+          the start of one and the end of another
+        </li>
+        <li>
+          it contains one or more fragments with one or more units of encoded 
+          substrate
+        </li>
+      </ul>
+      
+      <p>
+        When fragments arrive they are either head or tail fragments.  Head
+        fragments are those that start a unit and they are found at the end 
+        of the buffer.  Tail fragments end a unit of encoded substrate and are
+        found at the front of the buffer.
+      </p>
+    </section>
+  </body>
+</document>

Added: incubator/directory/snickers/trunk/xdocs/codec-stateful/navigation.xml
==============================================================================
--- (empty file)
+++ incubator/directory/snickers/trunk/xdocs/codec-stateful/navigation.xml	Tue Mar 23 16:00:22
2004
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<project>
+
+ <title>Apache Directory Project</title>
+
+ <body>
+
+    <links>
+      <item name="Apache" href="http://apache.org/"/>
+      <item name="Directory" href="../../index.html"/>
+      <item name="Eve" href="../eve/index.html"/>
+      <item name="LDAP" href="../ldap/index.html"/>
+      <item name="Naming" href="../naming/index.html"/>
+      <item name="Janus" href="../janus/index.html"/>
+      <item name="Snickers" href="/index.html"/>
+      <item name="Sitedocs" href="../sitedocs/index.html"/>
+    </links>
+
+    <menu name="About Directory">
+      <item name="Overview" href="../../index.html"/>
+      <item name="Community" href="../../community/index.html"/>
+      <item name="Latest News" href="../../news.html"/>
+      <item name="Subprojects" href="../../index.html">
+        <item name="Eve" href="../eve/index.html"/>
+        <item name="LDAP" href="../ldap/index.html"/>
+        <item name="Janus" href="../janus/index.html"/>
+        <item name="Naming" href="../naming/index.html"/>
+        <item name="Snickers" href="/index.html">
+          <item name="Stateful Codecs" href="/codec-stateful/index.html"/>
+          <item name="BER Codec" href="/ber-codec/index.html"/>
+          <item name="Stub Compiler" href="/stub-compiler/index.html"/>
+        </item>
+        <item name="Sitedocs" href="../sitedocs/index.html"/>
+      </item>
+      <item name="Documentation" href="../../doc/index.html"/>
+    </menu>
+
+    <menu name="Resources">
+      <item name="IRC" href="../../irc.html"/>
+      <item name="Jira" href=
+        "http://nagoya.apache.org/jira/secure/BrowseProject.jspa?id=10400"/>
+      <item name="Wiki" href="http://wiki.apache.org/directory"/>
+      <item name="Lists" href="../../mailing-lists.html"/>
+      <item name="License" href="../../license.html"/>
+      <item name="Sandbox" href="../../sandbox/index.html"/>
+      <item name="Downloads" href="../../download.cgi"/>
+      <item name="Subversion" href="../../svn.html"/>
+      <item name="Related Projects" href="../../related/index.html"/>
+    </menu>
+ </body>
+
+</project>

Modified: incubator/directory/snickers/trunk/xdocs/navigation.xml
==============================================================================
--- incubator/directory/snickers/trunk/xdocs/navigation.xml	(original)
+++ incubator/directory/snickers/trunk/xdocs/navigation.xml	Tue Mar 23 16:00:22 2004
@@ -27,6 +27,7 @@
         <item name="Janus" href="../janus/index.html"/>
         <item name="Naming" href="../naming/index.html"/>
         <item name="Snickers" href="/index.html">
+          <item name="Stateful Codecs" href="/codec-stateful/index.html"/>
           <item name="BER Codec" href="/ber-codec/index.html"/>
           <item name="Stub Compiler" href="/stub-compiler/index.html"/>
         </item>

Modified: incubator/directory/snickers/trunk/xdocs/stub-compiler/navigation.xml
==============================================================================
--- incubator/directory/snickers/trunk/xdocs/stub-compiler/navigation.xml	(original)
+++ incubator/directory/snickers/trunk/xdocs/stub-compiler/navigation.xml	Tue Mar 23 16:00:22
2004
@@ -27,6 +27,7 @@
         <item name="Janus" href="../janus/index.html"/>
         <item name="Naming" href="../naming/index.html"/>
         <item name="Snickers" href="/index.html">
+          <item name="Stateful Codecs" href="/codec-stateful/index.html"/>
           <item name="BER Codec" href="/ber-codec/index.html"/>
           <item name="Stub Compiler" href="/stub-compiler/index.html"/>
         </item>

Mime
View raw message