View Javadoc

1   /*
2    *   Copyright 2004-2005 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  
23  import org.apache.asn1.codec.EncoderException;
24  import org.apache.asn1.codec.stateful.AbstractStatefulEncoder;
25  
26  
27  /***
28   * A tuple tree visitor that encodes tuples in prefix order into a buffer, and
29   * chunking the buffer via callbacks as it is filled.  This encoder will work
30   * on both determinate and indeterminate tuples.  However all indeterminate
31   * tuples must be followed in sequence by an indeterminate terminator tuple.
32   *
33   * @todo might eventually want to make this encoder use a buffer pool to get
34   * its chunk buffers rather than having it create its own
35   * @author <a href="mailto:dev@directory.apache.org"> Apache Directory
36   *         Project</a> $Rev: 157644 $
37   */
38  public class TupleEncodingVisitor extends AbstractStatefulEncoder
39          implements TupleNodeVisitor
40  {
41      /*** An empty buffer array so we do not recreate every time on toArray */
42      private static final ByteBuffer[] EMPTY_ARRAY = new ByteBuffer[0];
43  
44      /*** The List storing the ByteBuffers collected during a visitation */
45      private ArrayList buffers = new ArrayList();
46  
47      /*** The visitor monitor used by this TupleNodeVisitor */
48      private VisitorMonitor visitorMonitor = VisitorMonitor.NOOP;
49  
50  
51      // ------------------------------------------------------------------------
52      // TupleNodeVisitor Implementations
53      // ------------------------------------------------------------------------
54  
55  
56      public void encode( Object obj ) throws EncoderException
57      {
58          if ( obj instanceof DefaultMutableTupleNode )
59          {
60              ( ( DefaultMutableTupleNode ) obj ).accept( this );
61  
62              return;
63          }
64  
65          throw new IllegalArgumentException( "Expected an argument of type"
66                  + " DefaultMutableTupleNode but instead got an instance of "
67                  + obj.getClass().getName() );
68      }
69  
70  
71      // ------------------------------------------------------------------------
72      // TupleNodeVisitor Implementations
73      // ------------------------------------------------------------------------
74  
75  
76      /***
77       * Visits a tree of tuple nodes using a specific visitation order.
78       *
79       * @todo major kludge in this method please see warnings inline
80       * @param node the node to visit
81       */
82      public void visit( TupleNode node )
83      {
84          Tuple tlv = node.getTuple();
85  
86          int size = tlv.getTagLength() + tlv.getLengthLength();
87          ByteBuffer buf = ByteBuffer.wrap( new byte[size] );
88          tlv.setTag( buf, tlv.getTagLength() );
89          tlv.setLength( buf, tlv.getLengthLength() );
90          buffers.add( buf.flip() );
91  
92          /*
93           * W A R N I N G
94           * -------------
95           *
96           * This is a total kludge right now! Without changing the entire design
97           * of the package or at least the Tuple class there really is no way to
98           * get ahold of all the chunks for a Tuple.  So right now we're using
99           * the last one hoping that it contains the entire value as one chunk.
100          * This must be fixed and indicates a serious flaw in the design.
101          *
102          */
103 
104         if ( tlv.isPrimitive() )
105         {
106             buffers.add( tlv.getLastValueChunk() );
107         }
108 
109         /*
110          * N O T E
111          * -------
112          *
113          * We presume termination tuples exist for indefinite tuples as sibling
114          * nodes adjacent to the indefinite node.  This is why we do not
115          * explicity handle termination here.  The termination octets actually
116          * represent another TLV tuple itself with a UNIVERSAL tag of 0 and a
117          * length of 0.
118          *
119          */
120         visitorMonitor.visited( this, node );
121     }
122 
123 
124     /***
125      * Checks to see if a node can be visited.
126      *
127      * @param node the node to be visited
128      * @return whether or node the node should be visited
129      */
130     public boolean canVisit( TupleNode node )
131     {
132         return true;
133     }
134 
135 
136     /***
137      * Determines whether the visitation order is prefix or postfix.
138      *
139      * @return true if the visitation is in prefix order, false otherwise.
140      */
141     public boolean isPrefix()
142     {
143         return true;
144     }
145 
146 
147     /***
148      * Get the array of children to visit sequentially to determine the order of
149      * child visitations.  Some children may not be returned at all if
150      * canVisit() returns false on them.
151      *
152      * @param node     the parent branch node
153      * @param children the child node array
154      * @return the new reordered array of children
155      */
156     public ArrayList getOrder( TupleNode node, ArrayList children )
157     {
158         return children;
159     }
160 
161 
162     /***
163      * Flushes out the array of ByteBuffer's collected during the visitation.
164      * This is done by calling encodeOccurred in one shot.
165      */
166     public void flush()
167     {
168         ByteBuffer[] array = ( ByteBuffer [] ) buffers.toArray( EMPTY_ARRAY );
169         buffers.clear();
170         super.encodeOccurred( array );
171     }
172 
173 
174     public void setMonitor( VisitorMonitor monitor )
175     {
176         visitorMonitor = monitor;
177     }
178 }