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.codec.MessageTypeEnum;
037 import org.apache.directory.shared.ldap.entry.Entry;
038 import org.apache.directory.shared.ldap.entry.EntryAttribute;
039 import org.apache.directory.shared.ldap.entry.client.DefaultClientAttribute;
040 import org.apache.directory.shared.ldap.entry.client.DefaultClientEntry;
041 import org.apache.directory.shared.ldap.name.DN;
042 import org.apache.directory.shared.ldap.util.StringTools;
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: 918756 $, $Date: 2010-03-04 00:05:29 +0100 (Jeu, 04 mar 2010) $,
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 MessageTypeEnum getMessageType()
117 {
118 return MessageTypeEnum.ADD_REQUEST;
119 }
120
121
122 /**
123 * {@inheritDoc}
124 */
125 public String getMessageTypeName()
126 {
127 return "ADD_REQUEST";
128 }
129
130
131 /**
132 * Initialize the Entry.
133 */
134 public void initEntry()
135 {
136 entry = new DefaultClientEntry();
137 }
138
139
140 /**
141 * Get the entry to be added
142 *
143 * @return Returns the entry.
144 */
145 public Entry getEntry()
146 {
147 return entry;
148 }
149
150
151 /**
152 * Sets the entry.
153 *
154 * @param entry
155 * the entry
156 */
157 public void setEntry( Entry entry )
158 {
159 this.entry = entry;
160 }
161
162
163 /**
164 * Create a new attributeValue
165 *
166 * @param type The attribute's name (called 'type' in the grammar)
167 */
168 public void addAttributeType( String type ) throws NamingException
169 {
170 // do not create a new attribute if we have seen this attributeType before
171 if ( entry.get( type ) != null )
172 {
173 currentAttribute = entry.get( type );
174 return;
175 }
176
177 // fix this to use AttributeImpl(type.getString().toLowerCase())
178 currentAttribute = new DefaultClientAttribute( type );
179 entry.put( currentAttribute );
180 }
181
182
183 /**
184 * Add a new value to the current attribute
185 *
186 * @param value The value to add
187 */
188 public void addAttributeValue( String value )
189 {
190 currentAttribute.add( value );
191 }
192
193
194 /**
195 * Add a new value to the current attribute
196 *
197 * @param value The value to add
198 */
199 public void addAttributeValue( org.apache.directory.shared.ldap.entry.Value<?> value )
200 {
201 currentAttribute.add( value );
202 }
203
204
205 /**
206 * Add a new value to the current attribute
207 *
208 * @param value The value to add
209 */
210 public void addAttributeValue( byte[] value )
211 {
212 currentAttribute.add( value );
213 }
214
215
216 /**
217 * Get the added DN
218 *
219 * @return Returns the entry DN.
220 */
221 public DN getEntryDn()
222 {
223 return entry.getDn();
224 }
225
226
227 /**
228 * Set the added DN.
229 *
230 * @param entry The DN to set.
231 */
232 public void setEntryDn( DN entryDn )
233 {
234 entry.setDn( entryDn );
235 }
236
237
238 /**
239 * Compute the AddRequest length
240 *
241 * AddRequest :
242 *
243 * 0x68 L1
244 * |
245 * +--> 0x04 L2 entry
246 * +--> 0x30 L3 (attributes)
247 * |
248 * +--> 0x30 L4-1 (attribute)
249 * | |
250 * | +--> 0x04 L5-1 type
251 * | +--> 0x31 L6-1 (values)
252 * | |
253 * | +--> 0x04 L7-1-1 value
254 * | +--> ...
255 * | +--> 0x04 L7-1-n value
256 * |
257 * +--> 0x30 L4-2 (attribute)
258 * | |
259 * | +--> 0x04 L5-2 type
260 * | +--> 0x31 L6-2 (values)
261 * | |
262 * | +--> 0x04 L7-2-1 value
263 * | +--> ...
264 * | +--> 0x04 L7-2-n value
265 * |
266 * +--> ...
267 * |
268 * +--> 0x30 L4-m (attribute)
269 * |
270 * +--> 0x04 L5-m type
271 * +--> 0x31 L6-m (values)
272 * |
273 * +--> 0x04 L7-m-1 value
274 * +--> ...
275 * +--> 0x04 L7-m-n value
276 */
277 protected int computeLengthProtocolOp()
278 {
279 // The entry
280 addRequestLength = 1 + TLV.getNbBytes( DN.getNbBytes( entry.getDn() ) ) + DN.getNbBytes( entry.getDn() );
281
282 // The attributes sequence
283 attributesLength = 0;
284
285 if ( ( entry != null ) && ( entry.size() != 0 ) )
286 {
287 attributeLength = new LinkedList<Integer>();
288 valuesLength = new LinkedList<Integer>();
289
290 // Compute the attributes length
291 for ( EntryAttribute attribute : entry )
292 {
293 int localAttributeLength = 0;
294 int localValuesLength = 0;
295
296 // Get the type length
297 int idLength = attribute.getId().getBytes().length;
298 localAttributeLength = 1 + TLV.getNbBytes( idLength ) + idLength;
299
300 // The values
301 if ( attribute.size() != 0 )
302 {
303 localValuesLength = 0;
304
305 for ( org.apache.directory.shared.ldap.entry.Value<?> value : attribute )
306 {
307 int valueLength = value.getBytes().length;
308 localValuesLength += 1 + TLV.getNbBytes( valueLength ) + valueLength;
309 }
310
311 localAttributeLength += 1 + TLV.getNbBytes( localValuesLength ) + localValuesLength;
312 }
313
314 // add the attribute length to the attributes length
315 attributesLength += 1 + TLV.getNbBytes( localAttributeLength ) + localAttributeLength;
316
317 attributeLength.add( localAttributeLength );
318 valuesLength.add( localValuesLength );
319 }
320 }
321
322 addRequestLength += 1 + TLV.getNbBytes( attributesLength ) + attributesLength;
323
324 // Return the result.
325 int result = 1 + TLV.getNbBytes( addRequestLength ) + addRequestLength;
326
327 if ( IS_DEBUG )
328 {
329 log.debug( "AddRequest PDU length = {}", Integer.valueOf( result ) );
330 }
331
332 return result;
333 }
334
335
336 /**
337 * Encode the AddRequest message to a PDU.
338 *
339 * AddRequest :
340 *
341 * 0x68 LL
342 * 0x04 LL entry
343 * 0x30 LL attributesList
344 * 0x30 LL attributeList
345 * 0x04 LL attributeDescription
346 * 0x31 LL attributeValues
347 * 0x04 LL attributeValue
348 * ...
349 * 0x04 LL attributeValue
350 * ...
351 * 0x30 LL attributeList
352 * 0x04 LL attributeDescription
353 * 0x31 LL attributeValue
354 * 0x04 LL attributeValue
355 * ...
356 * 0x04 LL attributeValue
357 *
358 * @param buffer The buffer where to put the PDU
359 * @return The PDU.
360 */
361 protected void encodeProtocolOp( ByteBuffer buffer ) throws EncoderException
362 {
363 try
364 {
365 // The AddRequest Tag
366 buffer.put( LdapConstants.ADD_REQUEST_TAG );
367 buffer.put( TLV.getBytes( addRequestLength ) );
368
369 // The entry
370 Value.encode( buffer, DN.getBytes( entry.getDn() ) );
371
372 // The attributes sequence
373 buffer.put( UniversalTag.SEQUENCE_TAG );
374 buffer.put( TLV.getBytes( attributesLength ) );
375
376 // The partial attribute list
377 if ( ( entry != null ) && ( entry.size() != 0 ) )
378 {
379 int attributeNumber = 0;
380
381 // Compute the attributes length
382 for ( EntryAttribute attribute : entry )
383 {
384 // The attributes list sequence
385 buffer.put( UniversalTag.SEQUENCE_TAG );
386 int localAttributeLength = attributeLength.get( attributeNumber );
387 buffer.put( TLV.getBytes( localAttributeLength ) );
388
389 // The attribute type
390 Value.encode( buffer, attribute.getId() );
391
392 // The values
393 buffer.put( UniversalTag.SET_TAG );
394 int localValuesLength = valuesLength.get( attributeNumber );
395 buffer.put( TLV.getBytes( localValuesLength ) );
396
397 if ( attribute.size() != 0 )
398 {
399 for ( org.apache.directory.shared.ldap.entry.Value<?> value : attribute )
400 {
401 if ( value.isBinary() )
402 {
403 Value.encode( buffer, value.getBytes() );
404 }
405 else
406 {
407 Value.encode( buffer, value.getString() );
408 }
409 }
410 }
411
412 // Go to the next attribute number;
413 attributeNumber++;
414 }
415 }
416 }
417 catch ( BufferOverflowException boe )
418 {
419 throw new EncoderException( "The PDU buffer size is too small !" );
420 }
421
422 if ( IS_DEBUG )
423 {
424 log.debug( "AddRequest encoding : {}", StringTools.dumpBytes( buffer.array() ) );
425 log.debug( "AddRequest initial value : {}", toString() );
426 }
427 }
428
429
430 /**
431 * @return Returns the currentAttribute type.
432 */
433 public String getCurrentAttributeType()
434 {
435 return currentAttribute.getId();
436 }
437
438
439 /**
440 * Return a String representing an AddRequest
441 *
442 * @return A String representing the AddRequest
443 */
444 public String toString()
445 {
446 StringBuilder sb = new StringBuilder();
447
448 sb.append( " Add Request\n" );
449 sb.append( " Attributes\n" );
450
451 if ( entry == null )
452 {
453 sb.append( " No attributes" );
454 }
455 else
456 {
457 sb.append( entry );
458 }
459
460 return toString( sb.toString() );
461 }
462 }