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.extras.controls.syncrepl_impl;
21  
22  
23  import java.nio.ByteBuffer;
24  import java.util.ArrayList;
25  import java.util.List;
26  
27  import org.apache.directory.api.asn1.Asn1Object;
28  import org.apache.directory.api.asn1.DecoderException;
29  import org.apache.directory.api.asn1.EncoderException;
30  import org.apache.directory.api.asn1.ber.Asn1Decoder;
31  import org.apache.directory.api.asn1.ber.tlv.BerValue;
32  import org.apache.directory.api.asn1.ber.tlv.TLV;
33  import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
34  import org.apache.directory.api.i18n.I18n;
35  import org.apache.directory.api.ldap.codec.api.ControlDecorator;
36  import org.apache.directory.api.ldap.codec.api.LdapApiService;
37  import org.apache.directory.api.ldap.extras.controls.syncrepl.syncInfoValue.SyncInfoValue;
38  import org.apache.directory.api.ldap.extras.controls.syncrepl.syncInfoValue.SyncInfoValueImpl;
39  import org.apache.directory.api.ldap.extras.controls.syncrepl.syncInfoValue.SynchronizationInfoEnum;
40  import org.apache.directory.api.util.Strings;
41  
42  
43  /**
44   * A syncInfoValue object, as defined in RFC 4533
45   *
46   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
47   */
48  public class SyncInfoValueDecorator extends ControlDecorator<SyncInfoValue> implements SyncInfoValue
49  {
50      /** The syncUUIDs cumulative length */
51      private int syncUUIDsLength;
52  
53      /** An instance of this decoder */
54      private static final Asn1Decoder decoder = new Asn1Decoder();
55  
56  
57      /**
58       * The constructor for this codec. Dont't forget to set the type.
59       */
60      public SyncInfoValueDecorator( LdapApiService codec )
61      {
62          super( codec, new SyncInfoValueImpl() );
63      }
64  
65  
66      /**
67       * The constructor for this codec. Dont't forget to set the type.
68       */
69      public SyncInfoValueDecorator( LdapApiService codec, SyncInfoValue control )
70      {
71          super( codec, control );
72      }
73  
74  
75      /**
76       * The constructor for this codec.
77       * @param type The kind of syncInfo we will store. Can be newCookie,
78       * refreshPresent, refreshDelete or syncIdSet
79       */
80      public SyncInfoValueDecorator( LdapApiService codec, SynchronizationInfoEnum type )
81      {
82          this( codec );
83  
84          setType( type );
85      }
86  
87      /** The global length for this control */
88      private int syncInfoValueLength;
89  
90  
91      /**
92       * {@inheritDoc}
93       */
94      public SynchronizationInfoEnum getType()
95      {
96          return getDecorated().getType();
97      }
98  
99  
100     /**
101      * {@inheritDoc}
102      */
103     public void setType( SynchronizationInfoEnum type )
104     {
105         this.getDecorated().setType( type );
106 
107         // Initialize the arrayList if needed
108         if ( ( type == SynchronizationInfoEnum.SYNC_ID_SET ) && ( getDecorated().getSyncUUIDs() == null ) )
109         {
110             getDecorated().setSyncUUIDs( new ArrayList<byte[]>() );
111         }
112     }
113 
114 
115     /**
116      * {@inheritDoc}
117      */
118     public byte[] getCookie()
119     {
120         return getDecorated().getCookie();
121     }
122 
123 
124     /**
125      * {@inheritDoc}
126      */
127     public void setCookie( byte[] cookie )
128     {
129         // Copy the bytes
130         if ( !Strings.isEmpty( cookie ) )
131         {
132             byte[] copy = new byte[cookie.length];
133             System.arraycopy( cookie, 0, copy, 0, cookie.length );
134             getDecorated().setCookie( copy );
135         }
136         else
137         {
138             getDecorated().setCookie( null );
139         }
140     }
141 
142 
143     /**
144      * {@inheritDoc}
145      */
146     public boolean isRefreshDone()
147     {
148         return getDecorated().isRefreshDone();
149     }
150 
151 
152     /**
153      * {@inheritDoc}
154      */
155     public void setRefreshDone( boolean refreshDone )
156     {
157         getDecorated().setRefreshDone( refreshDone );
158     }
159 
160 
161     /**
162      * {@inheritDoc}
163      */
164     public boolean isRefreshDeletes()
165     {
166         return getDecorated().isRefreshDeletes();
167     }
168 
169 
170     /**
171      * {@inheritDoc}
172      */
173     public void setRefreshDeletes( boolean refreshDeletes )
174     {
175         getDecorated().setRefreshDeletes( refreshDeletes );
176     }
177 
178 
179     /**
180      * {@inheritDoc}
181      */
182     public List<byte[]> getSyncUUIDs()
183     {
184         return getDecorated().getSyncUUIDs();
185     }
186 
187 
188     /**
189      * {@inheritDoc}
190      */
191     public void setSyncUUIDs( List<byte[]> syncUUIDs )
192     {
193         getDecorated().setSyncUUIDs( syncUUIDs );
194     }
195 
196 
197     /**
198      * {@inheritDoc}
199      */
200     public void addSyncUUID( byte[] syncUUID )
201     {
202         getDecorated().addSyncUUID( syncUUID );
203     }
204 
205 
206     /**
207      * Compute the SyncInfoValue length.
208      *
209      * SyncInfoValue :
210      *
211      * 0xA0 L1 abcd                   // newCookie
212      * 0xA1 L2                        // refreshDelete
213      *   |
214      *  [+--> 0x04 L3 abcd]           // cookie
215      *  [+--> 0x01 0x01 (0x00|0xFF)   // refreshDone
216      * 0xA2 L4                        // refreshPresent
217      *   |
218      *  [+--> 0x04 L5 abcd]           // cookie
219      *  [+--> 0x01 0x01 (0x00|0xFF)   // refreshDone
220      * 0xA3 L6                        // syncIdSet
221      *   |
222      *  [+--> 0x04 L7 abcd]           // cookie
223      *  [+--> 0x01 0x01 (0x00|0xFF)   // refreshDeletes
224      *   +--> 0x31 L8                 // SET OF syncUUIDs
225      *          |
226      *         [+--> 0x04 L9 abcd]    // syncUUID    public static final int AND_FILTER_TAG = 0xA0;
227 
228     public static final int OR_FILTER_TAG = 0xA1;
229 
230     public static final int NOT_FILTER_TAG = 0xA2;
231 
232     public static final int BIND_REQUEST_SASL_TAG = 0xA3;
233 
234      */
235     @Override
236     public int computeLength()
237     {
238         // The mode length
239         syncInfoValueLength = 0;
240 
241         switch ( getType() )
242         {
243             case NEW_COOKIE:
244                 if ( getCookie() != null )
245                 {
246                     syncInfoValueLength = 1 + TLV.getNbBytes( getCookie().length ) + getCookie().length;
247                 }
248                 else
249                 {
250                     syncInfoValueLength = 1 + 1;
251                 }
252 
253                 valueLength = syncInfoValueLength;
254 
255                 // Call the super class to compute the global control length
256                 return valueLength;
257 
258             case REFRESH_DELETE:
259             case REFRESH_PRESENT:
260                 if ( getCookie() != null )
261                 {
262                     syncInfoValueLength = 1 + TLV.getNbBytes( getCookie().length ) + getCookie().length;
263                 }
264 
265                 // The refreshDone flag, only if not true, as it default to true
266                 if ( !isRefreshDone() )
267                 {
268                     syncInfoValueLength += 1 + 1 + 1;
269                 }
270 
271                 valueLength = 1 + TLV.getNbBytes( syncInfoValueLength ) + syncInfoValueLength;
272 
273                 // Call the super class to compute the global control length
274                 return valueLength;
275 
276             case SYNC_ID_SET:
277                 if ( getCookie() != null )
278                 {
279                     syncInfoValueLength = 1 + TLV.getNbBytes( getCookie().length ) + getCookie().length;
280                 }
281 
282                 // The refreshDeletes flag, default to false
283                 if ( isRefreshDeletes() )
284                 {
285                     syncInfoValueLength += 1 + 1 + 1;
286                 }
287 
288                 // The syncUUIDs if any
289                 syncUUIDsLength = 0;
290 
291                 if ( getSyncUUIDs().size() != 0 )
292                 {
293                     for ( byte[] syncUUID : getSyncUUIDs() )
294                     {
295                         int uuidLength = 1 + TLV.getNbBytes( syncUUID.length ) + syncUUID.length;
296 
297                         syncUUIDsLength += uuidLength;
298                     }
299                 }
300 
301                 syncInfoValueLength += 1 + TLV.getNbBytes( syncUUIDsLength ) + syncUUIDsLength;
302                 valueLength = 1 + TLV.getNbBytes( syncInfoValueLength ) + syncInfoValueLength;
303 
304                 // Call the super class to compute the global control length
305                 return valueLength;
306 
307             default:
308 
309         }
310 
311         return 1 + TLV.getNbBytes( syncInfoValueLength ) + syncInfoValueLength;
312     }
313 
314 
315     /**
316      * Encode the SyncInfoValue control
317      *
318      * @param buffer The encoded sink
319      * @return A ByteBuffer that contains the encoded PDU
320      * @throws EncoderException If anything goes wrong.
321      */
322     @Override
323     public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
324     {
325         if ( buffer == null )
326         {
327             throw new EncoderException( I18n.err( I18n.ERR_04023 ) );
328         }
329 
330         switch ( getType() )
331         {
332             case NEW_COOKIE:
333                 // The first case : newCookie
334                 buffer.put( ( byte ) SyncInfoValueTags.NEW_COOKIE_TAG.getValue() );
335 
336                 // As the OCTET_STRING is absorbed by the Application tag,
337                 // we have to store the L and V separately
338                 if ( ( getCookie() == null ) || ( getCookie().length == 0 ) )
339                 {
340                     buffer.put( ( byte ) 0 );
341                 }
342                 else
343                 {
344                     buffer.put( TLV.getBytes( getCookie().length ) );
345                     buffer.put( getCookie() );
346                 }
347 
348                 break;
349 
350             case REFRESH_DELETE:
351                 // The second case : refreshDelete
352                 buffer.put( ( byte ) SyncInfoValueTags.REFRESH_DELETE_TAG.getValue() );
353                 buffer.put( TLV.getBytes( syncInfoValueLength ) );
354 
355                 // The cookie, if any
356                 if ( getCookie() != null )
357                 {
358                     BerValue.encode( buffer, getCookie() );
359                 }
360 
361                 // The refreshDone flag
362                 if ( !isRefreshDone() )
363                 {
364                     BerValue.encode( buffer, isRefreshDone() );
365                 }
366 
367                 break;
368 
369             case REFRESH_PRESENT:
370                 // The third case : refreshPresent
371                 buffer.put( ( byte ) SyncInfoValueTags.REFRESH_PRESENT_TAG.getValue() );
372                 buffer.put( TLV.getBytes( syncInfoValueLength ) );
373 
374                 // The cookie, if any
375                 if ( getCookie() != null )
376                 {
377                     BerValue.encode( buffer, getCookie() );
378                 }
379 
380                 // The refreshDone flag
381                 if ( !isRefreshDone() )
382                 {
383                     BerValue.encode( buffer, isRefreshDone() );
384                 }
385 
386                 break;
387 
388             case SYNC_ID_SET:
389                 // The last case : syncIdSet
390                 buffer.put( ( byte ) SyncInfoValueTags.SYNC_ID_SET_TAG.getValue() );
391                 buffer.put( TLV.getBytes( syncInfoValueLength ) );
392 
393                 // The cookie, if any
394                 if ( getCookie() != null )
395                 {
396                     BerValue.encode( buffer, getCookie() );
397                 }
398 
399                 // The refreshDeletes flag if not false
400                 if ( isRefreshDeletes() )
401                 {
402                     BerValue.encode( buffer, isRefreshDeletes() );
403                 }
404 
405                 // The syncUUIDs
406                 buffer.put( UniversalTag.SET.getValue() );
407                 buffer.put( TLV.getBytes( syncUUIDsLength ) );
408 
409                 // Loop on the UUIDs if any
410                 if ( getSyncUUIDs().size() != 0 )
411                 {
412                     for ( byte[] syncUUID : getSyncUUIDs() )
413                     {
414                         BerValue.encode( buffer, syncUUID );
415                     }
416                 }
417         }
418 
419         return buffer;
420     }
421 
422 
423     /**
424      * {@inheritDoc}
425      */
426     @Override
427     public byte[] getValue()
428     {
429         if ( value == null )
430         {
431             try
432             {
433                 computeLength();
434                 ByteBuffer buffer = ByteBuffer.allocate( valueLength );
435 
436                 switch ( getType() )
437                 {
438                     case NEW_COOKIE:
439                         // The first case : newCookie
440                         buffer.put( ( byte ) SyncInfoValueTags.NEW_COOKIE_TAG.getValue() );
441 
442                         // As the OCTET_STRING is absorbed by the Application tag,
443                         // we have to store the L and V separately
444                         if ( ( getCookie() == null ) || ( getCookie().length == 0 ) )
445                         {
446                             buffer.put( ( byte ) 0 );
447                         }
448                         else
449                         {
450                             buffer.put( TLV.getBytes( getCookie().length ) );
451                             buffer.put( getCookie() );
452                         }
453 
454                         break;
455 
456                     case REFRESH_DELETE:
457                         // The second case : refreshDelete
458                         buffer.put( ( byte ) SyncInfoValueTags.REFRESH_DELETE_TAG.getValue() );
459                         buffer.put( TLV.getBytes( syncInfoValueLength ) );
460 
461                         // The cookie, if any
462                         if ( getCookie() != null )
463                         {
464                             BerValue.encode( buffer, getCookie() );
465                         }
466 
467                         // The refreshDone flag
468                         if ( !isRefreshDone() )
469                         {
470                             BerValue.encode( buffer, isRefreshDone() );
471                         }
472 
473                         break;
474 
475                     case REFRESH_PRESENT:
476                         // The third case : refreshPresent
477                         buffer.put( ( byte ) SyncInfoValueTags.REFRESH_PRESENT_TAG.getValue() );
478                         buffer.put( TLV.getBytes( syncInfoValueLength ) );
479 
480                         // The cookie, if any
481                         if ( getCookie() != null )
482                         {
483                             BerValue.encode( buffer, getCookie() );
484                         }
485 
486                         // The refreshDone flag
487                         if ( !isRefreshDone() )
488                         {
489                             BerValue.encode( buffer, isRefreshDone() );
490                         }
491 
492                         break;
493 
494                     case SYNC_ID_SET:
495                         // The last case : syncIdSet
496                         buffer.put( ( byte ) SyncInfoValueTags.SYNC_ID_SET_TAG.getValue() );
497                         buffer.put( TLV.getBytes( syncInfoValueLength ) );
498 
499                         // The cookie, if any
500                         if ( getCookie() != null )
501                         {
502                             BerValue.encode( buffer, getCookie() );
503                         }
504 
505                         // The refreshDeletes flag if not false
506                         if ( isRefreshDeletes() )
507                         {
508                             BerValue.encode( buffer, isRefreshDeletes() );
509                         }
510 
511                         // The syncUUIDs
512                         buffer.put( UniversalTag.SET.getValue() );
513                         buffer.put( TLV.getBytes( syncUUIDsLength ) );
514 
515                         // Loop on the UUIDs if any
516                         if ( getSyncUUIDs().size() != 0 )
517                         {
518                             for ( byte[] syncUUID : getSyncUUIDs() )
519                             {
520                                 BerValue.encode( buffer, syncUUID );
521                             }
522                         }
523                 }
524 
525                 value = buffer.array();
526             }
527             catch ( EncoderException e )
528             {
529                 return null;
530             }
531         }
532 
533         return value;
534     }
535 
536 
537     /**
538      * {@inheritDoc}
539      */
540     public Asn1Object decode( byte[] controlBytes ) throws DecoderException
541     {
542         ByteBuffer bb = ByteBuffer.wrap( controlBytes );
543         SyncInfoValueContainer container = new SyncInfoValueContainer( getCodecService(), this );
544         decoder.decode( bb, container );
545         return this;
546     }
547 
548 
549     /**
550      * @see Object#toString()
551      */
552     public String toString()
553     {
554         return getDecorated().toString();
555     }
556 }