View Javadoc

1   /*
2    *   Copyright 2004 The Apache Software Foundation
3    *
4    *   Licensed under the Apache License, Version 2.0 (the "License");
5    *   you may not use this file except in compliance with the License.
6    *   You may obtain a copy of the License at
7    *
8    *       http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *   Unless required by applicable law or agreed to in writing, software
11   *   distributed under the License is distributed on an "AS IS" BASIS,
12   *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *   See the License for the specific language governing permissions and
14   *   limitations under the License.
15   *
16   */
17  package org.apache.asn1.ber ;
18  
19  
20  import java.nio.ByteBuffer;
21  import java.util.ArrayList;
22  import java.util.Stack;
23  
24  import org.apache.asn1.codec.DecoderException;
25  import org.apache.asn1.codec.stateful.CallbackHistory;
26  import org.apache.asn1.codec.stateful.DecoderCallback;
27  import org.apache.asn1.codec.stateful.DecoderMonitor;
28  import org.apache.asn1.codec.stateful.DecoderMonitorAdapter;
29  import org.apache.asn1.codec.stateful.StatefulDecoder;
30  
31  
32  /***
33   * Builds a TLV tree from the TLV stream emitted from the decoder.  The decoded
34   * objects delivered to this StatefulDecoder's DecoderCallback are 
35   * DefaultMutableTupleNodes.
36   *
37   * @author <a href="mailto:dev@directory.apache.org">
38   * Apache Directory Project</a>
39   * @version $Rev: 157644 $
40   */
41  public class TupleTreeDecoder implements StatefulDecoder
42  {
43      /*** a stack of nested constructed tuples used to track state */
44      Stack stack = new Stack() ;
45      /*** the underlying BER data stream to TLV stream decoder */
46      BERDecoder decoder = new BERDecoder() ;
47      /*** the callback to use for this StatefulDecoder */
48      DecoderCallback cb = null ;
49      /*** the monitor to use for this StatefulDecoder */
50      DecoderMonitor monitor = new DecoderMonitorAdapter() ;
51      /*** the value chunks buffer collection */
52      ArrayList valueChunks = new ArrayList() ;
53  
54      
55      /***
56       * Creates a simple BER byte stream to TLV Tuple tree decoder.
57       */
58      public TupleTreeDecoder()
59      {
60          BERDecoderCallback berCallback = new BERDecoderCallback()
61          {
62              public void tagDecoded( Tuple tlv ) { }
63              
64              public void partialValueDecoded( Tuple tlv ) 
65              {
66                  ByteBuffer copy = ByteBuffer.allocate( 
67                          tlv.getLastValueChunk().remaining() ) ;
68                  copy.put( tlv.getLastValueChunk() ) ;
69                  tlv.getLastValueChunk().rewind() ;
70                  copy.rewind() ;
71                  valueChunks.add( copy ) ;
72              }
73          
74              public void lengthDecoded( Tuple tlv )
75              {
76                  if ( ! tlv.isPrimitive ) 
77                  {
78                      DefaultMutableTupleNode child = null ;
79                      DefaultMutableTupleNode parent = null ;
80                      Tuple cloned = ( Tuple ) tlv.clone() ;
81                      
82                      if ( stack.isEmpty() )
83                      {
84                          stack.push( new DefaultMutableTupleNode( cloned ) ) ;
85                          return ;
86                      }
87                      
88                      parent = ( DefaultMutableTupleNode ) stack.peek() ;
89                      child = new DefaultMutableTupleNode( cloned ) ;
90                      child.setParent( parent ) ;
91                      parent.addLast( child ) ;
92                      stack.push( child ) ;
93                  }
94              }
95      
96              public void 
97                  decodeOccurred( StatefulDecoder decoder, Object decoded )
98              {
99                  handleTuple( ( Tuple ) decoded ) ;
100             }
101         } ;
102         
103         decoder.setCallback( berCallback ) ;
104         decoder.setDecoderMonitor( monitor ) ;
105     }
106     
107     
108     /***
109      * Handles a tuple recieved from the underlying BER byte stream decoder.
110      * 
111      * @param t the tuple to handle
112      */
113     private void handleTuple( Tuple t )
114     {
115         DefaultMutableTupleNode node = null ;
116         DefaultMutableTupleNode parent = null ;
117         
118         if ( t.isPrimitive )
119         {
120             node = new DefaultMutableTupleNode( ( Tuple ) t.clone(),
121                     valueChunks ) ;
122             valueChunks.clear() ;
123                 
124             if ( ! stack.isEmpty() )
125             {    
126                 parent = ( DefaultMutableTupleNode ) stack.peek() ;
127                 node.setParent( parent ) ;
128                 parent.addLast( node ) ;
129             }
130             
131             return ;
132         }
133             
134         node = ( DefaultMutableTupleNode ) stack.pop() ;
135         
136         if ( cb != null && stack.isEmpty() )
137         {
138             cb.decodeOccurred( this, node ) ;
139         }
140     }
141     
142     
143     /* (non-Javadoc)
144      * @see org.apache.asn1.codec.stateful.StatefulDecoder#decode(
145      * java.lang.Object)
146      */
147     public void decode( Object encoded ) throws DecoderException
148     {
149         decoder.decode( encoded ) ;
150     }
151     
152     
153     /***
154      * Decodes a BER byte buffer into a tree of TLV tuples.
155      * 
156      * @param buf the buffer to decode
157      * @return the TLV tuple node with children if applicable
158      * @throws DecoderException if there is a problem decoding the data
159      * @throws java.util.NoSuchElementException if there is not enough data
160      *  to properly decode a complete TLV tree
161      */
162     public static TupleNode treeDecode( ByteBuffer buf ) throws DecoderException
163     {
164         TupleTreeDecoder decoder = new TupleTreeDecoder() ;
165         CallbackHistory history = new CallbackHistory( 1 ) ;
166         
167         decoder.setCallback( history ) ;
168         decoder.decode( buf ) ;
169         
170         if ( history.isEmpty() )
171         {
172             return null ;
173         }
174         
175         return ( TupleNode ) history.getMostRecent() ;
176     }
177     
178     
179     /* (non-Javadoc)
180      * @see org.apache.asn1.codec.stateful.StatefulDecoder#setCallback(
181      * org.apache.asn1.codec.stateful.DecoderCallback)
182      */
183     public void setCallback( DecoderCallback cb )
184     {
185         this.cb = cb ;
186     }
187     
188     
189     /* (non-Javadoc)
190      * @see org.apache.asn1.codec.stateful.StatefulDecoder#setDecoderMonitor(
191      * org.apache.asn1.codec.stateful.DecoderMonitor)
192      */
193     public void setDecoderMonitor( DecoderMonitor monitor )
194     {
195         this.monitor = monitor ;
196         decoder.setDecoderMonitor( monitor ) ;
197     }
198 }