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 }