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