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.LdapCodecConstants;
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 codec The LDAP service instance
80       * @param decoratedMessage the decorated AddRequest
81       */
82      public AddRequestDecorator( LdapApiService codec, AddRequest decoratedMessage )
83      {
84          super( codec, decoratedMessage );
85      }
86  
87  
88      /**
89       * {@inheritDoc}
90       */
91      @Override
92      public AddRequest setMessageId( int messageId )
93      {
94          super.setMessageId( messageId );
95  
96          return this;
97      }
98  
99  
100     /**
101      * {@inheritDoc}
102      */
103     @Override
104     public AddRequest addControl( Control control )
105     {
106         return ( AddRequest ) super.addControl( control );
107     }
108 
109 
110     /**
111      * {@inheritDoc}
112      */
113     @Override
114     public AddRequest addAllControls( Control[] controls )
115     {
116         return ( AddRequest ) super.addAllControls( controls );
117     }
118 
119 
120     /**
121      * {@inheritDoc}
122      */
123     @Override
124     public AddRequest removeControl( Control control )
125     {
126         return ( AddRequest ) super.removeControl( control );
127     }
128 
129 
130     //-------------------------------------------------------------------------
131     // The AddRequest methods
132     //-------------------------------------------------------------------------
133 
134     /**
135      * {@inheritDoc}
136      */
137     @Override
138     public Dn getEntryDn()
139     {
140         return getDecorated().getEntryDn();
141     }
142 
143 
144     /**
145      * {@inheritDoc}
146      */
147     @Override
148     public AddRequest setEntryDn( Dn entry )
149     {
150         getDecorated().setEntryDn( entry );
151 
152         return this;
153     }
154 
155 
156     /**
157      * {@inheritDoc}
158      */
159     @Override
160     public Entry getEntry()
161     {
162         return getDecorated().getEntry();
163     }
164 
165 
166     /**
167      * {@inheritDoc}
168      */
169     @Override
170     public AddRequest setEntry( Entry entry )
171     {
172         getDecorated().setEntry( entry );
173 
174         return this;
175     }
176 
177 
178     /**
179      * Create a new attributeValue
180      * 
181      * @param type The attribute's name (called 'type' in the grammar)
182      * @throws LdapException If the value is invalid
183      */
184     public void addAttributeType( String type ) throws LdapException
185     {
186         // do not create a new attribute if we have seen this attributeType before
187         if ( getDecorated().getEntry().get( type ) != null )
188         {
189             currentAttribute = getDecorated().getEntry().get( type );
190             return;
191         }
192 
193         // fix this to use AttributeImpl(type.getString().toLowerCase())
194         currentAttribute = new DefaultAttribute( type );
195         getDecorated().getEntry().put( currentAttribute );
196     }
197 
198 
199     /**
200      * @return Returns the currentAttribute type.
201      */
202     public String getCurrentAttributeType()
203     {
204         return currentAttribute.getUpId();
205     }
206 
207 
208     /**
209      * Add a new value to the current attribute
210      * 
211      * @param value The value to add
212      * @throws LdapException If the value is invalid
213      */
214     public void addAttributeValue( String value ) throws LdapException
215     {
216         currentAttribute.add( value );
217     }
218 
219 
220     /**
221      * Add a new value to the current attribute
222      * 
223      * @param value The value to add
224      * @throws LdapException If the value is invalid
225      */
226     public void addAttributeValue( Value<?> value ) throws LdapException
227     {
228         currentAttribute.add( value );
229     }
230 
231 
232     /**
233      * Add a new value to the current attribute
234      * 
235      * @param value The value to add
236      * @throws LdapException If the value is invalid
237      */
238     public void addAttributeValue( byte[] value ) throws LdapException
239     {
240         currentAttribute.add( value );
241     }
242 
243 
244     //-------------------------------------------------------------------------
245     // The Decorator methods
246     //-------------------------------------------------------------------------
247     /**
248      * Compute the AddRequest length
249      * <br>
250      * AddRequest :
251      * <pre>
252      * 0x68 L1
253      *  |
254      *  +--&gt; 0x04 L2 entry
255      *  +--&gt; 0x30 L3 (attributes)
256      *        |
257      *        +--&gt; 0x30 L4-1 (attribute)
258      *        |     |
259      *        |     +--&gt; 0x04 L5-1 type
260      *        |     +--&gt; 0x31 L6-1 (values)
261      *        |           |
262      *        |           +--&gt; 0x04 L7-1-1 value
263      *        |           +--&gt; ...
264      *        |           +--&gt; 0x04 L7-1-n value
265      *        |
266      *        +--&gt; 0x30 L4-2 (attribute)
267      *        |     |
268      *        |     +--&gt; 0x04 L5-2 type
269      *        |     +--&gt; 0x31 L6-2 (values)
270      *        |           |
271      *        |           +--&gt; 0x04 L7-2-1 value
272      *        |           +--&gt; ...
273      *        |           +--&gt; 0x04 L7-2-n value
274      *        |
275      *        +--&gt; ...
276      *        |
277      *        +--&gt; 0x30 L4-m (attribute)
278      *              |
279      *              +--&gt; 0x04 L5-m type
280      *              +--&gt; 0x31 L6-m (values)
281      *                    |
282      *                    +--&gt; 0x04 L7-m-1 value
283      *                    +--&gt; ...
284      *                    +--&gt; 0x04 L7-m-n value
285      * </pre>
286      */
287     @Override
288     public int computeLength()
289     {
290         AddRequest addRequest = getDecorated();
291         Entry entry = addRequest.getEntry();
292 
293         if ( entry == null )
294         {
295             throw new IllegalArgumentException( I18n.err( I18n.ERR_04481_ENTRY_NULL_VALUE ) );
296         }
297 
298         dnBytes = Strings.getBytesUtf8( entry.getDn().getName() );
299         int dnLen = dnBytes.length;
300 
301         // The entry Dn
302         addRequestLength = 1 + TLV.getNbBytes( dnLen ) + dnLen;
303 
304         // The attributes sequence
305         entryLength = 0;
306 
307         if ( entry.size() != 0 )
308         {
309             attributesLength = new LinkedList<>();
310             attributeIds = new LinkedList<>();
311             valuesLength = new LinkedList<>();
312 
313             // Compute the attributes length
314             for ( Attribute attribute : entry )
315             {
316                 int localAttributeLength;
317                 int localValuesLength;
318 
319                 // Get the type length
320                 byte[] attributeIdBytes = Strings.getBytesUtf8( attribute.getUpId() );
321                 attributeIds.add( attributeIdBytes );
322 
323                 int idLength = attributeIdBytes.length;
324                 localAttributeLength = 1 + TLV.getNbBytes( idLength ) + idLength;
325 
326                 // The values
327                 if ( attribute.size() != 0 )
328                 {
329                     localValuesLength = 0;
330 
331                     for ( Value<?> value : attribute )
332                     {
333                         if ( value.getBytes() == null )
334                         {
335                             localValuesLength += 1 + 1;
336                         }
337                         else
338                         {
339                             int valueLength = value.getBytes().length;
340                             localValuesLength += 1 + TLV.getNbBytes( valueLength ) + valueLength;
341                         }
342                     }
343 
344                     localAttributeLength += 1 + TLV.getNbBytes( localValuesLength ) + localValuesLength;
345                 }
346                 else
347                 {
348                     // No value : we still have to store the encapsulating Sequence
349                     localValuesLength = 1 + 1;
350                     localAttributeLength += 1 + 1 + localValuesLength;
351                 }
352 
353                 // add the attribute length to the attributes length
354                 entryLength += 1 + TLV.getNbBytes( localAttributeLength ) + localAttributeLength;
355 
356                 attributesLength.add( localAttributeLength );
357                 valuesLength.add( localValuesLength );
358             }
359         }
360 
361         addRequestLength += 1 + TLV.getNbBytes( entryLength ) + entryLength;
362 
363         // Return the result.
364         return 1 + TLV.getNbBytes( addRequestLength ) + addRequestLength;
365     }
366 
367 
368     /**
369      * Encode the AddRequest message to a PDU.
370      * <br>
371      * AddRequest :
372      * <pre>
373      * 0x68 LL
374      *   0x04 LL entry
375      *   0x30 LL attributesList
376      *     0x30 LL attributeList
377      *       0x04 LL attributeDescription
378      *       0x31 LL attributeValues
379      *         0x04 LL attributeValue
380      *         ...
381      *         0x04 LL attributeValue
382      *     ...
383      *     0x30 LL attributeList
384      *       0x04 LL attributeDescription
385      *       0x31 LL attributeValue
386      *         0x04 LL attributeValue
387      *         ...
388      *         0x04 LL attributeValue
389      * </pre>
390      * 
391      * @param buffer The buffer where to put the PDU
392      */
393     @Override
394     public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
395     {
396         try
397         {
398             // The AddRequest Tag
399             buffer.put( LdapCodecConstants.ADD_REQUEST_TAG );
400             buffer.put( TLV.getBytes( addRequestLength ) );
401 
402             // The entry
403             BerValue.encode( buffer, dnBytes );
404 
405             // The attributes sequence
406             buffer.put( UniversalTag.SEQUENCE.getValue() );
407             buffer.put( TLV.getBytes( entryLength ) );
408 
409             // The partial attribute list
410             Entry entry = getEntry();
411 
412             if ( entry.size() != 0 )
413             {
414                 int attributeNumber = 0;
415 
416                 // Compute the attributes length
417                 for ( Attribute attribute : entry )
418                 {
419                     // The attributes list sequence
420                     buffer.put( UniversalTag.SEQUENCE.getValue() );
421                     int localAttributeLength = attributesLength.get( attributeNumber );
422                     buffer.put( TLV.getBytes( localAttributeLength ) );
423 
424                     // The attribute type
425                     BerValue.encode( buffer, attributeIds.get( attributeNumber ) );
426 
427                     // The values
428                     buffer.put( UniversalTag.SET.getValue() );
429                     int localValuesLength = valuesLength.get( attributeNumber );
430                     buffer.put( TLV.getBytes( localValuesLength ) );
431 
432                     if ( attribute.size() != 0 )
433                     {
434                         for ( Value<?> value : attribute )
435                         {
436                             BerValue.encode( buffer, value.getBytes() );
437                         }
438                     }
439                     else
440                     {
441                         BerValue.encode( buffer, Strings.EMPTY_BYTES );
442                     }
443 
444                     // Go to the next attribute number
445                     attributeNumber++;
446                 }
447             }
448 
449             return buffer;
450         }
451         catch ( BufferOverflowException boe )
452         {
453             throw new EncoderException( "The PDU buffer size is too small !", boe );
454         }
455     }
456 }