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.Collection;
26  import java.util.LinkedList;
27  import java.util.List;
28  
29  import org.apache.directory.api.asn1.EncoderException;
30  import org.apache.directory.api.asn1.ber.tlv.BerValue;
31  import org.apache.directory.api.asn1.ber.tlv.TLV;
32  import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
33  import org.apache.directory.api.i18n.I18n;
34  import org.apache.directory.api.ldap.codec.api.LdapApiService;
35  import org.apache.directory.api.ldap.codec.api.LdapCodecConstants;
36  import org.apache.directory.api.ldap.model.entry.Attribute;
37  import org.apache.directory.api.ldap.model.entry.DefaultAttribute;
38  import org.apache.directory.api.ldap.model.entry.DefaultModification;
39  import org.apache.directory.api.ldap.model.entry.Modification;
40  import org.apache.directory.api.ldap.model.entry.ModificationOperation;
41  import org.apache.directory.api.ldap.model.entry.Value;
42  import org.apache.directory.api.ldap.model.exception.LdapException;
43  import org.apache.directory.api.ldap.model.message.Control;
44  import org.apache.directory.api.ldap.model.message.ModifyRequest;
45  import org.apache.directory.api.ldap.model.name.Dn;
46  
47  
48  /**
49   * A decorator for the ModifyRequest message
50   *
51   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
52   */
53  public class ModifyRequestDecorator extends SingleReplyRequestDecorator<ModifyRequest>
54      implements ModifyRequest
55  {
56      /** The modify request length */
57      private int modifyRequestLength;
58  
59      /** The changes length */
60      private int changesLength;
61  
62      /** The list of all change lengths */
63      private List<Integer> changeLength;
64  
65      /** The list of all the modification lengths */
66      private List<Integer> modificationLength;
67  
68      /** The list of all the value lengths */
69      private List<Integer> valuesLength;
70  
71      /** The current attribute being decoded */
72      private Attribute currentAttribute;
73  
74      /** A local storage for the operation */
75      private ModificationOperation currentOperation;
76  
77  
78      /**
79       * Makes a ModifyRequest encodable.
80       *
81       * @param codec The LDAP service instance
82       * @param decoratedMessage the decorated ModifyRequest
83       */
84      public ModifyRequestDecorator( LdapApiService codec, ModifyRequest decoratedMessage )
85      {
86          super( codec, decoratedMessage );
87      }
88  
89  
90      /**
91       * Store the current operation
92       * 
93       * @param currentOperation The currentOperation to set.
94       */
95      public void setCurrentOperation( int currentOperation )
96      {
97          this.currentOperation = ModificationOperation.getOperation( currentOperation );
98      }
99  
100 
101     /**
102      * Add a new attributeTypeAndValue
103      * 
104      * @param type The attribute's name
105      */
106     public void addAttributeTypeAndValues( String type )
107     {
108         currentAttribute = new DefaultAttribute( type );
109 
110         Modification modification = new DefaultModification( currentOperation, currentAttribute );
111         getDecorated().addModification( modification );
112     }
113 
114 
115     /**
116      * @return the current attribute's type
117      */
118     public String getCurrentAttributeType()
119     {
120         return currentAttribute.getUpId();
121     }
122 
123 
124     /**
125      * Add a new value to the current attribute
126      * 
127      * @param value The value to add
128      * @throws LdapException If teh value is invalid
129      */
130     public void addAttributeValue( byte[] value ) throws LdapException
131     {
132         currentAttribute.add( value );
133     }
134 
135 
136     /**
137      * Add a new value to the current attribute
138      * 
139      * @param value The value to add
140      * @throws LdapException If teh value is invalid
141      */
142     public void addAttributeValue( String value ) throws LdapException
143     {
144         currentAttribute.add( value );
145     }
146 
147 
148     //-------------------------------------------------------------------------
149     // The ModifyRequest methods
150     //-------------------------------------------------------------------------
151 
152     /**
153      * {@inheritDoc}
154      */
155     @Override
156     public Dn getName()
157     {
158         return getDecorated().getName();
159     }
160 
161 
162     /**
163      * {@inheritDoc}
164      */
165     @Override
166     public ModifyRequest setName( Dn name )
167     {
168         getDecorated().setName( name );
169 
170         return this;
171     }
172 
173 
174     /**
175      * {@inheritDoc}
176      */
177     @Override
178     public Collection<Modification> getModifications()
179     {
180         return getDecorated().getModifications();
181     }
182 
183 
184     /**
185      * {@inheritDoc}
186      */
187     @Override
188     public ModifyRequest addModification( Modification mod )
189     {
190         getDecorated().addModification( mod );
191 
192         return this;
193     }
194 
195 
196     /**
197      * {@inheritDoc}
198      */
199     @Override
200     public ModifyRequest removeModification( Modification mod )
201     {
202         getDecorated().removeModification( mod );
203 
204         return this;
205     }
206 
207 
208     /**
209      * {@inheritDoc}
210      */
211     @Override
212     public ModifyRequest remove( String attributeName, String... attributeValue )
213     {
214         getDecorated().remove( attributeName, attributeValue );
215 
216         return this;
217     }
218 
219 
220     /**
221      * {@inheritDoc}
222      */
223     public ModifyRequest remove( String attributeName, byte[]... attributeValue )
224     {
225         getDecorated().remove( attributeName, attributeValue );
226 
227         return this;
228     }
229 
230 
231     /**
232      * {@inheritDoc}
233      */
234     @Override
235     public ModifyRequest remove( Attribute attr )
236     {
237         getDecorated().remove( attr );
238 
239         return this;
240     }
241 
242 
243     /**
244      * {@inheritDoc}
245      */
246     @Override
247     public ModifyRequest remove( String attributeName )
248     {
249         getDecorated().remove( attributeName );
250 
251         return this;
252     }
253 
254 
255     /**
256      * {@inheritDoc}
257      */
258     @Override
259     public ModifyRequest addModification( Attribute attr, ModificationOperation modOp )
260     {
261         getDecorated().addModification( attr, modOp );
262 
263         return this;
264     }
265 
266 
267     /**
268      * {@inheritDoc}
269      */
270     @Override
271     public ModifyRequest add( String attributeName, String... attributeValue )
272     {
273         getDecorated().add( attributeName, attributeValue );
274 
275         return this;
276     }
277 
278 
279     /**
280      * {@inheritDoc}
281      */
282     public ModifyRequest add( String attributeName, byte[]... attributeValue )
283     {
284         getDecorated().add( attributeName, attributeValue );
285 
286         return this;
287     }
288 
289 
290     /**
291      * {@inheritDoc}
292      */
293     @Override
294     public ModifyRequest add( Attribute attr )
295     {
296         getDecorated().add( attr );
297 
298         return this;
299     }
300 
301 
302     /**
303      * {@inheritDoc}
304      */
305     @Override
306     public ModifyRequest replace( String attributeName )
307     {
308         getDecorated().replace( attributeName );
309 
310         return this;
311     }
312 
313 
314     /**
315      * {@inheritDoc}
316      */
317     @Override
318     public ModifyRequest replace( String attributeName, String... attributeValue )
319     {
320         getDecorated().replace( attributeName, attributeValue );
321 
322         return this;
323     }
324 
325 
326     /**
327      * {@inheritDoc}
328      */
329     public ModifyRequest replace( String attributeName, byte[]... attributeValue )
330     {
331         getDecorated().replace( attributeName, attributeValue );
332 
333         return this;
334     }
335 
336 
337     /**
338      * {@inheritDoc}
339      */
340     @Override
341     public ModifyRequest replace( Attribute attr )
342     {
343         getDecorated().replace( attr );
344 
345         return this;
346     }
347 
348 
349     /**
350      * {@inheritDoc}
351      */
352     @Override
353     public ModifyRequest setMessageId( int messageId )
354     {
355         super.setMessageId( messageId );
356 
357         return this;
358     }
359 
360 
361     /**
362      * {@inheritDoc}
363      */
364     @Override
365     public ModifyRequest addControl( Control control )
366     {
367         return ( ModifyRequest ) super.addControl( control );
368     }
369 
370 
371     /**
372      * {@inheritDoc}
373      */
374     @Override
375     public ModifyRequest addAllControls( Control[] controls )
376     {
377         return ( ModifyRequest ) super.addAllControls( controls );
378     }
379 
380 
381     /**
382      * {@inheritDoc}
383      */
384     @Override
385     public ModifyRequest removeControl( Control control )
386     {
387         return ( ModifyRequest ) super.removeControl( control );
388     }
389 
390 
391     //-------------------------------------------------------------------------
392     // The Decorator methods
393     //-------------------------------------------------------------------------
394 
395     /**
396      * Compute the ModifyRequest length 
397      * <br>
398      * ModifyRequest :
399      * <pre>
400      * 0x66 L1
401      *  |
402      *  +--&gt; 0x04 L2 object
403      *  +--&gt; 0x30 L3 modifications
404      *        |
405      *        +--&gt; 0x30 L4-1 modification sequence
406      *        |     |
407      *        |     +--&gt; 0x0A 0x01 (0..2) operation
408      *        |     +--&gt; 0x30 L5-1 modification
409      *        |           |
410      *        |           +--&gt; 0x04 L6-1 type
411      *        |           +--&gt; 0x31 L7-1 vals
412      *        |                 |
413      *        |                 +--&gt; 0x04 L8-1-1 attributeValue
414      *        |                 +--&gt; 0x04 L8-1-2 attributeValue
415      *        |                 +--&gt; ...
416      *        |                 +--&gt; 0x04 L8-1-i attributeValue
417      *        |                 +--&gt; ...
418      *        |                 +--&gt; 0x04 L8-1-n attributeValue
419      *        |
420      *        +--&gt; 0x30 L4-2 modification sequence
421      *        .     |
422      *        .     +--&gt; 0x0A 0x01 (0..2) operation
423      *        .     +--&gt; 0x30 L5-2 modification
424      *                    |
425      *                    +--&gt; 0x04 L6-2 type
426      *                    +--&gt; 0x31 L7-2 vals
427      *                          |
428      *                          +--&gt; 0x04 L8-2-1 attributeValue
429      *                          +--&gt; 0x04 L8-2-2 attributeValue
430      *                          +--&gt; ...
431      *                          +--&gt; 0x04 L8-2-i attributeValue
432      *                          +--&gt; ...
433      *                          +--&gt; 0x04 L8-2-n attributeValue
434      * </pre>
435      */
436     @Override
437     public int computeLength()
438     {
439         // Initialized with name
440         modifyRequestLength = 1 + TLV.getNbBytes( Dn.getNbBytes( getName() ) )
441             + Dn.getNbBytes( getName() );
442 
443         // All the changes length
444         changesLength = 0;
445 
446         Collection<Modification> modifications = getModifications();
447 
448         if ( ( modifications != null ) && ( !modifications.isEmpty() ) )
449         {
450             changeLength = new LinkedList<>();
451             modificationLength = new LinkedList<>();
452             valuesLength = new LinkedList<>();
453 
454             for ( Modification modification : modifications )
455             {
456                 // Modification sequence length initialized with the operation
457                 int localModificationSequenceLength = 1 + 1 + 1;
458                 int localValuesLength = 0;
459 
460                 // Modification length initialized with the type
461                 int typeLength = modification.getAttribute().getUpId().length();
462                 int localModificationLength = 1 + TLV.getNbBytes( typeLength ) + typeLength;
463 
464                 // Get all the values
465                 if ( modification.getAttribute().size() != 0 )
466                 {
467                     for ( Value<?> value : modification.getAttribute() )
468                     {
469                         localValuesLength += 1 + TLV.getNbBytes( value.getBytes().length ) + value.getBytes().length;
470                     }
471                 }
472 
473                 localModificationLength += 1 + TLV.getNbBytes( localValuesLength ) + localValuesLength;
474 
475                 // Compute the modificationSequenceLength
476                 localModificationSequenceLength += 1 + TLV.getNbBytes( localModificationLength )
477                     + localModificationLength;
478 
479                 // Add the tag and the length
480                 changesLength += 1 + TLV.getNbBytes( localModificationSequenceLength )
481                     + localModificationSequenceLength;
482 
483                 // Store the arrays of values
484                 valuesLength.add( localValuesLength );
485                 modificationLength.add( localModificationLength );
486                 changeLength.add( localModificationSequenceLength );
487             }
488 
489             // Add the modifications length to the modificationRequestLength
490             modifyRequestLength += 1 + TLV.getNbBytes( changesLength ) + changesLength;
491         }
492 
493         return 1 + TLV.getNbBytes( modifyRequestLength ) + modifyRequestLength;
494     }
495 
496 
497     /**
498      * Encode the ModifyRequest message to a PDU. 
499      * <br>
500      * ModifyRequest : 
501      * <pre>
502      * 0x66 LL
503      *   0x04 LL object
504      *   0x30 LL modifiations
505      *     0x30 LL modification sequence
506      *       0x0A 0x01 operation
507      *       0x30 LL modification
508      *         0x04 LL type
509      *         0x31 LL vals
510      *           0x04 LL attributeValue
511      *           ... 
512      *           0x04 LL attributeValue
513      *     ... 
514      *     0x30 LL modification sequence
515      *       0x0A 0x01 operation
516      *       0x30 LL modification
517      *         0x04 LL type
518      *         0x31 LL vals
519      *           0x04 LL attributeValue
520      *           ... 
521      *           0x04 LL attributeValue
522      * </pre>
523      * 
524      * @param buffer The buffer where to put the PDU
525      * @return The PDU.
526      */
527     @Override
528     public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
529     {
530         try
531         {
532             // The AddRequest Tag
533             buffer.put( LdapCodecConstants.MODIFY_REQUEST_TAG );
534             buffer.put( TLV.getBytes( modifyRequestLength ) );
535 
536             // The entry
537             BerValue.encode( buffer, Dn.getBytes( getName() ) );
538 
539             // The modifications sequence
540             buffer.put( UniversalTag.SEQUENCE.getValue() );
541             buffer.put( TLV.getBytes( changesLength ) );
542 
543             // The modifications list
544             Collection<Modification> modifications = getModifications();
545 
546             if ( ( modifications != null ) && ( !modifications.isEmpty() ) )
547             {
548                 int modificationNumber = 0;
549 
550                 // Compute the modifications length
551                 for ( Modification modification : modifications )
552                 {
553                     // The modification sequence
554                     buffer.put( UniversalTag.SEQUENCE.getValue() );
555                     int localModificationSequenceLength = changeLength.get( modificationNumber );
556                     buffer.put( TLV.getBytes( localModificationSequenceLength ) );
557 
558                     // The operation. The value has to be changed, it's not
559                     // the same value in DirContext and in RFC 2251.
560                     buffer.put( UniversalTag.ENUMERATED.getValue() );
561                     buffer.put( ( byte ) 1 );
562                     buffer.put( ( byte ) modification.getOperation().getValue() );
563 
564                     // The modification
565                     buffer.put( UniversalTag.SEQUENCE.getValue() );
566                     int localModificationLength = modificationLength.get( modificationNumber );
567                     buffer.put( TLV.getBytes( localModificationLength ) );
568 
569                     // The modification type
570                     BerValue.encode( buffer, modification.getAttribute().getUpId() );
571 
572                     // The values
573                     buffer.put( UniversalTag.SET.getValue() );
574                     int localValuesLength = valuesLength.get( modificationNumber );
575                     buffer.put( TLV.getBytes( localValuesLength ) );
576 
577                     if ( modification.getAttribute().size() != 0 )
578                     {
579                         for ( org.apache.directory.api.ldap.model.entry.Value<?> value : modification.getAttribute() )
580                         {
581                             if ( value.isHumanReadable() )
582                             {
583                                 BerValue.encode( buffer, value.getString() );
584                             }
585                             else
586                             {
587                                 BerValue.encode( buffer, value.getBytes() );
588                             }
589                         }
590                     }
591 
592                     // Go to the next modification number
593                     modificationNumber++;
594                 }
595             }
596         }
597         catch ( BufferOverflowException boe )
598         {
599             throw new EncoderException( I18n.err( I18n.ERR_04005 ), boe );
600         }
601 
602         return buffer;
603     }
604 }