001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements. See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership. The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License. You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied. See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 *
019 */
020 package org.apache.directory.shared.ldap.codec.controls.replication.syncInfoValue;
021
022 import java.nio.ByteBuffer;
023 import java.util.ArrayList;
024 import java.util.List;
025
026 import org.apache.directory.shared.asn1.ber.tlv.TLV;
027 import org.apache.directory.shared.asn1.ber.tlv.UniversalTag;
028 import org.apache.directory.shared.asn1.ber.tlv.Value;
029 import org.apache.directory.shared.asn1.codec.EncoderException;
030 import org.apache.directory.shared.i18n.I18n;
031 import org.apache.directory.shared.ldap.codec.controls.AbstractControl;
032 import org.apache.directory.shared.ldap.message.control.replication.SynchronizationInfoEnum;
033 import org.apache.directory.shared.ldap.util.StringTools;
034
035 /**
036 * A syncInfoValue object, as defined in RFC 4533
037 *
038 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
039 * @version $Rev:$, $Date:
040 */
041 public class SyncInfoValueControl extends AbstractControl
042 {
043 /** This control OID */
044 public static final String CONTROL_OID = "1.3.6.1.4.1.4203.1.9.1.4";
045
046 /** The kind of syncInfoValue we are dealing with */
047 private SynchronizationInfoEnum type;
048
049 /** The cookie */
050 private byte[] cookie;
051
052 /** The refreshDone flag if we are dealing with refreshXXX syncInfo. Default to true */
053 private boolean refreshDone = true;
054
055 /** The refreshDeletes flag if we are dealing with syncIdSet syncInfo. Defaluts to false */
056 private boolean refreshDeletes = false;
057
058 /** The list of UUIDs if we are dealing with syncIdSet syncInfo */
059 private List<byte[]> syncUUIDs;
060
061 /** The syncUUIDs cumulative lentgh */
062 private int syncUUIDsLength;
063
064
065 /**
066 * The constructor for this codec.
067 * @param type The kind of syncInfo we will store. Can be newCookie,
068 * refreshPresent, refreshDelete or syncIdSet
069 */
070 public SyncInfoValueControl( SynchronizationInfoEnum type )
071 {
072 super( CONTROL_OID );
073
074 decoder = new SyncInfoValueControlDecoder();
075 this.type = type;
076
077 // Initialize the arrayList if needed
078 if ( type == SynchronizationInfoEnum.SYNC_ID_SET )
079 {
080 syncUUIDs = new ArrayList<byte[]>();
081 }
082 }
083
084
085 /** The global length for this control */
086 private int syncInfoValueLength;
087
088 /**
089 * Get the control type.
090 *
091 * @return the type : one of newCookie, refreshDelete, refreshPresent or syncIdSet
092 */
093 public SynchronizationInfoEnum getType()
094 {
095 return type;
096 }
097
098
099 /**
100 * @param syncMode the syncMode to set
101 */
102 public void setType( SynchronizationInfoEnum type )
103 {
104 this.type = type;
105 }
106
107
108 /**
109 * @return the cookie
110 */
111 public byte[] getCookie()
112 {
113 return cookie;
114 }
115
116
117 /**
118 * @param cookie the cookie to set
119 */
120 public void setCookie( byte[] cookie )
121 {
122 this.cookie = cookie;
123 }
124
125
126 /**
127 * @return the refreshDone
128 */
129 public boolean isRefreshDone()
130 {
131 return refreshDone;
132 }
133
134
135 /**
136 * @param refreshDone the refreshDone to set
137 */
138 public void setRefreshDone( boolean refreshDone )
139 {
140 this.refreshDone = refreshDone;
141 }
142
143
144 /**
145 * @return the refreshDeletes
146 */
147 public boolean isRefreshDeletes()
148 {
149 return refreshDeletes;
150 }
151
152
153 /**
154 * @param refreshDeletes the refreshDeletes to set
155 */
156 public void setRefreshDeletes( boolean refreshDeletes )
157 {
158 this.refreshDeletes = refreshDeletes;
159 }
160
161
162 /**
163 * @return the syncUUIDs
164 */
165 public List<byte[]> getSyncUUIDs()
166 {
167 return syncUUIDs;
168 }
169
170
171 /**
172 * @param syncUUIDs the syncUUIDs to set
173 */
174 public void setSyncUUIDs( List<byte[]> syncUUIDs )
175 {
176 this.syncUUIDs = syncUUIDs;
177 }
178
179
180 /**
181 * @param syncUUIDs the syncUUIDs to set
182 */
183 public void addSyncUUID( byte[] syncUUID )
184 {
185 syncUUIDs.add( syncUUID );
186 }
187
188
189
190
191 /**
192 * Compute the SyncInfoValue length.
193 *
194 * SyncInfoValue :
195 *
196 * 0xA0 L1 abcd // newCookie
197 * 0xA1 L2 // refreshDelete
198 * |
199 * [+--> 0x04 L3 abcd] // cookie
200 * [+--> 0x01 0x01 (0x00|0xFF) // refreshDone
201 * 0xA2 L4 // refreshPresent
202 * |
203 * [+--> 0x04 L5 abcd] // cookie
204 * [+--> 0x01 0x01 (0x00|0xFF) // refreshDone
205 * 0xA3 L6 // syncIdSet
206 * |
207 * [+--> 0x04 L7 abcd] // cookie
208 * [+--> 0x01 0x01 (0x00|0xFF) // refreshDeletes
209 * +--> 0x31 L8 // SET OF syncUUIDs
210 * |
211 * [+--> 0x04 L9 abcd] // syncUUID public static final int AND_FILTER_TAG = 0xA0;
212
213 public static final int OR_FILTER_TAG = 0xA1;
214
215 public static final int NOT_FILTER_TAG = 0xA2;
216
217 public static final int BIND_REQUEST_SASL_TAG = 0xA3;
218
219 */
220 public int computeLength()
221 {
222 // The mode length
223 syncInfoValueLength = 0;
224
225 switch ( type )
226 {
227 case NEW_COOKIE :
228 if ( cookie != null )
229 {
230 syncInfoValueLength = 1 + TLV.getNbBytes( cookie.length ) + cookie.length;
231 }
232 else
233 {
234 syncInfoValueLength = 1 + 1;
235 }
236
237 valueLength = syncInfoValueLength;
238
239 // Call the super class to compute the global control length
240 return super.computeLength( valueLength );
241
242 case REFRESH_DELETE :
243 case REFRESH_PRESENT :
244 if ( cookie != null )
245 {
246 syncInfoValueLength = 1 + TLV.getNbBytes( cookie.length ) + cookie.length;
247 }
248
249 // The refreshDone flag, only if not true, as it default to true
250 if ( !refreshDone )
251 {
252 syncInfoValueLength += 1 + 1 + 1;
253 }
254
255 valueLength = 1 + TLV.getNbBytes( syncInfoValueLength ) + syncInfoValueLength;
256
257 // Call the super class to compute the global control length
258 return super.computeLength( valueLength );
259
260 case SYNC_ID_SET :
261 if ( cookie != null )
262 {
263 syncInfoValueLength = 1 + TLV.getNbBytes( cookie.length ) + cookie.length;
264 }
265
266 // The refreshDeletes flag, default to false
267 if ( refreshDeletes )
268 {
269 syncInfoValueLength += 1 + 1 + 1;
270 }
271
272 // The syncUUIDs if any
273 syncUUIDsLength = 0;
274
275 if ( syncUUIDs.size() != 0 )
276 {
277 for ( byte[] syncUUID:syncUUIDs )
278 {
279 int uuidLength = 1 + TLV.getNbBytes( syncUUID.length ) + syncUUID.length;
280
281 syncUUIDsLength += uuidLength;
282 }
283 }
284
285 syncInfoValueLength += 1 + TLV.getNbBytes( syncUUIDsLength ) + syncUUIDsLength;
286 valueLength = 1 + TLV.getNbBytes( syncInfoValueLength ) + syncInfoValueLength;
287
288 // Call the super class to compute the global control length
289 return super.computeLength( valueLength );
290 }
291
292 return 1 + TLV.getNbBytes( syncInfoValueLength ) + syncInfoValueLength;
293 }
294
295
296 /**
297 * Encode the SyncInfoValue control
298 *
299 * @param buffer The encoded sink
300 * @return A ByteBuffer that contains the encoded PDU
301 * @throws EncoderException If anything goes wrong.
302 */
303 public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
304 {
305 if ( buffer == null )
306 {
307 throw new EncoderException( I18n.err( I18n.ERR_04023 ) );
308 }
309
310 // Encode the Control envelop
311 super.encode( buffer );
312
313 // Encode the OCTET_STRING tag
314 buffer.put( UniversalTag.OCTET_STRING_TAG );
315 buffer.put( TLV.getBytes( valueLength ) );
316
317 switch ( type )
318 {
319 case NEW_COOKIE :
320 // The first case : newCookie
321 buffer.put( (byte)SyncInfoValueTags.NEW_COOKIE_TAG.getValue() );
322
323 // As the OCTET_STRING is absorbed by the Application tag,
324 // we have to store the L and V separately
325 if ( ( cookie == null ) || ( cookie.length == 0 ) )
326 {
327 buffer.put( ( byte ) 0 );
328 }
329 else
330 {
331 buffer.put( TLV.getBytes( cookie.length ) );
332 buffer.put( cookie );
333 }
334
335 break;
336
337 case REFRESH_DELETE :
338 // The second case : refreshDelete
339 buffer.put( (byte)SyncInfoValueTags.REFRESH_DELETE_TAG.getValue() );
340 buffer.put( TLV.getBytes( syncInfoValueLength ) );
341
342 // The cookie, if any
343 if ( cookie != null )
344 {
345 Value.encode( buffer, cookie );
346 }
347
348 // The refreshDone flag
349 if ( !refreshDone )
350 {
351 Value.encode( buffer, refreshDone );
352 }
353
354 break;
355
356 case REFRESH_PRESENT :
357 // The third case : refreshPresent
358 buffer.put( (byte)SyncInfoValueTags.REFRESH_PRESENT_TAG.getValue() );
359 buffer.put( TLV.getBytes( syncInfoValueLength ) );
360
361 // The cookie, if any
362 if ( cookie != null )
363 {
364 Value.encode( buffer, cookie );
365 }
366
367 // The refreshDone flag
368 if ( !refreshDone )
369 {
370 Value.encode( buffer, refreshDone );
371 }
372
373 break;
374
375 case SYNC_ID_SET :
376 // The last case : syncIdSet
377 buffer.put( (byte)SyncInfoValueTags.SYNC_ID_SET_TAG.getValue() );
378 buffer.put( TLV.getBytes( syncInfoValueLength ) );
379
380 // The cookie, if any
381 if ( cookie != null )
382 {
383 Value.encode( buffer, cookie );
384 }
385
386 // The refreshDeletes flag if not false
387 if ( refreshDeletes )
388 {
389 Value.encode( buffer, refreshDeletes );
390 }
391
392 // The syncUUIDs
393 buffer.put( UniversalTag.SET_TAG );
394 buffer.put( TLV.getBytes( syncUUIDsLength ) );
395
396 // Loop on the UUIDs if any
397 if ( syncUUIDs.size() != 0 )
398 {
399 for ( byte[] syncUUID:syncUUIDs )
400 {
401 Value.encode( buffer , syncUUID );
402 }
403 }
404 }
405
406 return buffer;
407 }
408
409
410 /**
411 * {@inheritDoc}
412 */
413 public byte[] getValue()
414 {
415 if ( value == null )
416 {
417 try
418 {
419 computeLength();
420 ByteBuffer buffer = ByteBuffer.allocate( valueLength );
421
422 switch ( type )
423 {
424 case NEW_COOKIE :
425 // The first case : newCookie
426 buffer.put( (byte)SyncInfoValueTags.NEW_COOKIE_TAG.getValue() );
427
428 // As the OCTET_STRING is absorbed by the Application tag,
429 // we have to store the L and V separately
430 if ( ( cookie == null ) || ( cookie.length == 0 ) )
431 {
432 buffer.put( ( byte ) 0 );
433 }
434 else
435 {
436 buffer.put( TLV.getBytes( cookie.length ) );
437 buffer.put( cookie );
438 }
439
440 break;
441
442 case REFRESH_DELETE :
443 // The second case : refreshDelete
444 buffer.put( (byte)SyncInfoValueTags.REFRESH_DELETE_TAG.getValue() );
445 buffer.put( TLV.getBytes( syncInfoValueLength ) );
446
447 // The cookie, if any
448 if ( cookie != null )
449 {
450 Value.encode( buffer, cookie );
451 }
452
453 // The refreshDone flag
454 if ( !refreshDone )
455 {
456 Value.encode( buffer, refreshDone );
457 }
458
459 break;
460
461 case REFRESH_PRESENT :
462 // The third case : refreshPresent
463 buffer.put( (byte)SyncInfoValueTags.REFRESH_PRESENT_TAG.getValue() );
464 buffer.put( TLV.getBytes( syncInfoValueLength ) );
465
466 // The cookie, if any
467 if ( cookie != null )
468 {
469 Value.encode( buffer, cookie );
470 }
471
472 // The refreshDone flag
473 if ( !refreshDone )
474 {
475 Value.encode( buffer, refreshDone );
476 }
477
478 break;
479
480 case SYNC_ID_SET :
481 // The last case : syncIdSet
482 buffer.put( (byte)SyncInfoValueTags.SYNC_ID_SET_TAG.getValue() );
483 buffer.put( TLV.getBytes( syncInfoValueLength ) );
484
485 // The cookie, if any
486 if ( cookie != null )
487 {
488 Value.encode( buffer, cookie );
489 }
490
491 // The refreshDeletes flag if not false
492 if ( refreshDeletes )
493 {
494 Value.encode( buffer, refreshDeletes );
495 }
496
497 // The syncUUIDs
498 buffer.put( UniversalTag.SET_TAG );
499 buffer.put( TLV.getBytes( syncUUIDsLength ) );
500
501 // Loop on the UUIDs if any
502 if ( syncUUIDs.size() != 0 )
503 {
504 for ( byte[] syncUUID:syncUUIDs )
505 {
506 Value.encode( buffer , syncUUID );
507 }
508 }
509 }
510
511 value = buffer.array();
512 }
513 catch ( Exception e )
514 {
515 return null;
516 }
517 }
518
519 return value;
520 }
521
522
523 /**
524 * @see Object#toString()
525 */
526 public String toString()
527 {
528 StringBuilder sb = new StringBuilder();
529
530 sb.append( " SyncInfoValue control :\n" );
531 sb.append( " oid : " ).append( getOid() ).append( '\n' );
532 sb.append( " critical : " ).append( isCritical() ).append( '\n' );
533
534 switch ( type )
535 {
536 case NEW_COOKIE :
537 sb.append( " newCookie : '" ).
538 append( StringTools.dumpBytes( cookie ) ).append( "'\n" );
539 break;
540
541 case REFRESH_DELETE :
542 sb.append( " refreshDelete : \n" );
543
544 if ( cookie != null )
545 {
546 sb.append( " cookie : '" ).
547 append( StringTools.dumpBytes( cookie ) ).append( "'\n" );
548 }
549
550 sb.append( " refreshDone : " ).append( refreshDone ).append( '\n' );
551 break;
552
553 case REFRESH_PRESENT :
554 sb.append( " refreshPresent : \n" );
555
556 if ( cookie != null )
557 {
558 sb.append( " cookie : '" ).
559 append( StringTools.dumpBytes( cookie ) ).append( "'\n" );
560 }
561
562 sb.append( " refreshDone : " ).append( refreshDone ).append( '\n' );
563 break;
564
565 case SYNC_ID_SET :
566 sb.append( " syncIdSet : \n" );
567
568 if ( cookie != null )
569 {
570 sb.append( " cookie : '" ).
571 append( StringTools.dumpBytes( cookie ) ).append( "'\n" );
572 }
573
574 sb.append( " refreshDeletes : " ).append( refreshDeletes ).append( '\n' );
575 sb.append( " syncUUIDS : " );
576
577 if ( syncUUIDs.size() != 0 )
578 {
579 boolean isFirst = true;
580
581 for ( byte[] syncUUID:syncUUIDs )
582 {
583 if ( isFirst )
584 {
585 isFirst = false;
586 }
587 else
588 {
589 sb.append( ", " );
590 }
591
592 sb.append( syncUUID );
593 }
594
595 sb.append( '\n' );
596 }
597 else
598 {
599 sb.append( "empty\n" );
600 }
601
602 break;
603 }
604
605 return sb.toString();
606 }
607 }