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 */ 020package org.apache.directory.api.ldap.model.ldif; 021 022 023import java.io.Externalizable; 024import java.io.IOException; 025import java.io.ObjectInput; 026import java.io.ObjectOutput; 027import java.util.HashMap; 028import java.util.LinkedList; 029import java.util.List; 030import java.util.Map; 031import java.util.concurrent.ConcurrentHashMap; 032 033import org.apache.directory.api.i18n.I18n; 034import org.apache.directory.api.ldap.model.entry.Attribute; 035import org.apache.directory.api.ldap.model.entry.DefaultAttribute; 036import org.apache.directory.api.ldap.model.entry.DefaultEntry; 037import org.apache.directory.api.ldap.model.entry.DefaultModification; 038import org.apache.directory.api.ldap.model.entry.Entry; 039import org.apache.directory.api.ldap.model.entry.Modification; 040import org.apache.directory.api.ldap.model.entry.ModificationOperation; 041import org.apache.directory.api.ldap.model.entry.StringValue; 042import org.apache.directory.api.ldap.model.entry.Value; 043import org.apache.directory.api.ldap.model.exception.LdapException; 044import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException; 045import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException; 046import org.apache.directory.api.ldap.model.message.Control; 047import org.apache.directory.api.ldap.model.message.ResultCodeEnum; 048import org.apache.directory.api.ldap.model.name.Dn; 049import org.apache.directory.api.ldap.model.name.Rdn; 050import org.apache.directory.api.util.Base64; 051import org.apache.directory.api.util.Strings; 052 053 054/** 055 * A entry to be populated by an ldif parser. 056 * 057 * We will have different kind of entries : 058 * <ul> 059 * <li>added entries</li> 060 * <li>deleted entries</li> 061 * <li>modified entries</li> 062 * <li>Rdn modified entries</li> 063 * <li>Dn modified entries</li> 064 * </ul> 065 * 066 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 067 */ 068public class LdifEntry implements Cloneable, Externalizable 069{ 070 /** Used in toArray() */ 071 public static final Modification[] EMPTY_MODS = new Modification[0]; 072 073 /** the change type */ 074 private ChangeType changeType; 075 076 /** the modification item list */ 077 private List<Modification> modificationList; 078 079 /** The map containing all the modifications */ 080 private Map<String, Modification> modifications; 081 082 /** The new superior */ 083 private String newSuperior; 084 085 /** The new rdn */ 086 private String newRdn; 087 088 /** The delete old rdn flag */ 089 private boolean deleteOldRdn; 090 091 /** the entry */ 092 private Entry entry; 093 094 /** the DN */ 095 private Dn entryDn; 096 097 /** The controls */ 098 private Map<String, LdifControl> controls; 099 100 /** The lengthBeforeParsing of the entry at the time of parsing. This includes 101 * the lengthBeforeParsing of the comments present in entry at the time of parsing 102 * so this lengthBeforeParsing may not always match with the lengthBeforeParsing of the entry 103 * data present in memory. 104 */ 105 private int lengthBeforeParsing = 0; 106 107 /** the position of the entry in the file or given input string*/ 108 private long offset = 0; 109 110 /** 111 * Creates a new LdifEntry object. 112 */ 113 public LdifEntry() 114 { 115 changeType = ChangeType.None; // Default LDIF content 116 modificationList = new LinkedList<Modification>(); 117 modifications = new HashMap<String, Modification>(); 118 entry = new DefaultEntry( ( Dn ) null ); 119 entryDn = null; 120 controls = null; 121 } 122 123 124 /** 125 * Creates a new LdifEntry object, storing an Entry 126 */ 127 public LdifEntry( Entry entry ) 128 { 129 changeType = ChangeType.None; // Default LDIF content 130 modificationList = new LinkedList<Modification>(); 131 modifications = new HashMap<String, Modification>(); 132 this.entry = entry; 133 entryDn = entry.getDn(); 134 controls = null; 135 } 136 137 138 /** 139 * Creates a LdifEntry using a list of strings representing the Ldif element 140 * 141 * @param dn The LdifEntry DN 142 * @param avas The Ldif to convert to an LdifEntry 143 * @throws LdapInvalidAttributeValueException If either the AttributeType or the associated value 144 * is incorrect 145 * @throws LdapLdifException If we get any other exception 146 */ 147 public LdifEntry( Dn dn, Object... avas ) throws LdapInvalidAttributeValueException, LdapLdifException 148 { 149 // First, convert the arguments to a full LDIF 150 StringBuilder sb = new StringBuilder(); 151 int pos = 0; 152 boolean valueExpected = false; 153 String dnStr = null; 154 155 if ( dn == null ) 156 { 157 dnStr = ""; 158 } 159 else 160 { 161 dnStr = dn.getName(); 162 } 163 164 if ( LdifUtils.isLDIFSafe( dnStr ) ) 165 { 166 sb.append( "dn: " ).append( dnStr ).append( '\n' ); 167 } 168 else 169 { 170 sb.append( "dn:: " ).append( Base64.encode( Strings.getBytesUtf8( dnStr ) ) ).append( '\n' ); 171 } 172 173 for ( Object ava : avas ) 174 { 175 if ( !valueExpected ) 176 { 177 if ( !( ava instanceof String ) ) 178 { 179 throw new LdapInvalidAttributeValueException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, I18n.err( 180 I18n.ERR_12085, ( pos + 1 ) ) ); 181 } 182 183 String attribute = ( String ) ava; 184 sb.append( attribute ); 185 186 if ( attribute.indexOf( ':' ) != -1 ) 187 { 188 sb.append( '\n' ); 189 } 190 else 191 { 192 valueExpected = true; 193 } 194 } 195 else 196 { 197 if ( ava instanceof String ) 198 { 199 sb.append( ": " ).append( ( String ) ava ).append( '\n' ); 200 } 201 else if ( ava instanceof byte[] ) 202 { 203 sb.append( ":: " ); 204 sb.append( new String( Base64.encode( ( byte[] ) ava ) ) ); 205 sb.append( '\n' ); 206 } 207 else 208 { 209 throw new LdapInvalidAttributeValueException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, I18n.err( 210 I18n.ERR_12086, ( pos + 1 ) ) ); 211 } 212 213 valueExpected = false; 214 } 215 } 216 217 if ( valueExpected ) 218 { 219 throw new LdapInvalidAttributeValueException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, I18n 220 .err( I18n.ERR_12087 ) ); 221 } 222 223 // Now, parse the Ldif and convert it to a LdifEntry 224 LdifReader reader = new LdifReader(); 225 List<LdifEntry> ldifEntries = reader.parseLdif( sb.toString() ); 226 227 try 228 { 229 reader.close(); 230 } 231 catch ( IOException e ) 232 { 233 e.printStackTrace(); 234 } 235 236 if ( ( ldifEntries != null ) && ( ldifEntries.size() == 1 ) ) 237 { 238 LdifEntry ldifEntry = ldifEntries.get( 0 ); 239 240 changeType = ldifEntry.getChangeType(); 241 controls = ldifEntry.getControls(); 242 entryDn = ldifEntry.getDn(); 243 244 switch ( ldifEntry.getChangeType() ) 245 { 246 case Add: 247 // Fallback 248 case None: 249 entry = ldifEntry.getEntry(); 250 break; 251 252 case Delete: 253 break; 254 255 case ModDn: 256 case ModRdn: 257 newRdn = ldifEntry.getNewRdn(); 258 newSuperior = ldifEntry.getNewSuperior(); 259 deleteOldRdn = ldifEntry.isDeleteOldRdn(); 260 break; 261 262 case Modify: 263 modificationList = ldifEntry.getModifications(); 264 modifications = new HashMap<String, Modification>(); 265 266 for ( Modification modification : modificationList ) 267 { 268 modifications.put( modification.getAttribute().getId(), modification ); 269 } 270 271 break; 272 } 273 } 274 } 275 276 277 /** 278 * Creates a LdifEntry using a list of strings representing the Ldif element 279 * 280 * @param dn The LdifEntry DN 281 * @param avas The Ldif attributes and values to convert to an LdifEntry 282 * @throws LdapInvalidDnException If the Dn is invalid 283 * @throws LdapInvalidAttributeValueException If either the AttributeType or the associated value 284 * is incorrect 285 * @throws LdapLdifException If we get any other exception 286 */ 287 public LdifEntry( String dn, Object... strings ) 288 throws LdapInvalidAttributeValueException, LdapLdifException, LdapInvalidDnException 289 { 290 this( new Dn( dn ), strings ); 291 } 292 293 294 /** 295 * Set the Distinguished Name 296 * 297 * @param dn The Distinguished Name 298 */ 299 public void setDn( Dn dn ) 300 { 301 entryDn = dn; 302 entry.setDn( dn ); 303 } 304 305 306 /** 307 * Set the Distinguished Name 308 * 309 * @param dn The Distinguished Name 310 * @throws LdapInvalidDnException If the Dn is invalid 311 */ 312 public void setDn( String dn ) throws LdapInvalidDnException 313 { 314 entryDn = new Dn( dn ); 315 entry.setDn( entryDn ); 316 } 317 318 319 /** 320 * Set the modification type 321 * 322 * @param changeType The change type 323 * 324 */ 325 public void setChangeType( ChangeType changeType ) 326 { 327 this.changeType = changeType; 328 } 329 330 331 /** 332 * Set the change type 333 * 334 * @param changeType The change type 335 */ 336 public void setChangeType( String changeType ) 337 { 338 if ( "add".equals( changeType ) ) 339 { 340 this.changeType = ChangeType.Add; 341 } 342 else if ( "modify".equals( changeType ) ) 343 { 344 this.changeType = ChangeType.Modify; 345 } 346 else if ( "moddn".equals( changeType ) ) 347 { 348 this.changeType = ChangeType.ModDn; 349 } 350 else if ( "modrdn".equals( changeType ) ) 351 { 352 this.changeType = ChangeType.ModRdn; 353 } 354 else if ( "delete".equals( changeType ) ) 355 { 356 this.changeType = ChangeType.Delete; 357 } 358 } 359 360 361 /** 362 * Add a modification item (used by modify operations) 363 * 364 * @param modification The modification to be added 365 */ 366 public void addModification( Modification modification ) 367 { 368 if ( changeType == ChangeType.Modify ) 369 { 370 modificationList.add( modification ); 371 modifications.put( modification.getAttribute().getId(), modification ); 372 } 373 } 374 375 376 /** 377 * Add a modification item (used by modify operations) 378 * 379 * @param modOp The operation. One of : 380 * <ul> 381 * <li>ModificationOperation.ADD_ATTRIBUTE</li> 382 * <li>ModificationOperation.REMOVE_ATTRIBUTE</li> 383 * <li>ModificationOperation.REPLACE_ATTRIBUTE</li> 384 * </ul> 385 * 386 * @param attr The attribute to be added 387 */ 388 public void addModification( ModificationOperation modOp, Attribute attr ) 389 { 390 if ( changeType == ChangeType.Modify ) 391 { 392 Modification item = new DefaultModification( modOp, attr ); 393 modificationList.add( item ); 394 modifications.put( attr.getId(), item ); 395 } 396 } 397 398 399 /** 400 * Add a modification 401 * 402 * @param modOp The modification operation value. One of : 403 * <ul> 404 * <li>ModificationOperation.ADD_ATTRIBUTE</li> 405 * <li>ModificationOperation.REMOVE_ATTRIBUTE</li> 406 * <li>ModificationOperation.REPLACE_ATTRIBUTE</li> 407 * </ul> 408 * 409 * @param id The attribute's ID 410 * @param value The attribute's value 411 */ 412 public void addModification( ModificationOperation modOp, String id, Object value ) 413 { 414 if ( changeType == ChangeType.Modify ) 415 { 416 Attribute attr; 417 418 if ( value == null ) 419 { 420 value = new StringValue( ( String ) null ); 421 attr = new DefaultAttribute( id, ( Value<?> ) value ); 422 } 423 else 424 { 425 attr = ( Attribute ) value; 426 } 427 428 Modification item = new DefaultModification( modOp, attr ); 429 modificationList.add( item ); 430 modifications.put( id, item ); 431 } 432 } 433 434 435 /** 436 * Add an attribute to the entry 437 * 438 * @param attr The attribute to be added 439 * @throws org.apache.directory.api.ldap.model.exception.LdapException if something went wrong 440 */ 441 public void addAttribute( Attribute attr ) throws LdapException 442 { 443 entry.put( attr ); 444 } 445 446 447 /** 448 * Add an attribute to the entry 449 * 450 * @param id The attribute ID 451 * 452 * @param values The attribute values 453 * @throws LdapException if something went wrong 454 */ 455 public void addAttribute( String id, Object... values ) throws LdapException 456 { 457 if ( values != null ) 458 { 459 for ( Object value : values ) 460 { 461 if ( value instanceof String ) 462 { 463 entry.add( id, ( String ) value ); 464 } 465 else 466 { 467 entry.add( id, ( byte[] ) value ); 468 } 469 } 470 } 471 else 472 { 473 entry.add( id, ( Value<?> ) null ); 474 } 475 } 476 477 478 /** 479 * Remove a list of Attributes from the LdifEntry 480 * 481 * @param ids The Attributes to remove 482 * @return The list of removed EntryAttributes 483 */ 484 public void removeAttribute( String... ids ) 485 { 486 if ( entry.containsAttribute( ids ) ) 487 { 488 entry.removeAttributes( ids ); 489 } 490 } 491 492 493 /** 494 * Add an attribute value to an existing attribute 495 * 496 * @param id The attribute ID 497 * 498 * @param value The attribute value 499 * @throws org.apache.directory.api.ldap.model.exception.LdapException if something went wrong 500 */ 501 public void putAttribute( String id, Object value ) throws LdapException 502 { 503 if ( value instanceof String ) 504 { 505 entry.add( id, ( String ) value ); 506 } 507 else 508 { 509 entry.add( id, ( byte[] ) value ); 510 } 511 } 512 513 514 /** 515 * Get the change type 516 * 517 * @return The change type. One of : 518 * <ul> 519 * <li>ADD</li> 520 * <li>MODIFY</li> 521 * <li>MODDN</li> 522 * <li>MODRDN</li> 523 * <li>DELETE</li> 524 * <li>NONE</li> 525 * </ul> 526 */ 527 public ChangeType getChangeType() 528 { 529 return changeType; 530 } 531 532 533 /** 534 * @return The list of modification items 535 */ 536 public List<Modification> getModifications() 537 { 538 return modificationList; 539 } 540 541 542 /** 543 * Gets the modification items as an array. 544 * 545 * @return modification items as an array. 546 */ 547 public Modification[] getModificationArray() 548 { 549 return modificationList.toArray( EMPTY_MODS ); 550 } 551 552 553 /** 554 * @return The entry Distinguished name 555 */ 556 public Dn getDn() 557 { 558 return entryDn; 559 } 560 561 562 /** 563 * @return The number of entry modifications 564 */ 565 public int size() 566 { 567 return modificationList.size(); 568 } 569 570 571 /** 572 * Returns a attribute given it's id 573 * 574 * @param attributeId The attribute Id 575 * @return The attribute if it exists 576 */ 577 public Attribute get( String attributeId ) 578 { 579 if ( "dn".equalsIgnoreCase( attributeId ) ) 580 { 581 return new DefaultAttribute( "dn", entry.getDn().getName() ); 582 } 583 584 return entry.get( attributeId ); 585 } 586 587 588 /** 589 * Get the entry's entry 590 * 591 * @return the stored Entry 592 */ 593 public Entry getEntry() 594 { 595 if ( isEntry() ) 596 { 597 return entry; 598 } 599 else 600 { 601 return null; 602 } 603 } 604 605 606 /** 607 * @return True, if the old Rdn should be deleted. 608 */ 609 public boolean isDeleteOldRdn() 610 { 611 return deleteOldRdn; 612 } 613 614 615 /** 616 * Set the flage deleteOldRdn 617 * 618 * @param deleteOldRdn True if the old Rdn should be deleted 619 */ 620 public void setDeleteOldRdn( boolean deleteOldRdn ) 621 { 622 this.deleteOldRdn = deleteOldRdn; 623 } 624 625 626 /** 627 * @return The new Rdn 628 */ 629 public String getNewRdn() 630 { 631 return newRdn; 632 } 633 634 635 /** 636 * Set the new Rdn 637 * 638 * @param newRdn The new Rdn 639 */ 640 public void setNewRdn( String newRdn ) 641 { 642 this.newRdn = newRdn; 643 } 644 645 646 /** 647 * @return The new superior 648 */ 649 public String getNewSuperior() 650 { 651 return newSuperior; 652 } 653 654 655 /** 656 * Set the new superior 657 * 658 * @param newSuperior The new Superior 659 */ 660 public void setNewSuperior( String newSuperior ) 661 { 662 this.newSuperior = newSuperior; 663 } 664 665 666 /** 667 * @return True if this is a content ldif 668 */ 669 public boolean isLdifContent() 670 { 671 return changeType == ChangeType.None; 672 } 673 674 675 /** 676 * @return True if there is this is a change ldif 677 */ 678 public boolean isLdifChange() 679 { 680 return changeType != ChangeType.None; 681 } 682 683 684 /** 685 * @return True if the entry is an ADD entry 686 */ 687 public boolean isChangeAdd() 688 { 689 return changeType == ChangeType.Add; 690 } 691 692 693 /** 694 * @return True if the entry is a DELETE entry 695 */ 696 public boolean isChangeDelete() 697 { 698 return changeType == ChangeType.Delete; 699 } 700 701 702 /** 703 * @return True if the entry is a MODDN entry 704 */ 705 public boolean isChangeModDn() 706 { 707 return changeType == ChangeType.ModDn; 708 } 709 710 711 /** 712 * @return True if the entry is a MODRDN entry 713 */ 714 public boolean isChangeModRdn() 715 { 716 return changeType == ChangeType.ModRdn; 717 } 718 719 720 /** 721 * @return True if the entry is a MODIFY entry 722 */ 723 public boolean isChangeModify() 724 { 725 return changeType == ChangeType.Modify; 726 } 727 728 729 /** 730 * Tells if the current entry is a added one 731 * 732 * @return <code>true</code> if the entry is added 733 */ 734 public boolean isEntry() 735 { 736 return ( changeType == ChangeType.None ) || ( changeType == ChangeType.Add ); 737 } 738 739 740 /** 741 * @return true if the entry has some controls 742 */ 743 public boolean hasControls() 744 { 745 return controls != null; 746 } 747 748 749 /** 750 * @return The set of controls for this entry 751 */ 752 public Map<String, LdifControl> getControls() 753 { 754 return controls; 755 } 756 757 758 /** 759 * @param oid The control's OID 760 * @return The associated control, if any 761 */ 762 public LdifControl getControl( String oid ) 763 { 764 if ( controls != null ) 765 { 766 return controls.get( oid ); 767 } 768 769 return null; 770 } 771 772 773 /** 774 * Add a control to the entry 775 * 776 * @param controls The added controls 777 */ 778 public void addControl( Control... controls ) 779 { 780 if ( controls == null ) 781 { 782 throw new IllegalArgumentException( "The added control must not be null" ); 783 } 784 785 for ( Control control : controls ) 786 { 787 if ( changeType == ChangeType.None ) 788 { 789 changeType = ChangeType.Add; 790 } 791 792 if ( this.controls == null ) 793 { 794 this.controls = new ConcurrentHashMap<String, LdifControl>(); 795 } 796 797 if ( control instanceof LdifControl ) 798 { 799 this.controls.put( control.getOid(), ( LdifControl ) control ); 800 } 801 else 802 { 803 LdifControl ldifControl = new LdifControl( control.getOid() ); 804 ldifControl.setCritical( control.isCritical() ); 805 this.controls.put( control.getOid(), new LdifControl( control.getOid() ) ); 806 } 807 } 808 } 809 810 811 /** 812 * Clone method 813 * @return a clone of the current instance 814 * @exception CloneNotSupportedException If there is some problem while cloning the instance 815 */ 816 public LdifEntry clone() throws CloneNotSupportedException 817 { 818 LdifEntry clone = ( LdifEntry ) super.clone(); 819 820 if ( modificationList != null ) 821 { 822 for ( Modification modif : modificationList ) 823 { 824 Modification modifClone = new DefaultModification( modif.getOperation(), 825 modif.getAttribute().clone() ); 826 clone.modificationList.add( modifClone ); 827 } 828 } 829 830 if ( modifications != null ) 831 { 832 for ( String key : modifications.keySet() ) 833 { 834 Modification modif = modifications.get( key ); 835 Modification modifClone = new DefaultModification( modif.getOperation(), 836 modif.getAttribute().clone() ); 837 clone.modifications.put( key, modifClone ); 838 } 839 840 } 841 842 if ( entry != null ) 843 { 844 clone.entry = entry.clone(); 845 } 846 847 return clone; 848 } 849 850 851 /** 852 * Returns the lengthBeforeParsing of the entry at the time of parsing. This includes 853 * the lengthBeforeParsing of the comments present in entry at the time of parsing 854 * so this lengthBeforeParsing may not always match with the lengthBeforeParsing of the entry 855 * data present in memory. 856 */ 857 public int getLengthBeforeParsing() 858 { 859 return lengthBeforeParsing; 860 } 861 862 863 /** 864 * @param lengthBeforeParsing the lengthBeforeParsing to set 865 */ 866 /**No qualifier*/ void setLengthBeforeParsing( int length ) 867 { 868 this.lengthBeforeParsing = length; 869 } 870 871 872 /** 873 * @return the offset 874 */ 875 public long getOffset() 876 { 877 return offset; 878 } 879 880 881 /** 882 * @param offset the offset to set 883 */ 884 /**No qualifier*/ void setOffset( long offset ) 885 { 886 this.offset = offset; 887 } 888 889 890 /** 891 * @return a String representing the Entry, as a LDIF 892 */ 893 public String toString() 894 { 895 try 896 { 897 return LdifUtils.convertToLdif( this ); 898 } 899 catch ( LdapException ne ) 900 { 901 return ""; 902 } 903 } 904 905 906 /** 907 * @see Object#hashCode() 908 * 909 * @return the instance's hash code 910 */ 911 public int hashCode() 912 { 913 int result = 37; 914 915 if ( entry != null && entry.getDn() != null ) 916 { 917 result = result * 17 + entry.getDn().hashCode(); 918 } 919 920 if ( changeType != null ) 921 { 922 result = result * 17 + changeType.hashCode(); 923 924 // Check each different cases 925 switch ( changeType ) 926 { 927 case None: 928 // Fall through 929 case Add: 930 // Checks the attributes 931 if ( entry != null ) 932 { 933 result = result * 17 + entry.hashCode(); 934 } 935 936 break; 937 938 case Delete: 939 // Nothing to compute 940 break; 941 942 case Modify: 943 if ( modificationList != null ) 944 { 945 result = result * 17 + modificationList.hashCode(); 946 947 for ( Modification modification : modificationList ) 948 { 949 result = result * 17 + modification.hashCode(); 950 } 951 } 952 953 break; 954 955 case ModDn: 956 case ModRdn: 957 result = result * 17; 958 959 if ( deleteOldRdn ) 960 { 961 result++; 962 } 963 else 964 { 965 result--; 966 } 967 968 if ( newRdn != null ) 969 { 970 result = result * 17 + newRdn.hashCode(); 971 } 972 973 if ( newSuperior != null ) 974 { 975 result = result * 17 + newSuperior.hashCode(); 976 } 977 978 break; 979 980 default: 981 break; // do nothing 982 } 983 } 984 985 if ( controls != null ) 986 { 987 for ( String control : controls.keySet() ) 988 { 989 result = result * 17 + control.hashCode(); 990 } 991 } 992 993 return result; 994 } 995 996 997 /** 998 * {@inheritDoc} 999 */ 1000 public boolean equals( Object o ) 1001 { 1002 // Basic equals checks 1003 if ( this == o ) 1004 { 1005 return true; 1006 } 1007 1008 if ( o == null ) 1009 { 1010 return false; 1011 } 1012 1013 if ( !( o instanceof LdifEntry ) ) 1014 { 1015 return false; 1016 } 1017 1018 LdifEntry otherEntry = ( LdifEntry ) o; 1019 1020 // Check the Dn 1021 Dn thisDn = entryDn; 1022 Dn dnEntry = otherEntry.getDn(); 1023 1024 if ( !thisDn.equals( dnEntry ) ) 1025 { 1026 return false; 1027 } 1028 1029 // Check the changeType 1030 if ( changeType != otherEntry.changeType ) 1031 { 1032 return false; 1033 } 1034 1035 // Check each different cases 1036 switch ( changeType ) 1037 { 1038 case None: 1039 // Fall through 1040 case Add: 1041 // Checks the attributes 1042 if ( entry.size() != otherEntry.entry.size() ) 1043 { 1044 return false; 1045 } 1046 1047 if ( !entry.equals( otherEntry.entry ) ) 1048 { 1049 return false; 1050 } 1051 1052 break; 1053 1054 case Delete: 1055 // Nothing to do, if the DNs are equals 1056 break; 1057 1058 case Modify: 1059 // Check the modificationItems list 1060 1061 // First, deal with special cases 1062 if ( modificationList == null ) 1063 { 1064 if ( otherEntry.modificationList != null ) 1065 { 1066 return false; 1067 } 1068 else 1069 { 1070 break; 1071 } 1072 } 1073 1074 if ( otherEntry.modificationList == null ) 1075 { 1076 return false; 1077 } 1078 1079 if ( modificationList.size() != otherEntry.modificationList.size() ) 1080 { 1081 return false; 1082 } 1083 1084 // Now, compares the contents 1085 int i = 0; 1086 1087 for ( Modification modification : modificationList ) 1088 { 1089 if ( !modification.equals( otherEntry.modificationList.get( i ) ) ) 1090 { 1091 return false; 1092 } 1093 1094 i++; 1095 } 1096 1097 break; 1098 1099 case ModDn: 1100 case ModRdn: 1101 // Check the deleteOldRdn flag 1102 if ( deleteOldRdn != otherEntry.deleteOldRdn ) 1103 { 1104 return false; 1105 } 1106 1107 // Check the newRdn value 1108 try 1109 { 1110 Rdn thisNewRdn = new Rdn( newRdn ); 1111 Rdn entryNewRdn = new Rdn( otherEntry.newRdn ); 1112 1113 if ( !thisNewRdn.equals( entryNewRdn ) ) 1114 { 1115 return false; 1116 } 1117 } 1118 catch ( LdapInvalidDnException ine ) 1119 { 1120 return false; 1121 } 1122 1123 // Check the newSuperior value 1124 try 1125 { 1126 Dn thisNewSuperior = new Dn( newSuperior ); 1127 Dn entryNewSuperior = new Dn( otherEntry.newSuperior ); 1128 1129 if ( !thisNewSuperior.equals( entryNewSuperior ) ) 1130 { 1131 return false; 1132 } 1133 } 1134 catch ( LdapInvalidDnException ine ) 1135 { 1136 return false; 1137 } 1138 1139 break; 1140 1141 default: 1142 break; // do nothing 1143 } 1144 1145 if ( controls != null ) 1146 { 1147 Map<String, LdifControl> otherControls = otherEntry.controls; 1148 1149 if ( otherControls == null ) 1150 { 1151 return false; 1152 } 1153 1154 if ( controls.size() != otherControls.size() ) 1155 { 1156 return false; 1157 } 1158 1159 for ( String controlOid : controls.keySet() ) 1160 { 1161 if ( !otherControls.containsKey( controlOid ) ) 1162 { 1163 return false; 1164 } 1165 1166 Control thisControl = controls.get( controlOid ); 1167 Control otherControl = otherControls.get( controlOid ); 1168 1169 if ( thisControl == null ) 1170 { 1171 if ( otherControl != null ) 1172 { 1173 return false; 1174 } 1175 } 1176 else 1177 { 1178 if ( !thisControl.equals( otherControl ) ) 1179 { 1180 return false; 1181 } 1182 } 1183 } 1184 1185 return true; 1186 } 1187 else 1188 { 1189 return otherEntry.controls == null; 1190 } 1191 } 1192 1193 1194 /** 1195 * @see Externalizable#readExternal(ObjectInput) 1196 * 1197 * @param in The stream from which the LdifEntry is read 1198 * @throws IOException If the stream can't be read 1199 * @throws ClassNotFoundException If the LdifEntry can't be created 1200 */ 1201 public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException 1202 { 1203 // Read the changeType 1204 int type = in.readInt(); 1205 changeType = ChangeType.getChangeType( type ); 1206 1207 // Read the modification 1208 switch ( changeType ) 1209 { 1210 case Add: 1211 case None: 1212 // Read the entry 1213 entry.readExternal( in ); 1214 entryDn = entry.getDn(); 1215 1216 break; 1217 1218 case Delete: 1219 // Read the Dn 1220 entryDn = new Dn(); 1221 entryDn.readExternal( in ); 1222 1223 break; 1224 1225 case ModDn: 1226 // Fallback 1227 case ModRdn: 1228 // Read the Dn 1229 entryDn = new Dn(); 1230 entryDn.readExternal( in ); 1231 1232 deleteOldRdn = in.readBoolean(); 1233 1234 if ( in.readBoolean() ) 1235 { 1236 newRdn = in.readUTF(); 1237 } 1238 1239 if ( in.readBoolean() ) 1240 { 1241 newSuperior = in.readUTF(); 1242 } 1243 1244 break; 1245 1246 case Modify: 1247 // Read the Dn 1248 entryDn = new Dn(); 1249 entryDn.readExternal( in ); 1250 1251 // Read the modifications 1252 int nbModifs = in.readInt(); 1253 1254 for ( int i = 0; i < nbModifs; i++ ) 1255 { 1256 Modification modification = new DefaultModification(); 1257 modification.readExternal( in ); 1258 1259 addModification( modification ); 1260 } 1261 1262 break; 1263 } 1264 1265 int nbControls = in.readInt(); 1266 1267 // We have at least a control 1268 if ( nbControls > 0 ) 1269 { 1270 controls = new ConcurrentHashMap<String, LdifControl>( nbControls ); 1271 1272 for ( int i = 0; i < nbControls; i++ ) 1273 { 1274 LdifControl control = new LdifControl(); 1275 1276 control.readExternal( in ); 1277 1278 controls.put( control.getOid(), control ); 1279 } 1280 } 1281 } 1282 1283 1284 /** 1285 * @see Externalizable#readExternal(ObjectInput) 1286 * @param out The stream in which the ChangeLogEvent will be serialized. 1287 * @throws IOException If the serialization fail 1288 */ 1289 public void writeExternal( ObjectOutput out ) throws IOException 1290 { 1291 // Write the changeType 1292 out.writeInt( changeType.getChangeType() ); 1293 1294 // Write the data 1295 switch ( changeType ) 1296 { 1297 case Add: 1298 case None: 1299 entry.writeExternal( out ); 1300 break; 1301 1302 // Fallback 1303 case Delete: 1304 // we write the Dn 1305 entryDn.writeExternal( out ); 1306 break; 1307 1308 case ModDn: 1309 // Fallback 1310 case ModRdn: 1311 // Write the Dn 1312 entryDn.writeExternal( out ); 1313 1314 out.writeBoolean( deleteOldRdn ); 1315 1316 if ( newRdn == null ) 1317 { 1318 out.writeBoolean( false ); 1319 } 1320 else 1321 { 1322 out.writeBoolean( true ); 1323 out.writeUTF( newRdn ); 1324 } 1325 1326 if ( newSuperior != null ) 1327 { 1328 out.writeBoolean( true ); 1329 out.writeUTF( newSuperior ); 1330 } 1331 else 1332 { 1333 out.writeBoolean( false ); 1334 } 1335 break; 1336 1337 case Modify: 1338 // Write the Dn 1339 entryDn.writeExternal( out ); 1340 1341 // Write the modifications 1342 out.writeInt( modificationList.size() ); 1343 1344 for ( Modification modification : modificationList ) 1345 { 1346 modification.writeExternal( out ); 1347 } 1348 1349 break; 1350 } 1351 1352 // The controls 1353 if ( controls != null ) 1354 { 1355 // Write the control 1356 out.writeInt( controls.size() ); 1357 1358 for ( LdifControl control : controls.values() ) 1359 { 1360 control.writeExternal( out ); 1361 } 1362 } 1363 else 1364 { 1365 // No control, write -1 1366 out.writeInt( -1 ); 1367 } 1368 1369 // and flush the result 1370 out.flush(); 1371 } 1372}