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