001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements. See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership. The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License. You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied. See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 *
019 */
020 package org.apache.directory.shared.ldap.codec;
021
022
023 import java.nio.BufferOverflowException;
024 import java.nio.ByteBuffer;
025
026 import org.apache.directory.shared.asn1.AbstractAsn1Object;
027 import org.apache.directory.shared.asn1.Asn1Object;
028 import org.apache.directory.shared.asn1.ber.tlv.TLV;
029 import org.apache.directory.shared.asn1.ber.tlv.UniversalTag;
030 import org.apache.directory.shared.asn1.ber.tlv.Value;
031 import org.apache.directory.shared.asn1.codec.EncoderException;
032 import org.apache.directory.shared.ldap.util.StringTools;
033
034
035 /**
036 * A Asn1Object to store a Control.
037 *
038 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
039 * @version $Rev: 764131 $, $Date: 2009-04-11 03:03:00 +0200 (Sam, 11 avr 2009) $,
040 */
041 public class ControlCodec extends AbstractAsn1Object
042 {
043 // ~ Instance fields
044 // ----------------------------------------------------------------------------
045
046 /** The control type */
047 private String controlType;
048
049 /** The criticality (default value is false) */
050 private boolean criticality = false;
051
052 /** Optionnal control value */
053 private Object controlValue;
054
055 /** Optionnal control value in encoded form */
056 private byte[] encodedValue;
057
058 /** The control length */
059 private int controlLength;
060
061 // ~ Methods
062 // ------------------------------------------------------------------------------------
063
064 /**
065 * Default constructor.
066 */
067 public ControlCodec()
068 {
069 super();
070 }
071
072 /**
073 * Get the control type
074 *
075 * @return A string which represent the control type
076 */
077 public String getControlType()
078 {
079 return controlType == null ? "" : controlType;
080 }
081
082
083 /**
084 * Set the control type
085 *
086 * @param controlType The OID to be stored
087 */
088 public void setControlType( String controlType )
089 {
090 this.controlType = controlType;
091 }
092
093
094 /**
095 * Get the control value
096 *
097 * @return The control value
098 */
099 public Object getControlValue()
100 {
101 if ( controlValue == null )
102 {
103 return StringTools.EMPTY_BYTES;
104 }
105 else if ( controlValue instanceof String )
106 {
107 return StringTools.getBytesUtf8( ( String ) controlValue );
108 }
109 else
110 {
111 return controlValue;
112 }
113 }
114
115
116 /**
117 * Set the encoded control value
118 *
119 * @param encodedValue The encoded control value to store
120 */
121 public void setEncodedValue( byte[] encodedValue )
122 {
123 if ( encodedValue != null )
124 {
125 this.encodedValue = new byte[ encodedValue.length ];
126 System.arraycopy( encodedValue, 0, this.encodedValue, 0, encodedValue.length );
127 } else {
128 this.encodedValue = null;
129 }
130 }
131
132
133 /**
134 * Get the raw control encoded bytes
135 *
136 * @return the encoded bytes for the control
137 */
138 public byte[] getEncodedValue()
139 {
140 if ( encodedValue == null )
141 {
142 return StringTools.EMPTY_BYTES;
143 }
144
145 final byte[] copy = new byte[ encodedValue.length ];
146 System.arraycopy( encodedValue, 0, copy, 0, encodedValue.length );
147 return copy;
148 }
149
150
151 /**
152 * Set the control value
153 *
154 * @param controlValue The control value to store
155 */
156 public void setControlValue( Object controlValue )
157 {
158 this.controlValue = controlValue;
159 }
160
161
162 /**
163 * Get the criticality
164 *
165 * @return <code>true</code> if the criticality flag is true.
166 */
167 public boolean getCriticality()
168 {
169 return criticality;
170 }
171
172
173 /**
174 * Set the criticality
175 *
176 * @param criticality The criticality value
177 */
178 public void setCriticality( boolean criticality )
179 {
180 this.criticality = criticality;
181 }
182
183
184 /**
185 * Compute the Control length
186 * Control :
187 *
188 * 0x30 L1
189 * |
190 * +--> 0x04 L2 controlType
191 * [+--> 0x01 0x01 criticality]
192 * [+--> 0x04 L3 controlValue]
193 *
194 * Control length = Length(0x30) + length(L1)
195 * + Length(0x04) + Length(L2) + L2
196 * [+ Length(0x01) + 1 + 1]
197 * [+ Length(0x04) + Length(L3) + L3]
198 */
199 public int computeLength()
200 {
201 // The controlType
202 int controlTypeLengh = StringTools.getBytesUtf8( controlType ).length;
203 controlLength = 1 + TLV.getNbBytes( controlTypeLengh ) + controlTypeLengh;
204
205 // The criticality, only if true
206 if ( criticality )
207 {
208 controlLength += 1 + 1 + 1; // Always 3 for a boolean
209 }
210
211 // The control value, if any
212 if ( controlValue != null )
213 {
214 byte[] controlBytes;
215 if ( controlValue instanceof byte[] )
216 {
217 controlBytes = ( byte[] ) controlValue;
218 controlLength += 1 + TLV.getNbBytes( controlBytes.length ) + controlBytes.length;
219 }
220 else if ( controlValue instanceof String )
221 {
222 controlBytes = StringTools.getBytesUtf8( ( String ) controlValue );
223 controlLength += 1 + TLV.getNbBytes( controlBytes.length ) + controlBytes.length;
224 }
225 else if ( controlValue instanceof Asn1Object )
226 {
227 int length = ( ( Asn1Object ) controlValue ).computeLength();
228 controlLength += 1 + TLV.getNbBytes( length ) + length;
229 }
230 else
231 {
232 throw new IllegalStateException( "Don't know how to handle control value class "
233 + controlValue.getClass() );
234 }
235 }
236
237 return 1 + TLV.getNbBytes( controlLength ) + controlLength;
238 }
239
240
241 /**
242 * Generate the PDU which contains the Control.
243 * Control :
244 * 0x30 LL
245 * 0x04 LL type
246 * [0x01 0x01 criticality]
247 * [0x04 LL value]
248 *
249 * @param buffer The encoded PDU
250 * @return A ByteBuffer that contaons the PDU
251 * @throws EncoderException If anything goes wrong.
252 */
253 public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
254 {
255 try
256 {
257 // The LdapMessage Sequence
258 buffer.put( UniversalTag.SEQUENCE_TAG );
259
260 // The length has been calculated by the computeLength method
261 buffer.put( TLV.getBytes( controlLength ) );
262 }
263 catch ( BufferOverflowException boe )
264 {
265 throw new EncoderException( "The PDU buffer size is too small !" );
266 }
267
268 // The control type
269 Value.encode( buffer, getControlType().getBytes() );
270
271 // The control criticality, if true
272 if ( criticality )
273 {
274 Value.encode( buffer, criticality );
275 }
276
277 // The control value, if any
278 if ( controlValue != null )
279 {
280 byte[] controlBytes;
281 if ( controlValue instanceof byte[] )
282 {
283 controlBytes = ( byte[] ) controlValue;
284 encodedValue = controlBytes;
285 }
286 else if ( controlValue instanceof String )
287 {
288 controlBytes = StringTools.getBytesUtf8( ( String ) controlValue );
289 encodedValue = controlBytes;
290 }
291 else if ( controlValue instanceof Asn1Object )
292 {
293 controlBytes = ( ( Asn1Object ) controlValue ).encode( null ).array();
294 encodedValue = controlBytes;
295 }
296 else
297 {
298 throw new IllegalStateException( "Don't know how to handle control value class "
299 + controlValue.getClass() );
300 }
301
302 Value.encode( buffer, controlBytes );
303 }
304
305 return buffer;
306 }
307
308
309 /**
310 * Return a String representing a Control
311 */
312 public String toString()
313 {
314 StringBuffer sb = new StringBuffer();
315
316 sb.append( " Control\n" );
317 sb.append( " Control type : '" ).append( controlType ).append(
318 "'\n" );
319 sb.append( " Criticality : '" ).append( criticality ).append( "'\n" );
320
321 if ( controlValue != null )
322 {
323 if ( controlValue instanceof byte[] )
324 {
325 sb.append( " Control value : '" ).append( StringTools.dumpBytes( ( byte[] ) controlValue ) )
326 .append( "'\n" );
327 }
328 else
329 {
330 sb.append( " Control value : '" ).append( controlValue ).append( "'\n" );
331 }
332 }
333
334 return sb.toString();
335 }
336 }