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.add;
021
022
023 import java.nio.BufferOverflowException;
024 import java.nio.ByteBuffer;
025 import java.util.LinkedList;
026 import java.util.List;
027
028 import javax.naming.NamingException;
029
030 import org.apache.directory.shared.asn1.ber.tlv.TLV;
031 import org.apache.directory.shared.asn1.ber.tlv.UniversalTag;
032 import org.apache.directory.shared.asn1.ber.tlv.Value;
033 import org.apache.directory.shared.asn1.codec.EncoderException;
034 import org.apache.directory.shared.ldap.codec.LdapConstants;
035 import org.apache.directory.shared.ldap.codec.LdapMessageCodec;
036 import org.apache.directory.shared.ldap.entry.Entry;
037 import org.apache.directory.shared.ldap.entry.EntryAttribute;
038 import org.apache.directory.shared.ldap.entry.client.DefaultClientAttribute;
039 import org.apache.directory.shared.ldap.entry.client.DefaultClientEntry;
040 import org.apache.directory.shared.ldap.name.LdapDN;
041 import org.apache.directory.shared.ldap.util.StringTools;
042
043 import org.slf4j.Logger;
044 import org.slf4j.LoggerFactory;
045
046
047 /**
048 * An AddRequest Message. Its syntax is :
049 * AddRequest ::= [APPLICATION 8] SEQUENCE {
050 * entry LDAPDN,
051 * attributes AttributeList }
052 *
053 * AttributeList ::= SEQUENCE OF SEQUENCE {
054 * type AttributeDescription,
055 * vals SET OF AttributeValue }
056 *
057 * AttributeValue ::= OCTET STRING
058 *
059 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
060 * @version $Rev: 798550 $, $Date: 2009-07-28 16:54:01 +0200 (Mar, 28 jul 2009) $,
061 */
062 public class AddRequestCodec extends LdapMessageCodec
063 {
064 // ~ Static fields/initializers
065 // -----------------------------------------------------------------
066
067 /** The logger */
068 private static final Logger log = LoggerFactory.getLogger( AddRequestCodec.class );
069
070 /** Speedup for logs */
071 private static final boolean IS_DEBUG = log.isDebugEnabled();
072
073 // ~ Instance fields
074 // ----------------------------------------------------------------------------
075
076 /** The attributes list. */
077 private Entry entry;
078
079 /** The current attribute being decoded */
080 private EntryAttribute currentAttribute;
081
082 /** The add request length */
083 private int addRequestLength;
084
085 /** The attributes length */
086 private int attributesLength;
087
088 /** The list of all attributes length */
089 private List<Integer> attributeLength;
090
091 /** The list of all vals length */
092 private List<Integer> valuesLength;
093
094
095 // ~ Constructors
096 // -------------------------------------------------------------------------------
097
098 /**
099 * Creates a new AddRequest object.
100 */
101 public AddRequestCodec()
102 {
103 super();
104 entry = new DefaultClientEntry();
105 }
106
107
108 // ~ Methods
109 // ------------------------------------------------------------------------------------
110
111 /**
112 * Get the message type
113 *
114 * @return Returns the type.
115 */
116 public int getMessageType()
117 {
118 return LdapConstants.ADD_REQUEST;
119 }
120
121
122 /**
123 * Initialize the Entry.
124 */
125 public void initEntry()
126 {
127 entry = new DefaultClientEntry();
128 }
129
130
131 /**
132 * Get the entry to be added
133 *
134 * @return Returns the entry.
135 */
136 public Entry getEntry()
137 {
138 return entry;
139 }
140
141
142 /**
143 * Sets the entry.
144 *
145 * @param entry
146 * the entry
147 */
148 public void setEntry( Entry entry )
149 {
150 this.entry = entry;
151 }
152
153
154 /**
155 * Create a new attributeValue
156 *
157 * @param type The attribute's name (called 'type' in the grammar)
158 */
159 public void addAttributeType( String type ) throws NamingException
160 {
161 // do not create a new attribute if we have seen this attributeType before
162 if ( entry.get( type ) != null )
163 {
164 currentAttribute = entry.get( type );
165 return;
166 }
167
168 // fix this to use AttributeImpl(type.getString().toLowerCase())
169 currentAttribute = new DefaultClientAttribute( type );
170 entry.put( currentAttribute );
171 }
172
173
174 /**
175 * Add a new value to the current attribute
176 *
177 * @param value The value to add
178 */
179 public void addAttributeValue( String value )
180 {
181 currentAttribute.add( value );
182 }
183
184
185 /**
186 * Add a new value to the current attribute
187 *
188 * @param value The value to add
189 */
190 public void addAttributeValue( org.apache.directory.shared.ldap.entry.Value<?> value )
191 {
192 currentAttribute.add( value );
193 }
194
195
196 /**
197 * Add a new value to the current attribute
198 *
199 * @param value The value to add
200 */
201 public void addAttributeValue( byte[] value )
202 {
203 currentAttribute.add( value );
204 }
205
206
207 /**
208 * Get the added DN
209 *
210 * @return Returns the entry DN.
211 */
212 public LdapDN getEntryDn()
213 {
214 return entry.getDn();
215 }
216
217
218 /**
219 * Set the added DN.
220 *
221 * @param entry The DN to set.
222 */
223 public void setEntryDn( LdapDN entryDn )
224 {
225 entry.setDn( entryDn );
226 }
227
228
229 /**
230 * Compute the AddRequest length
231 *
232 * AddRequest :
233 *
234 * 0x68 L1
235 * |
236 * +--> 0x04 L2 entry
237 * +--> 0x30 L3 (attributes)
238 * |
239 * +--> 0x30 L4-1 (attribute)
240 * | |
241 * | +--> 0x04 L5-1 type
242 * | +--> 0x31 L6-1 (values)
243 * | |
244 * | +--> 0x04 L7-1-1 value
245 * | +--> ...
246 * | +--> 0x04 L7-1-n value
247 * |
248 * +--> 0x30 L4-2 (attribute)
249 * | |
250 * | +--> 0x04 L5-2 type
251 * | +--> 0x31 L6-2 (values)
252 * | |
253 * | +--> 0x04 L7-2-1 value
254 * | +--> ...
255 * | +--> 0x04 L7-2-n value
256 * |
257 * +--> ...
258 * |
259 * +--> 0x30 L4-m (attribute)
260 * |
261 * +--> 0x04 L5-m type
262 * +--> 0x31 L6-m (values)
263 * |
264 * +--> 0x04 L7-m-1 value
265 * +--> ...
266 * +--> 0x04 L7-m-n value
267 */
268 public int computeLength()
269 {
270 // The entry
271 addRequestLength = 1 + TLV.getNbBytes( LdapDN.getNbBytes( entry.getDn() ) ) + LdapDN.getNbBytes( entry.getDn() );
272
273 // The attributes sequence
274 attributesLength = 0;
275
276 if ( ( entry != null ) && ( entry.size() != 0 ) )
277 {
278 attributeLength = new LinkedList<Integer>();
279 valuesLength = new LinkedList<Integer>();
280
281 // Compute the attributes length
282 for ( EntryAttribute attribute : entry )
283 {
284 int localAttributeLength = 0;
285 int localValuesLength = 0;
286
287 // Get the type length
288 int idLength = attribute.getId().getBytes().length;
289 localAttributeLength = 1 + TLV.getNbBytes( idLength ) + idLength;
290
291 // The values
292 if ( attribute.size() != 0 )
293 {
294 localValuesLength = 0;
295
296 for ( org.apache.directory.shared.ldap.entry.Value<?> value : attribute )
297 {
298 int valueLength = value.getBytes().length;
299 localValuesLength += 1 + TLV.getNbBytes( valueLength ) + valueLength;
300 }
301
302 localAttributeLength += 1 + TLV.getNbBytes( localValuesLength ) + localValuesLength;
303 }
304
305 // add the attribute length to the attributes length
306 attributesLength += 1 + TLV.getNbBytes( localAttributeLength ) + localAttributeLength;
307
308 attributeLength.add( localAttributeLength );
309 valuesLength.add( localValuesLength );
310 }
311 }
312
313 addRequestLength += 1 + TLV.getNbBytes( attributesLength ) + attributesLength;
314
315 // Return the result.
316 int result = 1 + TLV.getNbBytes( addRequestLength ) + addRequestLength;
317
318 if ( IS_DEBUG )
319 {
320 log.debug( "AddRequest PDU length = {}", Integer.valueOf( result ) );
321 }
322
323 return result;
324 }
325
326
327 /**
328 * Encode the AddRequest message to a PDU.
329 *
330 * AddRequest :
331 *
332 * 0x68 LL
333 * 0x04 LL entry
334 * 0x30 LL attributesList
335 * 0x30 LL attributeList
336 * 0x04 LL attributeDescription
337 * 0x31 LL attributeValues
338 * 0x04 LL attributeValue
339 * ...
340 * 0x04 LL attributeValue
341 * ...
342 * 0x30 LL attributeList
343 * 0x04 LL attributeDescription
344 * 0x31 LL attributeValue
345 * 0x04 LL attributeValue
346 * ...
347 * 0x04 LL attributeValue
348 *
349 * @param buffer The buffer where to put the PDU
350 * @return The PDU.
351 */
352 public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
353 {
354 if ( buffer == null )
355 {
356 throw new EncoderException( "Cannot put a PDU in a null buffer !" );
357 }
358
359 try
360 {
361 // The AddRequest Tag
362 buffer.put( LdapConstants.ADD_REQUEST_TAG );
363 buffer.put( TLV.getBytes( addRequestLength ) );
364
365 // The entry
366 Value.encode( buffer, LdapDN.getBytes( entry.getDn() ) );
367
368 // The attributes sequence
369 buffer.put( UniversalTag.SEQUENCE_TAG );
370 buffer.put( TLV.getBytes( attributesLength ) );
371
372 // The partial attribute list
373 if ( ( entry != null ) && ( entry.size() != 0 ) )
374 {
375 int attributeNumber = 0;
376
377 // Compute the attributes length
378 for ( EntryAttribute attribute : entry )
379 {
380 // The attributes list sequence
381 buffer.put( UniversalTag.SEQUENCE_TAG );
382 int localAttributeLength = attributeLength.get( attributeNumber );
383 buffer.put( TLV.getBytes( localAttributeLength ) );
384
385 // The attribute type
386 Value.encode( buffer, attribute.getId() );
387
388 // The values
389 buffer.put( UniversalTag.SET_TAG );
390 int localValuesLength = valuesLength.get( attributeNumber );
391 buffer.put( TLV.getBytes( localValuesLength ) );
392
393 if ( attribute.size() != 0 )
394 {
395 for ( org.apache.directory.shared.ldap.entry.Value<?> value : attribute )
396 {
397 if ( value.isBinary() )
398 {
399 Value.encode( buffer, value.getBytes() );
400 }
401 else
402 {
403 Value.encode( buffer, value.getString() );
404 }
405 }
406 }
407
408 // Go to the next attribute number;
409 attributeNumber++;
410 }
411 }
412 }
413 catch ( BufferOverflowException boe )
414 {
415 throw new EncoderException( "The PDU buffer size is too small !" );
416 }
417
418 if ( IS_DEBUG )
419 {
420 log.debug( "AddRequest encoding : {}", StringTools.dumpBytes( buffer.array() ) );
421 log.debug( "AddRequest initial value : {}", toString() );
422 }
423
424 return buffer;
425 }
426
427
428 /**
429 * Return a String representing an AddRequest
430 *
431 * @return A String representing the AddRequest
432 */
433 public String toString()
434 {
435
436 StringBuilder sb = new StringBuilder();
437
438 sb.append( " Add Request\n" );
439 sb.append( " Attributes\n" );
440
441 if ( entry == null )
442 {
443 sb.append( " No attributes\n" );
444 }
445 else
446 {
447 sb.append( entry );
448 }
449
450 return sb.toString();
451 }
452
453
454 /**
455 * @return Returns the currentAttribute type.
456 */
457 public String getCurrentAttributeType()
458 {
459 return currentAttribute.getId();
460 }
461 }