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 package org.apache.directory.shared.ldap.entry.client; 020 021 022 import java.io.IOException; 023 import java.io.ObjectInput; 024 import java.io.ObjectOutput; 025 import java.util.ArrayList; 026 import java.util.Collections; 027 import java.util.HashMap; 028 import java.util.Iterator; 029 import java.util.List; 030 import java.util.Map; 031 import java.util.SortedMap; 032 import java.util.TreeMap; 033 034 import org.apache.directory.shared.ldap.exception.LdapException; 035 036 import org.apache.directory.shared.i18n.I18n; 037 import org.apache.directory.shared.ldap.entry.AbstractEntry; 038 import org.apache.directory.shared.ldap.entry.Entry; 039 import org.apache.directory.shared.ldap.entry.EntryAttribute; 040 import org.apache.directory.shared.ldap.entry.Value; 041 import org.apache.directory.shared.ldap.name.DN; 042 import org.apache.directory.shared.ldap.util.StringTools; 043 import org.slf4j.Logger; 044 import org.slf4j.LoggerFactory; 045 046 047 /** 048 * A default implementation of a ServerEntry which should suite most 049 * use cases. 050 * 051 * This class is final, it should not be extended. 052 * 053 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 054 * @version $Rev$, $Date$ 055 */ 056 public final class DefaultClientEntry extends AbstractEntry<String> //implements ClientEntry 057 { 058 /** Used for serialization */ 059 private static final long serialVersionUID = 2L; 060 061 /** The logger for this class */ 062 private static final Logger LOG = LoggerFactory.getLogger( DefaultClientEntry.class ); 063 064 //------------------------------------------------------------------------- 065 // Constructors 066 //------------------------------------------------------------------------- 067 /** 068 * Creates a new instance of DefaultClientEntry. 069 * <p> 070 * This entry <b>must</b> be initialized before being used ! 071 */ 072 public DefaultClientEntry() 073 { 074 dn = DN.EMPTY_DN; 075 } 076 077 078 /** 079 * Creates a new instance of DefaultServerEntry, with a 080 * DN. 081 * 082 * @param dn The DN for this serverEntry. Can be null. 083 */ 084 public DefaultClientEntry( DN dn ) 085 { 086 this.dn = dn; 087 } 088 089 090 /** 091 * Creates a new instance of DefaultServerEntry, with a 092 * DN and a list of IDs. 093 * 094 * @param dn The DN for this serverEntry. Can be null. 095 * @param upIds The list of attributes to create. 096 */ 097 public DefaultClientEntry( DN dn, String... upIds ) 098 { 099 this.dn = dn; 100 101 for ( String upId:upIds ) 102 { 103 // Add a new AttributeType without value 104 set( upId ); 105 } 106 } 107 108 109 /** 110 * <p> 111 * Creates a new instance of DefaultClientEntry, with a 112 * DN and a list of EntryAttributes. 113 * </p> 114 * 115 * @param dn The DN for this serverEntry. Can be null 116 * @param attributes The list of attributes to create 117 */ 118 public DefaultClientEntry( DN dn, EntryAttribute... attributes ) 119 { 120 this.dn = dn; 121 122 for ( EntryAttribute attribute:attributes ) 123 { 124 if ( attribute == null ) 125 { 126 continue; 127 } 128 129 // Store a new ClientAttribute 130 this.attributes.put( attribute.getId(), attribute ); 131 } 132 } 133 134 135 //------------------------------------------------------------------------- 136 // Helper methods 137 //------------------------------------------------------------------------- 138 private String getId( String upId ) throws IllegalArgumentException 139 { 140 String id = StringTools.trim( StringTools.toLowerCase( upId ) ); 141 142 // If empty, throw an error 143 if ( ( id == null ) || ( id.length() == 0 ) ) 144 { 145 String message = I18n.err( I18n.ERR_04133 ); 146 LOG.error( message ); 147 throw new IllegalArgumentException( message ); 148 } 149 150 return id; 151 } 152 153 154 //------------------------------------------------------------------------- 155 // Entry methods 156 //------------------------------------------------------------------------- 157 /** 158 * Add some Attributes to the current Entry. 159 * 160 * @param attributes The attributes to add 161 * @throws LdapException If we can't add any of the attributes 162 */ 163 public void add( EntryAttribute... attributes ) throws LdapException 164 { 165 // Loop on all the added attributes 166 for ( EntryAttribute attribute:attributes ) 167 { 168 // If the attribute already exist, we will add the new values. 169 if ( contains( attribute ) ) 170 { 171 EntryAttribute existingAttr = get( attribute.getId() ); 172 173 // Loop on all the values, and add them to the existing attribute 174 for ( Value<?> value:attribute ) 175 { 176 existingAttr.add( value ); 177 } 178 } 179 else 180 { 181 // Stores the attribute into the entry 182 this.attributes.put( attribute.getId(), attribute ); 183 } 184 } 185 } 186 187 188 /** 189 * Add an attribute (represented by its ID and binary values) into an entry. 190 * 191 * @param upId The attribute ID 192 * @param values The list of binary values to inject. It can be empty 193 * @throws LdapException If the attribute does not exist 194 */ 195 public void add( String upId, byte[]... values ) throws LdapException 196 { 197 // First, transform the upID to a valid ID 198 String id = getId( upId ); 199 200 // Now, check to see if we already have such an attribute 201 EntryAttribute attribute = attributes.get( id ); 202 203 if ( attribute != null ) 204 { 205 // This Attribute already exist, we add the values 206 // into it. (If the values already exists, they will 207 // not be added, but this is done in the add() method) 208 attribute.add( values ); 209 attribute.setUpId( upId ); 210 } 211 else 212 { 213 // We have to create a new Attribute and set the values 214 // and the upId 215 attributes.put( id, new DefaultClientAttribute( upId, values ) ); 216 } 217 } 218 219 220 /** 221 * Add some String values to the current Entry. 222 * 223 * @param upId The user provided ID of the attribute we want to add 224 * some values to 225 * @param values The list of String values to add 226 * @throws LdapException If we can't add any of the values 227 */ 228 public void add( String upId, String... values ) throws LdapException 229 { 230 // First, transform the upID to a valid ID 231 String id = getId( upId ); 232 233 // Now, check to see if we already have such an attribute 234 EntryAttribute attribute = attributes.get( id ); 235 236 if ( attribute != null ) 237 { 238 // This Attribute already exist, we add the values 239 // into it. (If the values already exists, they will 240 // not be added, but this is done in the add() method) 241 attribute.add( values ); 242 attribute.setUpId( upId ); 243 } 244 else 245 { 246 // We have to create a new Attribute and set the values 247 // and the upId 248 attributes.put( id, new DefaultClientAttribute( upId, values ) ); 249 } 250 } 251 252 253 /** 254 * Add an attribute (represented by its ID and Value values) into an entry. 255 * 256 * @param upId The attribute ID 257 * @param values The list of Value values to inject. It can be empty 258 * @throws LdapException If the attribute does not exist 259 */ 260 public void add( String upId, Value<?>... values ) throws LdapException 261 { 262 // First, transform the upID to a valid ID 263 String id = getId( upId ); 264 265 // Now, check to see if we already have such an attribute 266 EntryAttribute attribute = attributes.get( id ); 267 268 if ( attribute != null ) 269 { 270 // This Attribute already exist, we add the values 271 // into it. (If the values already exists, they will 272 // not be added, but this is done in the add() method) 273 attribute.add( values ); 274 attribute.setUpId( upId ); 275 } 276 else 277 { 278 // We have to create a new Attribute and set the values 279 // and the upId 280 attributes.put( id, new DefaultClientAttribute( upId, values ) ); 281 } 282 } 283 284 285 /** 286 * Clone an entry. All the element are duplicated, so a modification on 287 * the original object won't affect the cloned object, as a modification 288 * on the cloned object has no impact on the original object 289 */ 290 public Entry clone() 291 { 292 // First, clone the structure 293 DefaultClientEntry clone = (DefaultClientEntry)super.clone(); 294 295 // Just in case ... Should *never* happen 296 if ( clone == null ) 297 { 298 return null; 299 } 300 301 // An Entry has a DN and many attributes. 302 // First, clone the DN, if not null. 303 if ( dn != null ) 304 { 305 clone.setDn( (DN)dn.clone() ); 306 } 307 308 // then clone the ClientAttribute Map. 309 clone.attributes = (Map<String, EntryAttribute>)(((HashMap<String, EntryAttribute>)attributes).clone()); 310 311 // now clone all the attributes 312 clone.attributes.clear(); 313 314 for ( EntryAttribute attribute:attributes.values() ) 315 { 316 clone.attributes.put( attribute.getId(), attribute.clone() ); 317 } 318 319 // We are done ! 320 return clone; 321 } 322 323 324 /** 325 * <p> 326 * Checks if an entry contains a list of attributes. 327 * </p> 328 * <p> 329 * If the list is null or empty, this method will return <code>true</code> 330 * if the entry has no attribute, <code>false</code> otherwise. 331 * </p> 332 * 333 * @param attributes The Attributes to look for 334 * @return <code>true</code> if all the attributes are found within 335 * the entry, <code>false</code> if at least one of them is not present. 336 * @throws LdapException If the attribute does not exist 337 */ 338 public boolean contains( EntryAttribute... attributes ) throws LdapException 339 { 340 for ( EntryAttribute attribute:attributes ) 341 { 342 if ( attribute == null ) 343 { 344 return this.attributes.size() == 0; 345 } 346 347 if ( !this.attributes.containsKey( attribute.getId() ) ) 348 { 349 return false; 350 } 351 } 352 353 return true; 354 } 355 356 357 /** 358 * Checks if an entry contains a specific attribute 359 * 360 * @param attributes The Attributes to look for 361 * @return <code>true</code> if the attributes are found within the entry 362 * @throws LdapException If the attribute does not exist 363 */ 364 public boolean contains( String upId ) throws LdapException 365 { 366 String id = getId( upId ); 367 368 return attributes.containsKey( id ); 369 } 370 371 372 /** 373 * Checks if an entry contains an attribute with some binary values. 374 * 375 * @param id The Attribute we are looking for. 376 * @param values The searched values. 377 * @return <code>true</code> if all the values are found within the attribute, 378 * false if at least one value is not present or if the ID is not valid. 379 */ 380 public boolean contains( String upId, byte[]... values ) 381 { 382 String id = getId( upId ); 383 384 EntryAttribute attribute = attributes.get( id ); 385 386 if ( attribute == null ) 387 { 388 return false; 389 } 390 391 return attribute.contains( values ); 392 } 393 394 395 /** 396 * Checks if an entry contains an attribute with some String values. 397 * 398 * @param id The Attribute we are looking for. 399 * @param values The searched values. 400 * @return <code>true</code> if all the values are found within the attribute, 401 * false if at least one value is not present or if the ID is not valid. 402 */ 403 public boolean contains( String upId, String... values ) 404 { 405 String id = getId( upId ); 406 407 EntryAttribute attribute = attributes.get( id ); 408 409 if ( attribute == null ) 410 { 411 return false; 412 } 413 414 return attribute.contains( values ); 415 } 416 417 418 /** 419 * Checks if an entry contains an attribute with some values. 420 * 421 * @param id The Attribute we are looking for. 422 * @param values The searched values. 423 * @return <code>true</code> if all the values are found within the attribute, 424 * false if at least one value is not present or if the ID is not valid. 425 */ 426 public boolean contains( String upId, Value<?>... values ) 427 { 428 String id = getId( upId ); 429 430 EntryAttribute attribute = attributes.get( id ); 431 432 if ( attribute == null ) 433 { 434 return false; 435 } 436 437 return attribute.contains( values ); 438 } 439 440 441 /** 442 * Checks if an entry contains some specific attributes. 443 * 444 * @param attributes The Attributes to look for. 445 * @return <code>true</code> if the attributes are all found within the entry. 446 */ 447 public boolean containsAttribute( String... attributes ) 448 { 449 for ( String attribute:attributes ) 450 { 451 String id = getId( attribute ); 452 453 if ( !this.attributes.containsKey( id ) ) 454 { 455 return false; 456 } 457 } 458 459 return true; 460 } 461 462 463 /** 464 * <p> 465 * Returns the attribute with the specified alias. The return value 466 * is <code>null</code> if no match is found. 467 * </p> 468 * <p>An Attribute with an id different from the supplied alias may 469 * be returned: for example a call with 'cn' may in some implementations 470 * return an Attribute whose getId() field returns 'commonName'. 471 * </p> 472 * 473 * @param alias an aliased name of the attribute identifier 474 * @return the attribute associated with the alias 475 */ 476 public EntryAttribute get( String alias ) 477 { 478 try 479 { 480 String id = getId( alias ); 481 482 return attributes.get( id ); 483 } 484 catch( IllegalArgumentException iea ) 485 { 486 LOG.error( I18n.err( I18n.ERR_04134, alias ) ); 487 return null; 488 } 489 } 490 491 492 /** 493 * <p> 494 * Put an attribute (represented by its ID and some binary values) into an entry. 495 * </p> 496 * <p> 497 * If the attribute already exists, the previous attribute will be 498 * replaced and returned. 499 * </p> 500 * 501 * @param upId The attribute ID 502 * @param values The list of binary values to put. It can be empty. 503 * @return The replaced attribute 504 */ 505 public EntryAttribute put( String upId, byte[]... values ) 506 { 507 // Get the normalized form of the ID 508 String id = getId( upId ); 509 510 // Create a new attribute 511 EntryAttribute clientAttribute = new DefaultClientAttribute( upId, values ); 512 513 // Replace the previous one, and return it back 514 return attributes.put( id, clientAttribute ); 515 } 516 517 518 /** 519 * <p> 520 * Put an attribute (represented by its ID and some String values) into an entry. 521 * </p> 522 * <p> 523 * If the attribute already exists, the previous attribute will be 524 * replaced and returned. 525 * </p> 526 * 527 * @param upId The attribute ID 528 * @param values The list of String values to put. It can be empty. 529 * @return The replaced attribute 530 */ 531 public EntryAttribute put( String upId, String... values ) 532 { 533 // Get the normalized form of the ID 534 String id = getId( upId ); 535 536 // Create a new attribute 537 EntryAttribute clientAttribute = new DefaultClientAttribute( upId, values ); 538 539 // Replace the previous one, and return it back 540 return attributes.put( id, clientAttribute ); 541 } 542 543 544 /** 545 * <p> 546 * Put an attribute (represented by its ID and some values) into an entry. 547 * </p> 548 * <p> 549 * If the attribute already exists, the previous attribute will be 550 * replaced and returned. 551 * </p> 552 * 553 * @param upId The attribute ID 554 * @param values The list of values to put. It can be empty. 555 * @return The replaced attribute 556 */ 557 public EntryAttribute put( String upId, Value<?>... values ) 558 { 559 // Get the normalized form of the ID 560 String id = getId( upId ); 561 562 // Create a new attribute 563 EntryAttribute clientAttribute = new DefaultClientAttribute( upId, values ); 564 565 // Replace the previous one, and return it back 566 return attributes.put( id, clientAttribute ); 567 } 568 569 570 /** 571 * <p> 572 * Put some new ClientAttribute using the User Provided ID. 573 * No value is inserted. 574 * </p> 575 * <p> 576 * If an existing Attribute is found, it will be replaced by an 577 * empty attribute, and returned to the caller. 578 * </p> 579 * 580 * @param upIds The user provided IDs of the AttributeTypes to add. 581 * @return A list of replaced Attributes. 582 */ 583 public List<EntryAttribute> set( String... upIds ) 584 { 585 if ( upIds == null ) 586 { 587 String message = I18n.err( I18n.ERR_04135 ); 588 LOG.error( message ); 589 throw new IllegalArgumentException( message ); 590 } 591 592 List<EntryAttribute> returnedClientAttributes = new ArrayList<EntryAttribute>(); 593 594 // Now, loop on all the attributeType to add 595 for ( String upId:upIds ) 596 { 597 String id = StringTools.trim( StringTools.toLowerCase( upId ) ); 598 599 if ( id == null ) 600 { 601 String message = I18n.err( I18n.ERR_04136 ); 602 LOG.error( message ); 603 throw new IllegalArgumentException( message ); 604 } 605 606 if ( attributes.containsKey( id ) ) 607 { 608 // Add the removed serverAttribute to the list 609 returnedClientAttributes.add( attributes.remove( id ) ); 610 } 611 612 EntryAttribute newAttribute = new DefaultClientAttribute( upId ); 613 attributes.put( id, newAttribute ); 614 } 615 616 return returnedClientAttributes; 617 } 618 619 620 /** 621 * <p> 622 * Places attributes in the attribute collection. 623 * </p> 624 * <p>If there is already an attribute with the same ID as any of the 625 * new attributes, the old ones are removed from the collection and 626 * are returned by this method. If there was no attribute with the 627 * same ID the return value is <code>null</code>. 628 *</p> 629 * 630 * @param attributes the attributes to be put 631 * @return the old attributes with the same OID, if exist; otherwise 632 * <code>null</code> 633 * @exception LdapException if the operation fails 634 */ 635 public List<EntryAttribute> put( EntryAttribute... attributes ) throws LdapException 636 { 637 // First, get the existing attributes 638 List<EntryAttribute> previous = new ArrayList<EntryAttribute>(); 639 640 for ( EntryAttribute attribute:attributes ) 641 { 642 String id = attribute.getId(); 643 644 if ( contains( id ) ) 645 { 646 // Store the attribute and remove it from the list 647 previous.add( get( id ) ); 648 this.attributes.remove( id ); 649 } 650 651 // add the new one 652 this.attributes.put( id, (EntryAttribute)attribute ); 653 } 654 655 // return the previous attributes 656 return previous; 657 } 658 659 660 public List<EntryAttribute> remove( EntryAttribute... attributes ) throws LdapException 661 { 662 List<EntryAttribute> removedAttributes = new ArrayList<EntryAttribute>(); 663 664 for ( EntryAttribute attribute:attributes ) 665 { 666 if ( contains( attribute.getId() ) ) 667 { 668 this.attributes.remove( attribute.getId() ); 669 removedAttributes.add( attribute ); 670 } 671 } 672 673 return removedAttributes; 674 } 675 676 677 /** 678 * <p> 679 * Removes the attribute with the specified alias. 680 * </p> 681 * <p> 682 * The removed attribute are returned by this method. 683 * </p> 684 * <p> 685 * If there is no attribute with the specified alias, 686 * the return value is <code>null</code>. 687 * </p> 688 * 689 * @param attributes an aliased name of the attribute to be removed 690 * @return the removed attributes, if any, as a list; otherwise <code>null</code> 691 */ 692 public List<EntryAttribute> removeAttributes( String... attributes ) 693 { 694 if ( attributes.length == 0 ) 695 { 696 return null; 697 } 698 699 List<EntryAttribute> removed = new ArrayList<EntryAttribute>( attributes.length ); 700 701 for ( String attribute:attributes ) 702 { 703 EntryAttribute attr = get( attribute ); 704 705 if ( attr != null ) 706 { 707 removed.add( this.attributes.remove( attr.getId() ) ); 708 } 709 else 710 { 711 String message = I18n.err( I18n.ERR_04137, attribute ); 712 LOG.warn( message ); 713 continue; 714 } 715 } 716 717 if ( removed.size() == 0 ) 718 { 719 return null; 720 } 721 else 722 { 723 return removed; 724 } 725 } 726 727 728 /** 729 * <p> 730 * Removes the specified binary values from an attribute. 731 * </p> 732 * <p> 733 * If at least one value is removed, this method returns <code>true</code>. 734 * </p> 735 * <p> 736 * If there is no more value after having removed the values, the attribute 737 * will be removed too. 738 * </p> 739 * <p> 740 * If the attribute does not exist, nothing is done and the method returns 741 * <code>false</code> 742 * </p> 743 * 744 * @param upId The attribute ID 745 * @param values the values to be removed 746 * @return <code>true</code> if at least a value is removed, <code>false</code> 747 * if not all the values have been removed or if the attribute does not exist. 748 */ 749 public boolean remove( String upId, byte[]... values ) throws LdapException 750 { 751 try 752 { 753 String id = getId( upId ); 754 755 EntryAttribute attribute = get( id ); 756 757 if ( attribute == null ) 758 { 759 // Can't remove values from a not existing attribute ! 760 return false; 761 } 762 763 int nbOldValues = attribute.size(); 764 765 // Remove the values 766 attribute.remove( values ); 767 768 if ( attribute.size() == 0 ) 769 { 770 // No mare values, remove the attribute 771 attributes.remove( id ); 772 773 return true; 774 } 775 776 if ( nbOldValues != attribute.size() ) 777 { 778 // At least one value have been removed, return true. 779 return true; 780 } 781 else 782 { 783 // No values have been removed, return false. 784 return false; 785 } 786 } 787 catch ( IllegalArgumentException iae ) 788 { 789 LOG.error( I18n.err( I18n.ERR_04138, upId ) ); 790 return false; 791 } 792 } 793 794 795 /** 796 * <p> 797 * Removes the specified String values from an attribute. 798 * </p> 799 * <p> 800 * If at least one value is removed, this method returns <code>true</code>. 801 * </p> 802 * <p> 803 * If there is no more value after having removed the values, the attribute 804 * will be removed too. 805 * </p> 806 * <p> 807 * If the attribute does not exist, nothing is done and the method returns 808 * <code>false</code> 809 * </p> 810 * 811 * @param upId The attribute ID 812 * @param attributes the attributes to be removed 813 * @return <code>true</code> if at least a value is removed, <code>false</code> 814 * if not all the values have been removed or if the attribute does not exist. 815 */ 816 public boolean remove( String upId, String... values ) throws LdapException 817 { 818 try 819 { 820 String id = getId( upId ); 821 822 EntryAttribute attribute = get( id ); 823 824 if ( attribute == null ) 825 { 826 // Can't remove values from a not existing attribute ! 827 return false; 828 } 829 830 int nbOldValues = attribute.size(); 831 832 // Remove the values 833 attribute.remove( values ); 834 835 if ( attribute.size() == 0 ) 836 { 837 // No mare values, remove the attribute 838 attributes.remove( id ); 839 840 return true; 841 } 842 843 if ( nbOldValues != attribute.size() ) 844 { 845 // At least one value have been removed, return true. 846 return true; 847 } 848 else 849 { 850 // No values have been removed, return false. 851 return false; 852 } 853 } 854 catch ( IllegalArgumentException iae ) 855 { 856 LOG.error( I18n.err( I18n.ERR_04138, upId ) ); 857 return false; 858 } 859 } 860 861 862 /** 863 * <p> 864 * Removes the specified values from an attribute. 865 * </p> 866 * <p> 867 * If at least one value is removed, this method returns <code>true</code>. 868 * </p> 869 * <p> 870 * If there is no more value after having removed the values, the attribute 871 * will be removed too. 872 * </p> 873 * <p> 874 * If the attribute does not exist, nothing is done and the method returns 875 * <code>false</code> 876 * </p> 877 * 878 * @param upId The attribute ID 879 * @param attributes the attributes to be removed 880 * @return <code>true</code> if at least a value is removed, <code>false</code> 881 * if not all the values have been removed or if the attribute does not exist. 882 */ 883 public boolean remove( String upId, Value<?>... values ) throws LdapException 884 { 885 try 886 { 887 String id = getId( upId ); 888 889 EntryAttribute attribute = get( id ); 890 891 if ( attribute == null ) 892 { 893 // Can't remove values from a not existing attribute ! 894 return false; 895 } 896 897 int nbOldValues = attribute.size(); 898 899 // Remove the values 900 attribute.remove( values ); 901 902 if ( attribute.size() == 0 ) 903 { 904 // No mare values, remove the attribute 905 attributes.remove( id ); 906 907 return true; 908 } 909 910 if ( nbOldValues != attribute.size() ) 911 { 912 // At least one value have been removed, return true. 913 return true; 914 } 915 else 916 { 917 // No values have been removed, return false. 918 return false; 919 } 920 } 921 catch ( IllegalArgumentException iae ) 922 { 923 LOG.error( I18n.err( I18n.ERR_04138, upId ) ); 924 return false; 925 } 926 } 927 928 929 public Iterator<EntryAttribute> iterator() 930 { 931 return Collections.unmodifiableMap( attributes ).values().iterator(); 932 } 933 934 935 /** 936 * @see Externalizable#writeExternal(ObjectOutput)<p> 937 * 938 * This is the place where we serialize entries, and all theirs 939 * elements. 940 * <p> 941 * The structure used to store the entry is the following : 942 * <li> 943 * <b>[DN]</b> : If it's null, stores an empty DN 944 * </li> 945 * <li> 946 * <b>[attributes number]</b> : the number of attributes. 947 * </li> 948 * <li> 949 * <b>[attribute]*</b> : each attribute, if we have some 950 * </li> 951 */ 952 public void writeExternal( ObjectOutput out ) throws IOException 953 { 954 // First, the DN 955 if ( dn == null ) 956 { 957 // Write an empty DN 958 out.writeObject( DN.EMPTY_DN ); 959 } 960 else 961 { 962 // Write the DN 963 out.writeObject( dn ); 964 } 965 966 // Then the attributes. 967 // Store the attributes' nulber first 968 out.writeInt( attributes.size() ); 969 970 // Iterate through the keys. 971 for ( EntryAttribute attribute:attributes.values() ) 972 { 973 // Store the attribute 974 out.writeObject( attribute ); 975 } 976 977 out.flush(); 978 } 979 980 981 /** 982 * @see Externalizable#readExternal(ObjectInput) 983 */ 984 public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException 985 { 986 // Read the DN 987 dn = (DN)in.readObject(); 988 989 // Read the number of attributes 990 int nbAttributes = in.readInt(); 991 992 // Read the attributes 993 for ( int i = 0; i < nbAttributes; i++ ) 994 { 995 // Read each attribute 996 EntryAttribute attribute = (DefaultClientAttribute)in.readObject(); 997 998 attributes.put( attribute.getId(), attribute ); 999 } 1000 } 1001 1002 1003 /** 1004 * Get the hash code of this ClientEntry. 1005 * 1006 * @see java.lang.Object#hashCode() 1007 * @return the instance's hash code 1008 */ 1009 public int hashCode() 1010 { 1011 int result = 37; 1012 1013 result = result*17 + dn.hashCode(); 1014 1015 SortedMap<String, EntryAttribute> sortedMap = new TreeMap<String, EntryAttribute>(); 1016 1017 for ( String id:attributes.keySet() ) 1018 { 1019 sortedMap.put( id, attributes.get( id ) ); 1020 } 1021 1022 for ( String id:sortedMap.keySet() ) 1023 { 1024 result = result*17 + sortedMap.get( id ).hashCode(); 1025 } 1026 1027 return result; 1028 } 1029 1030 1031 /** 1032 * Tells if an entry has a specific ObjectClass value 1033 * 1034 * @param objectClass The ObjectClass we want to check 1035 * @return <code>true</code> if the ObjectClass value is present 1036 * in the ObjectClass attribute 1037 */ 1038 public boolean hasObjectClass( String objectClass ) 1039 { 1040 return contains( "objectclass", objectClass ); 1041 } 1042 1043 1044 /** 1045 * @see Object#equals(Object) 1046 */ 1047 public boolean equals( Object o ) 1048 { 1049 // Short circuit 1050 1051 if ( this == o ) 1052 { 1053 return true; 1054 } 1055 1056 if ( ! ( o instanceof DefaultClientEntry ) ) 1057 { 1058 return false; 1059 } 1060 1061 DefaultClientEntry other = (DefaultClientEntry)o; 1062 1063 // Both DN must be equal 1064 if ( dn == null ) 1065 { 1066 if ( other.getDn() != null ) 1067 { 1068 return false; 1069 } 1070 } 1071 else 1072 { 1073 if ( !dn.equals( other.getDn() ) ) 1074 { 1075 return false; 1076 } 1077 } 1078 1079 // They must have the same number of attributes 1080 if ( size() != other.size() ) 1081 { 1082 return false; 1083 } 1084 1085 // Each attribute must be equal 1086 for ( EntryAttribute attribute:other ) 1087 { 1088 if ( !attribute.equals( this.get( attribute.getId() ) ) ) 1089 { 1090 return false; 1091 } 1092 } 1093 1094 return true; 1095 } 1096 1097 1098 /** 1099 * @see Object#toString() 1100 */ 1101 public String toString() 1102 { 1103 StringBuilder sb = new StringBuilder(); 1104 1105 sb.append( "ClientEntry\n" ); 1106 sb.append( " dn: " ).append( dn.getName() ).append( '\n' ); 1107 1108 // First dump the ObjectClass attribute 1109 if ( containsAttribute( "objectClass" ) ) 1110 { 1111 EntryAttribute objectClass = get( "objectclass" ); 1112 1113 sb.append( objectClass ); 1114 } 1115 1116 if ( attributes.size() != 0 ) 1117 { 1118 for ( EntryAttribute attribute:attributes.values() ) 1119 { 1120 if ( !attribute.getId().equals( "objectclass" ) ) 1121 { 1122 sb.append( attribute ); 1123 } 1124 } 1125 } 1126 1127 return sb.toString(); 1128 } 1129 }