View Javadoc
1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    * 
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   * 
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License.
18   * 
19   */
20  package org.apache.directory.api.ldap.codec.decorators;
21  
22  
23  import java.nio.BufferOverflowException;
24  import java.nio.ByteBuffer;
25  import java.util.LinkedList;
26  import java.util.List;
27  
28  import org.apache.directory.api.asn1.EncoderException;
29  import org.apache.directory.api.asn1.ber.tlv.BerValue;
30  import org.apache.directory.api.asn1.ber.tlv.TLV;
31  import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
32  import org.apache.directory.api.i18n.I18n;
33  import org.apache.directory.api.ldap.codec.api.LdapApiService;
34  import org.apache.directory.api.ldap.codec.api.LdapConstants;
35  import org.apache.directory.api.ldap.model.entry.Attribute;
36  import org.apache.directory.api.ldap.model.entry.DefaultAttribute;
37  import org.apache.directory.api.ldap.model.entry.Entry;
38  import org.apache.directory.api.ldap.model.entry.Value;
39  import org.apache.directory.api.ldap.model.exception.LdapException;
40  import org.apache.directory.api.ldap.model.message.AddRequest;
41  import org.apache.directory.api.ldap.model.message.Control;
42  import org.apache.directory.api.ldap.model.name.Dn;
43  import org.apache.directory.api.util.Strings;
44  
45  
46  /**
47   * A decorator for the AddRequest message
48   *
49   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
50   */
51  public final class AddRequestDecorator extends SingleReplyRequestDecorator<AddRequest> implements
52      AddRequest
53  {
54      /** The add request length */
55      private int addRequestLength;
56  
57      /** The Entry length */
58      private int entryLength;
59  
60      /** The list of all attributes length */
61      private List<Integer> attributesLength;
62  
63      /** The list of all attributes Id bytes */
64      private List<byte[]> attributeIds;
65  
66      /** The list of all vals length */
67      private List<Integer> valuesLength;
68  
69      /** The current attribute being decoded */
70      private Attribute currentAttribute;
71  
72      /** The bytes containing the Dn */
73      private byte[] dnBytes;
74  
75  
76      /**
77       * Makes a AddRequest a MessageDecorator.
78       *
79       * @param decoratedMessage the decorated AddRequest
80       */
81      public AddRequestDecorator( LdapApiService codec, AddRequest decoratedMessage )
82      {
83          super( codec, decoratedMessage );
84      }
85  
86  
87      /**
88       * Stores the encoded length for the AddRequest
89       * @param addRequestLength The encoded length
90       */
91      public void setAddRequestLength( int addRequestLength )
92      {
93          this.addRequestLength = addRequestLength;
94      }
95  
96  
97      /**
98       * @return The encoded AddRequest's length
99       */
100     public int getAddRequestLength()
101     {
102         return addRequestLength;
103     }
104 
105 
106     /**
107      * Stores the encoded length for the Entry
108      * @param entryLength The encoded length
109      */
110     public void setEntryLength( int entryLength )
111     {
112         this.entryLength = entryLength;
113     }
114 
115 
116     /**
117      * @return The encoded Entry's length
118      */
119     public int getEntryLength()
120     {
121         return entryLength;
122     }
123 
124 
125     /**
126      * Stores the encoded length for the attributes
127      * @param attributesLength The encoded length
128      */
129     public void setAttributesLength( List<Integer> attributesLength )
130     {
131         this.attributesLength = attributesLength;
132     }
133 
134 
135     /**
136      * @return The encoded values length
137      */
138     public List<Integer> getAttributesLength()
139     {
140         return attributesLength;
141     }
142 
143 
144     /**
145      * Stores the encoded length for the values
146      * @param valuesLength The encoded length
147      */
148     public void setValuesLength( List<Integer> valuesLength )
149     {
150         this.valuesLength = valuesLength;
151     }
152 
153 
154     /**
155      * @return The encoded values length
156      */
157     public List<Integer> getValuesLength()
158     {
159         return valuesLength;
160     }
161 
162 
163     /**
164      * {@inheritDoc}
165      */
166     public AddRequest setMessageId( int messageId )
167     {
168         super.setMessageId( messageId );
169 
170         return this;
171     }
172 
173 
174     /**
175      * {@inheritDoc}
176      */
177     public AddRequest addControl( Control control )
178     {
179         return ( AddRequest ) super.addControl( control );
180     }
181 
182 
183     /**
184      * {@inheritDoc}
185      */
186     public AddRequest addAllControls( Control[] controls )
187     {
188         return ( AddRequest ) super.addAllControls( controls );
189     }
190 
191 
192     /**
193      * {@inheritDoc}
194      */
195     public AddRequest removeControl( Control control )
196     {
197         return ( AddRequest ) super.removeControl( control );
198     }
199 
200 
201     //-------------------------------------------------------------------------
202     // The AddRequest methods
203     //-------------------------------------------------------------------------
204 
205     /**
206      * {@inheritDoc}
207      */
208     public Dn getEntryDn()
209     {
210         return getDecorated().getEntryDn();
211     }
212 
213 
214     /**
215      * {@inheritDoc}
216      */
217     public AddRequest setEntryDn( Dn entry )
218     {
219         getDecorated().setEntryDn( entry );
220 
221         return this;
222     }
223 
224 
225     /**
226      * {@inheritDoc}
227      */
228     public Entry getEntry()
229     {
230         return getDecorated().getEntry();
231     }
232 
233 
234     /**
235      * {@inheritDoc}
236      */
237     public AddRequest setEntry( Entry entry )
238     {
239         getDecorated().setEntry( entry );
240 
241         return this;
242     }
243 
244 
245     /**
246      * Create a new attributeValue
247      * 
248      * @param type The attribute's name (called 'type' in the grammar)
249      */
250     public void addAttributeType( String type ) throws LdapException
251     {
252         // do not create a new attribute if we have seen this attributeType before
253         if ( getDecorated().getEntry().get( type ) != null )
254         {
255             currentAttribute = getDecorated().getEntry().get( type );
256             return;
257         }
258 
259         // fix this to use AttributeImpl(type.getString().toLowerCase())
260         currentAttribute = new DefaultAttribute( type );
261         getDecorated().getEntry().put( currentAttribute );
262     }
263 
264 
265     /**
266      * @return Returns the currentAttribute type.
267      */
268     public String getCurrentAttributeType()
269     {
270         return currentAttribute.getUpId();
271     }
272 
273 
274     /**
275      * Add a new value to the current attribute
276      * 
277      * @param value The value to add
278      */
279     public void addAttributeValue( String value ) throws LdapException
280     {
281         currentAttribute.add( value );
282     }
283 
284 
285     /**
286      * Add a new value to the current attribute
287      * 
288      * @param value The value to add
289      */
290     public void addAttributeValue( Value<?> value ) throws LdapException
291     {
292         currentAttribute.add( value );
293     }
294 
295 
296     /**
297      * Add a new value to the current attribute
298      * 
299      * @param value The value to add
300      */
301     public void addAttributeValue( byte[] value ) throws LdapException
302     {
303         currentAttribute.add( value );
304     }
305 
306 
307     //-------------------------------------------------------------------------
308     // The Decorator methods
309     //-------------------------------------------------------------------------
310     /**
311      * Compute the AddRequest length
312      * 
313      * AddRequest :
314      * 
315      * 0x68 L1
316      *  |
317      *  +--> 0x04 L2 entry
318      *  +--> 0x30 L3 (attributes)
319      *        |
320      *        +--> 0x30 L4-1 (attribute)
321      *        |     |
322      *        |     +--> 0x04 L5-1 type
323      *        |     +--> 0x31 L6-1 (values)
324      *        |           |
325      *        |           +--> 0x04 L7-1-1 value
326      *        |           +--> ...
327      *        |           +--> 0x04 L7-1-n value
328      *        |
329      *        +--> 0x30 L4-2 (attribute)
330      *        |     |
331      *        |     +--> 0x04 L5-2 type
332      *        |     +--> 0x31 L6-2 (values)
333      *        |           |
334      *        |           +--> 0x04 L7-2-1 value
335      *        |           +--> ...
336      *        |           +--> 0x04 L7-2-n value
337      *        |
338      *        +--> ...
339      *        |
340      *        +--> 0x30 L4-m (attribute)
341      *              |
342      *              +--> 0x04 L5-m type
343      *              +--> 0x31 L6-m (values)
344      *                    |
345      *                    +--> 0x04 L7-m-1 value
346      *                    +--> ...
347      *                    +--> 0x04 L7-m-n value
348      */
349     public int computeLength()
350     {
351         AddRequest addRequest = getDecorated();
352         Entry entry = addRequest.getEntry();
353 
354         if ( entry == null )
355         {
356             throw new IllegalArgumentException( I18n.err( I18n.ERR_04481_ENTRY_NULL_VALUE ) );
357         }
358 
359         dnBytes = Strings.getBytesUtf8( entry.getDn().getName() );
360         int dnLen = dnBytes.length;
361 
362         // The entry Dn
363         int addRequestLength = 1 + TLV.getNbBytes( dnLen ) + dnLen;
364 
365         // The attributes sequence
366         int entryLength = 0;
367 
368         if ( entry.size() != 0 )
369         {
370             attributesLength = new LinkedList<Integer>();
371             attributeIds = new LinkedList<byte[]>();
372             valuesLength = new LinkedList<Integer>();
373 
374             // Compute the attributes length
375             for ( Attribute attribute : entry )
376             {
377                 int localAttributeLength = 0;
378                 int localValuesLength = 0;
379 
380                 // Get the type length
381                 byte[] attributeIdBytes = Strings.getBytesUtf8( attribute.getUpId() );
382                 attributeIds.add( attributeIdBytes );
383 
384                 int idLength = attributeIdBytes.length;
385                 localAttributeLength = 1 + TLV.getNbBytes( idLength ) + idLength;
386 
387                 // The values
388                 if ( attribute.size() != 0 )
389                 {
390                     localValuesLength = 0;
391 
392                     for ( Value<?> value : attribute )
393                     {
394                         if ( value.getBytes() == null )
395                         {
396                             localValuesLength += 1 + 1;
397                         }
398                         else
399                         {
400                             int valueLength = value.getBytes().length;
401                             localValuesLength += 1 + TLV.getNbBytes( valueLength ) + valueLength;
402                         }
403                     }
404 
405                     localAttributeLength += 1 + TLV.getNbBytes( localValuesLength ) + localValuesLength;
406                 }
407                 else
408                 {
409                     // No value : we still have to store the encapsulating Sequence
410                     localValuesLength = 1 + 1;
411                     localAttributeLength += 1 + 1 + localValuesLength;
412                 }
413 
414                 // add the attribute length to the attributes length
415                 entryLength += 1 + TLV.getNbBytes( localAttributeLength ) + localAttributeLength;
416 
417                 attributesLength.add( localAttributeLength );
418                 valuesLength.add( localValuesLength );
419             }
420 
421             setAttributesLength( attributesLength );
422             setValuesLength( valuesLength );
423             setEntryLength( entryLength );
424         }
425 
426         addRequestLength += 1 + TLV.getNbBytes( entryLength ) + entryLength;
427         setAddRequestLength( addRequestLength );
428 
429         // Return the result.
430         return 1 + TLV.getNbBytes( addRequestLength ) + addRequestLength;
431     }
432 
433 
434     /**
435      * Encode the AddRequest message to a PDU.
436      * 
437      * AddRequest :
438      * 
439      * 0x68 LL
440      *   0x04 LL entry
441      *   0x30 LL attributesList
442      *     0x30 LL attributeList
443      *       0x04 LL attributeDescription
444      *       0x31 LL attributeValues
445      *         0x04 LL attributeValue
446      *         ...
447      *         0x04 LL attributeValue
448      *     ...
449      *     0x30 LL attributeList
450      *       0x04 LL attributeDescription
451      *       0x31 LL attributeValue
452      *         0x04 LL attributeValue
453      *         ...
454      *         0x04 LL attributeValue
455      * 
456      * @param buffer The buffer where to put the PDU
457      */
458     public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
459     {
460         try
461         {
462             // The AddRequest Tag
463             buffer.put( LdapConstants.ADD_REQUEST_TAG );
464             buffer.put( TLV.getBytes( getAddRequestLength() ) );
465 
466             // The entry
467             BerValue.encode( buffer, dnBytes );
468 
469             // The attributes sequence
470             buffer.put( UniversalTag.SEQUENCE.getValue() );
471             buffer.put( TLV.getBytes( getEntryLength() ) );
472 
473             // The partial attribute list
474             Entry entry = getEntry();
475 
476             if ( entry.size() != 0 )
477             {
478                 int attributeNumber = 0;
479 
480                 // Compute the attributes length
481                 for ( Attribute attribute : entry )
482                 {
483                     // The attributes list sequence
484                     buffer.put( UniversalTag.SEQUENCE.getValue() );
485                     int localAttributeLength = attributesLength.get( attributeNumber );
486                     buffer.put( TLV.getBytes( localAttributeLength ) );
487 
488                     // The attribute type
489                     BerValue.encode( buffer, attributeIds.get( attributeNumber ) );
490 
491                     // The values
492                     buffer.put( UniversalTag.SET.getValue() );
493                     int localValuesLength = valuesLength.get( attributeNumber );
494                     buffer.put( TLV.getBytes( localValuesLength ) );
495 
496                     if ( attribute.size() != 0 )
497                     {
498                         for ( Value<?> value : attribute )
499                         {
500                             BerValue.encode( buffer, value.getBytes() );
501                         }
502                     }
503                     else
504                     {
505                         BerValue.encode( buffer, Strings.EMPTY_BYTES );
506                     }
507 
508                     // Go to the next attribute number;
509                     attributeNumber++;
510                 }
511             }
512 
513             return buffer;
514         }
515         catch ( BufferOverflowException boe )
516         {
517             throw new EncoderException( "The PDU buffer size is too small !" );
518         }
519     }
520 }