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 }