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 */ 019package org.apache.directory.api.ldap.model.entry; 020 021 022import java.io.IOException; 023import java.io.ObjectInput; 024import java.io.ObjectOutput; 025import java.util.ArrayList; 026import java.util.Collection; 027import java.util.Collections; 028import java.util.HashMap; 029import java.util.Iterator; 030import java.util.List; 031import java.util.Map; 032 033import org.apache.directory.api.i18n.I18n; 034import org.apache.directory.api.ldap.model.constants.SchemaConstants; 035import org.apache.directory.api.ldap.model.exception.LdapException; 036import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException; 037import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException; 038import org.apache.directory.api.ldap.model.ldif.LdapLdifException; 039import org.apache.directory.api.ldap.model.ldif.LdifAttributesReader; 040import org.apache.directory.api.ldap.model.message.ResultCodeEnum; 041import org.apache.directory.api.ldap.model.name.Dn; 042import org.apache.directory.api.ldap.model.schema.AttributeType; 043import org.apache.directory.api.ldap.model.schema.SchemaManager; 044import org.apache.directory.api.util.Base64; 045import org.apache.directory.api.util.Strings; 046import org.slf4j.Logger; 047import org.slf4j.LoggerFactory; 048 049 050/** 051 * A default implementation of a ServerEntry which should suite most 052 * use cases.<br> 053 * <br> 054 * This class is final, it should not be extended. 055 * 056 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 057 */ 058public final class DefaultEntry implements Entry 059{ 060 /** Used for serialization */ 061 private static final long serialVersionUID = 2L; 062 063 /** The logger for this class */ 064 private static final Logger LOG = LoggerFactory.getLogger( DefaultEntry.class ); 065 066 /** The Dn for this entry */ 067 private Dn dn; 068 069 /** A map containing all the attributes for this entry */ 070 private Map<String, Attribute> attributes = new HashMap<>(); 071 072 /** A speedup to get the ObjectClass attribute */ 073 private static AttributeType objectClassAttributeType; 074 075 /** The SchemaManager */ 076 private SchemaManager schemaManager; 077 078 /** The computed hashcode. We don't want to compute it each time the hashcode() method is called */ 079 private volatile int h; 080 081 /** A mutex to manage synchronization*/ 082 private static final Object MUTEX = new Object(); 083 084 085 //------------------------------------------------------------------------- 086 // Constructors 087 //------------------------------------------------------------------------- 088 /** 089 * Creates a new instance of DefaultEntry. 090 * <p> 091 * This entry <b>must</b> be initialized before being used ! 092 */ 093 public DefaultEntry() 094 { 095 this( ( SchemaManager ) null ); 096 } 097 098 099 /** 100 * <p> 101 * Creates a new instance of DefaultEntry, schema aware. 102 * </p> 103 * <p> 104 * No attributes will be created. 105 * </p> 106 * 107 * @param schemaManager The reference to the schemaManager 108 */ 109 public DefaultEntry( SchemaManager schemaManager ) 110 { 111 this.schemaManager = schemaManager; 112 dn = Dn.EMPTY_DN; 113 114 // Initialize the ObjectClass object 115 if ( schemaManager != null ) 116 { 117 initObjectClassAT(); 118 } 119 } 120 121 122 /** 123 * Creates a new instance of DefaultEntry, with a Dn. 124 * 125 * @param dn The String Dn for this serverEntry. Can be null. 126 * @throws LdapInvalidDnException If the Dn is invalid 127 */ 128 public DefaultEntry( String dn ) throws LdapInvalidDnException 129 { 130 this.dn = new Dn( dn ); 131 } 132 133 134 /** 135 * Creates a new instance of DefaultEntry, with a Dn. 136 * 137 * @param dn The Dn for this serverEntry. Can be null. 138 */ 139 public DefaultEntry( Dn dn ) 140 { 141 this.dn = dn; 142 } 143 144 145 /** 146 * <p> 147 * Creates a new instance of DefaultEntry, schema aware. 148 * </p> 149 * <p> 150 * No attributes will be created. 151 * </p> 152 * 153 * @param schemaManager The reference to the schemaManager 154 * @param dn The String Dn for this serverEntry. Can be null. 155 * @throws LdapInvalidDnException If the Dn is invalid 156 */ 157 public DefaultEntry( SchemaManager schemaManager, String dn ) throws LdapInvalidDnException 158 { 159 this.schemaManager = schemaManager; 160 161 if ( Strings.isEmpty( dn ) ) 162 { 163 this.dn = Dn.EMPTY_DN; 164 } 165 else 166 { 167 this.dn = new Dn( dn ); 168 normalizeDN( this.dn ); 169 } 170 171 // Initialize the ObjectClass object 172 initObjectClassAT(); 173 } 174 175 176 /** 177 * <p> 178 * Creates a new instance of DefaultEntry, schema aware. 179 * </p> 180 * <p> 181 * No attributes will be created. 182 * </p> 183 * 184 * @param schemaManager The reference to the schemaManager 185 * @param dn The Dn for this serverEntry. Can be null. 186 */ 187 public DefaultEntry( SchemaManager schemaManager, Dn dn ) 188 { 189 this.schemaManager = schemaManager; 190 191 if ( dn == null ) 192 { 193 this.dn = Dn.EMPTY_DN; 194 } 195 else 196 { 197 this.dn = dn; 198 normalizeDN( this.dn ); 199 } 200 201 // Initialize the ObjectClass object 202 initObjectClassAT(); 203 } 204 205 206 /** 207 * Creates a new instance of DefaultEntry, with a 208 * Dn and a list of IDs. 209 * 210 * @param dn The Dn for this serverEntry. Can be null. 211 * @param elements The list of attributes to create. 212 * @throws LdapException If we weren't able to create a new Entry instance 213 */ 214 public DefaultEntry( String dn, Object... elements ) throws LdapException 215 { 216 this( null, dn, elements ); 217 } 218 219 220 /** 221 * Creates a new instance of DefaultEntry, with a 222 * Dn and a list of IDs. 223 * 224 * @param dn The Dn for this serverEntry. Can be null. 225 * @param elements The list of attributes to create. 226 * @throws LdapException If we weren't able to create a new Entry instance 227 */ 228 public DefaultEntry( Dn dn, Object... elements ) throws LdapException 229 { 230 this( null, dn, elements ); 231 } 232 233 234 /** 235 * Creates a new instance of DefaultEntry, with a 236 * Dn and a list of IDs. 237 * 238 * @param schemaManager The reference to the schemaManager 239 * @param dn The Dn for this serverEntry. Can be null. 240 * @param elements The list of attributes to create. 241 * @throws LdapException If we weren't able to create a new Entry instance 242 */ 243 public DefaultEntry( SchemaManager schemaManager, String dn, Object... elements ) throws LdapException 244 { 245 this( schemaManager, new Dn( schemaManager, dn ), elements ); 246 } 247 248 249 /** 250 * Creates a new instance of DefaultEntry, with a 251 * Dn and a list of IDs. 252 * 253 * @param schemaManager The reference to the schemaManager 254 * @param dn The Dn for this serverEntry. Can be null. 255 * @param elements The list of attributes to create. 256 * @throws LdapException If we weren't able to create a new Entry instance 257 */ 258 public DefaultEntry( SchemaManager schemaManager, Dn dn, Object... elements ) throws LdapException 259 { 260 DefaultEntry entry = ( DefaultEntry ) createEntry( schemaManager, elements ); 261 262 this.dn = dn; 263 this.attributes = entry.attributes; 264 this.schemaManager = schemaManager; 265 266 if ( schemaManager != null ) 267 { 268 this.dn.apply( schemaManager ); 269 initObjectClassAT(); 270 } 271 } 272 273 274 /** 275 * <p> 276 * Creates a new instance of DefaultEntry, copying 277 * another entry. 278 * </p> 279 * <p> 280 * No attributes will be created. 281 * </p> 282 * 283 * @param schemaManager The reference to the schemaManager 284 * @param entry the entry to copy 285 * @throws LdapException If we weren't able to create a new Entry instance 286 */ 287 public DefaultEntry( SchemaManager schemaManager, Entry entry ) throws LdapException 288 { 289 this.schemaManager = schemaManager; 290 291 // Initialize the ObjectClass object 292 initObjectClassAT(); 293 294 // We will clone the existing entry, because it may be normalized 295 if ( entry.getDn() != null ) 296 { 297 dn = entry.getDn(); 298 normalizeDN( dn ); 299 } 300 else 301 { 302 dn = Dn.EMPTY_DN; 303 } 304 305 // Init the attributes map 306 attributes = new HashMap<>( entry.size() ); 307 308 // and copy all the attributes 309 for ( Attribute attribute : entry ) 310 { 311 try 312 { 313 // First get the AttributeType 314 AttributeType attributeType = attribute.getAttributeType(); 315 316 if ( attributeType == null ) 317 { 318 attributeType = schemaManager.lookupAttributeTypeRegistry( attribute.getId() ); 319 } 320 321 // Create a new ServerAttribute. 322 Attribute serverAttribute = new DefaultAttribute( attributeType, attribute ); 323 324 // And store it 325 add( serverAttribute ); 326 } 327 catch ( LdapException ne ) 328 { 329 // Just log a warning 330 LOG.warn( "The attribute '" + attribute.getId() + "' cannot be stored" ); 331 throw ne; 332 } 333 } 334 } 335 336 337 //------------------------------------------------------------------------- 338 // Helper methods 339 //------------------------------------------------------------------------- 340 private Entry createEntry( SchemaManager schemaManager, Object... elements ) 341 throws LdapInvalidAttributeValueException, LdapLdifException 342 { 343 StringBuilder sb = new StringBuilder(); 344 int pos = 0; 345 boolean valueExpected = false; 346 347 for ( Object element : elements ) 348 { 349 if ( !valueExpected ) 350 { 351 if ( !( element instanceof String ) ) 352 { 353 throw new LdapInvalidAttributeValueException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, I18n.err( 354 I18n.ERR_12085, pos + 1 ) ); 355 } 356 357 String attribute = ( String ) element; 358 sb.append( attribute ); 359 360 if ( attribute.indexOf( ':' ) != -1 ) 361 { 362 sb.append( '\n' ); 363 } 364 else 365 { 366 valueExpected = true; 367 } 368 } 369 else 370 { 371 if ( element instanceof String ) 372 { 373 sb.append( ": " ).append( ( String ) element ).append( '\n' ); 374 } 375 else if ( element instanceof byte[] ) 376 { 377 sb.append( ":: " ); 378 sb.append( new String( Base64.encode( ( byte[] ) element ) ) ); 379 sb.append( '\n' ); 380 } 381 else 382 { 383 throw new LdapInvalidAttributeValueException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, I18n.err( 384 I18n.ERR_12086, pos + 1 ) ); 385 } 386 387 valueExpected = false; 388 } 389 } 390 391 if ( valueExpected ) 392 { 393 throw new LdapInvalidAttributeValueException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, I18n 394 .err( I18n.ERR_12087 ) ); 395 } 396 397 try ( LdifAttributesReader reader = new LdifAttributesReader() ) 398 { 399 return reader.parseEntry( schemaManager, sb.toString() ); 400 } 401 catch ( IOException e ) 402 { 403 throw new LdapLdifException( "Cannot read an entry" ); 404 } 405 } 406 407 408 /** 409 * Get the trimmed and lower cased entry ID 410 */ 411 private String getId( String upId ) 412 { 413 String id = Strings.trim( Strings.toLowerCaseAscii( upId ) ); 414 415 // If empty, throw an error 416 if ( Strings.isEmpty( id ) ) 417 { 418 String message = I18n.err( I18n.ERR_04133 ); 419 LOG.error( message ); 420 throw new IllegalArgumentException( message ); 421 } 422 423 return id; 424 } 425 426 427 /** 428 * Get the UpId if it is null. 429 * 430 * @param upId The ID 431 */ 432 private String getUpId( String upId, AttributeType attributeType ) 433 { 434 String normUpId = Strings.trim( upId ); 435 436 if ( attributeType == null ) 437 { 438 if ( Strings.isEmpty( normUpId ) ) 439 { 440 String message = I18n.err( I18n.ERR_04458 ); 441 LOG.error( message ); 442 throw new IllegalArgumentException( message ); 443 } 444 445 return upId; 446 } 447 else if ( Strings.isEmpty( normUpId ) ) 448 { 449 String id = attributeType.getName(); 450 451 if ( Strings.isEmpty( id ) ) 452 { 453 id = attributeType.getOid(); 454 } 455 456 return id; 457 } 458 else 459 { 460 return upId; 461 } 462 } 463 464 465 /** 466 * This method is used to initialize the OBJECT_CLASS_AT attributeType. 467 * 468 * We want to do it only once, so it's a synchronized method. Note that 469 * the alternative would be to call the lookup() every time, but this won't 470 * be very efficient, as it will get the AT from a map, which is also 471 * synchronized, so here, we have a very minimal cost. 472 * 473 * We can't do it once as a static part in the body of this class, because 474 * the access to the registries is mandatory to get back the AttributeType. 475 */ 476 private void initObjectClassAT() 477 { 478 if ( schemaManager == null ) 479 { 480 return; 481 } 482 483 try 484 { 485 synchronized ( MUTEX ) 486 { 487 if ( objectClassAttributeType == null ) 488 { 489 objectClassAttributeType = schemaManager 490 .lookupAttributeTypeRegistry( SchemaConstants.OBJECT_CLASS_AT ); 491 } 492 } 493 } 494 catch ( LdapException ne ) 495 { 496 // do nothing... 497 } 498 } 499 500 501 /** 502 * normalizes the given Dn if it was not already normalized 503 * 504 * @param dn the Dn to be normalized 505 */ 506 private void normalizeDN( Dn dn ) 507 { 508 if ( !dn.isSchemaAware() ) 509 { 510 try 511 { 512 // The dn must be normalized 513 dn.apply( schemaManager ); 514 } 515 catch ( LdapException ne ) 516 { 517 LOG.warn( "The Dn '{}' cannot be normalized", dn ); 518 } 519 } 520 } 521 522 523 /** 524 * A helper method to recompute the hash code 525 */ 526 private void rehash() 527 { 528 h = 37; 529 h = h * 17 + dn.hashCode(); 530 } 531 532 533 /** 534 * Add a new EntryAttribute, with its upId. If the upId is null, 535 * default to the AttributeType name. 536 * 537 * Updates the AttributeMap. 538 * @param upId The user provided ID 539 * @param attributeType The AttributeType to use 540 * @param values The values to inject 541 * @throws LdapInvalidAttributeValueException If the creation failed because the AttributeType 542 * is not existing, or the values are invalid 543 */ 544 protected void createAttribute( String upId, AttributeType attributeType, byte[]... values ) 545 throws LdapInvalidAttributeValueException 546 { 547 Attribute attribute = new DefaultAttribute( attributeType, values ); 548 attribute.setUpId( upId, attributeType ); 549 attributes.put( attributeType.getOid(), attribute ); 550 } 551 552 553 /** 554 * Add a new EntryAttribute, with its upId. If the upId is null, 555 * default to the AttributeType name. 556 * 557 * Updates the AttributeMap. 558 * @param upId The user provided ID 559 * @param attributeType The AttributeType to use 560 * @param values The values to inject 561 * @throws LdapInvalidAttributeValueException If the creation failed because the AttributeType 562 * is not existing, or the values are invalid 563 */ 564 protected void createAttribute( String upId, AttributeType attributeType, String... values ) 565 throws LdapInvalidAttributeValueException 566 { 567 Attribute attribute = new DefaultAttribute( attributeType, values ); 568 attribute.setUpId( upId, attributeType ); 569 attributes.put( attributeType.getOid(), attribute ); 570 } 571 572 573 /** 574 * Add a new EntryAttribute, with its upId. If the upId is null, 575 * default to the AttributeType name. 576 * 577 * Updates the AttributeMap. 578 * @param upId The user provided ID 579 * @param attributeType The AttributeType to use 580 * @param values The values to inject 581 * @throws LdapInvalidAttributeValueException If the creation failed because the AttributeType 582 * is not existing, or the values are invalid 583 */ 584 protected void createAttribute( String upId, AttributeType attributeType, Value<?>... values ) 585 throws LdapInvalidAttributeValueException 586 { 587 Attribute attribute = new DefaultAttribute( attributeType, values ); 588 attribute.setUpId( upId, attributeType ); 589 attributes.put( attributeType.getOid(), attribute ); 590 } 591 592 593 /** 594 * Returns the attributeType from an Attribute ID. 595 * 596 * @param upId The user provided ID 597 * @return The entry's AttributeType for this ID 598 * @throws LdapException If the ID is not found in the entry 599 */ 600 protected AttributeType getAttributeType( String upId ) throws LdapException 601 { 602 if ( Strings.isEmpty( Strings.trim( upId ) ) ) 603 { 604 String message = I18n.err( I18n.ERR_04457_NULL_ATTRIBUTE_ID ); 605 LOG.error( message ); 606 throw new IllegalArgumentException( message ); 607 } 608 609 return schemaManager.lookupAttributeTypeRegistry( upId ); 610 } 611 612 613 //------------------------------------------------------------------------- 614 // Entry methods 615 //------------------------------------------------------------------------- 616 /** 617 * {@inheritDoc} 618 */ 619 public Entry add( AttributeType attributeType, byte[]... values ) throws LdapException 620 { 621 if ( attributeType == null ) 622 { 623 String message = I18n.err( I18n.ERR_04460_ATTRIBUTE_TYPE_NULL_NOT_ALLOWED ); 624 LOG.error( message ); 625 throw new IllegalArgumentException( message ); 626 } 627 628 if ( ( values == null ) || ( values.length == 0 ) ) 629 { 630 String message = I18n.err( I18n.ERR_04478_NO_VALUE_NOT_ALLOWED ); 631 LOG.error( message ); 632 throw new IllegalArgumentException( message ); 633 } 634 635 // ObjectClass with binary values are not allowed 636 if ( attributeType.equals( objectClassAttributeType ) ) 637 { 638 String message = I18n.err( I18n.ERR_04461 ); 639 LOG.error( message ); 640 throw new UnsupportedOperationException( message ); 641 } 642 643 Attribute attribute = attributes.get( attributeType.getOid() ); 644 645 if ( attribute != null ) 646 { 647 // This Attribute already exist, we add the values 648 // into it 649 attribute.add( values ); 650 } 651 else 652 { 653 // We have to create a new Attribute and set the values. 654 // The upId, which is set to null, will be setup by the 655 // createAttribute method 656 createAttribute( null, attributeType, values ); 657 } 658 659 return this; 660 } 661 662 663 /** 664 * {@inheritDoc} 665 */ 666 @Override 667 public Entry add( AttributeType attributeType, String... values ) throws LdapException 668 { 669 if ( attributeType == null ) 670 { 671 String message = I18n.err( I18n.ERR_04460_ATTRIBUTE_TYPE_NULL_NOT_ALLOWED ); 672 LOG.error( message ); 673 throw new IllegalArgumentException( message ); 674 } 675 676 Attribute attribute = attributes.get( attributeType.getOid() ); 677 678 if ( attribute != null ) 679 { 680 // This Attribute already exist, we add the values 681 // into it 682 attribute.add( values ); 683 } 684 else 685 { 686 // We have to create a new Attribute and set the values. 687 // The upId, which is set to null, will be setup by the 688 // createAttribute method 689 createAttribute( null, attributeType, values ); 690 } 691 692 return this; 693 } 694 695 696 /** 697 * {@inheritDoc} 698 */ 699 @Override 700 public Entry add( AttributeType attributeType, Value<?>... values ) throws LdapException 701 { 702 if ( attributeType == null ) 703 { 704 String message = I18n.err( I18n.ERR_04460_ATTRIBUTE_TYPE_NULL_NOT_ALLOWED ); 705 LOG.error( message ); 706 throw new IllegalArgumentException( message ); 707 } 708 709 Attribute attribute = attributes.get( attributeType.getOid() ); 710 711 if ( attribute != null ) 712 { 713 // This Attribute already exist, we add the values 714 // into it 715 attribute.add( values ); 716 } 717 else 718 { 719 // We have to create a new Attribute and set the values. 720 // The upId, which is set to null, will be setup by the 721 // createAttribute method 722 createAttribute( null, attributeType, values ); 723 } 724 725 return this; 726 } 727 728 729 /** 730 * {@inheritDoc} 731 */ 732 public Entry add( String upId, AttributeType attributeType, byte[]... values ) throws LdapException 733 { 734 // ObjectClass with binary values are not allowed 735 if ( attributeType.equals( objectClassAttributeType ) ) 736 { 737 String message = I18n.err( I18n.ERR_04461 ); 738 LOG.error( message ); 739 throw new UnsupportedOperationException( message ); 740 } 741 742 Attribute attribute = attributes.get( attributeType.getOid() ); 743 744 String id = getUpId( upId, attributeType ); 745 746 if ( attribute != null ) 747 { 748 // This Attribute already exist, we add the values 749 // into it 750 attribute.add( values ); 751 attribute.setUpId( id, attributeType ); 752 } 753 else 754 { 755 // We have to create a new Attribute and set the values 756 // and the upId 757 createAttribute( id, attributeType, values ); 758 } 759 760 return this; 761 } 762 763 764 /** 765 * {@inheritDoc} 766 */ 767 @Override 768 public Entry add( String upId, AttributeType attributeType, Value<?>... values ) throws LdapException 769 { 770 if ( attributeType == null ) 771 { 772 String message = I18n.err( I18n.ERR_04460_ATTRIBUTE_TYPE_NULL_NOT_ALLOWED ); 773 LOG.error( message ); 774 throw new IllegalArgumentException( message ); 775 } 776 777 String id = getUpId( upId, attributeType ); 778 779 Attribute attribute = attributes.get( attributeType.getOid() ); 780 781 if ( attribute != null ) 782 { 783 // This Attribute already exist, we add the values 784 // into it 785 attribute.add( values ); 786 attribute.setUpId( id, attributeType ); 787 } 788 else 789 { 790 createAttribute( id, attributeType, values ); 791 } 792 793 return this; 794 } 795 796 797 /** 798 * {@inheritDoc} 799 */ 800 @Override 801 public Entry add( String upId, AttributeType attributeType, String... values ) throws LdapException 802 { 803 if ( attributeType == null ) 804 { 805 String message = I18n.err( I18n.ERR_04460_ATTRIBUTE_TYPE_NULL_NOT_ALLOWED ); 806 LOG.error( message ); 807 throw new IllegalArgumentException( message ); 808 } 809 810 String id = getUpId( upId, attributeType ); 811 812 Attribute attribute = attributes.get( attributeType.getOid() ); 813 814 if ( attribute != null ) 815 { 816 // This Attribute already exist, we add the values 817 // into it 818 attribute.add( values ); 819 attribute.setUpId( id, attributeType ); 820 } 821 else 822 { 823 // We have to create a new Attribute and set the values 824 // and the upId 825 createAttribute( id, attributeType, values ); 826 } 827 828 return this; 829 } 830 831 832 /** 833 * {@inheritDoc} 834 */ 835 @Override 836 public Entry add( Attribute... attributes ) throws LdapException 837 { 838 // Loop on all the added attributes 839 for ( Attribute attribute : attributes ) 840 { 841 AttributeType attributeType = attribute.getAttributeType(); 842 843 if ( attributeType != null ) 844 { 845 String oid = attributeType.getOid(); 846 847 if ( this.attributes.containsKey( oid ) ) 848 { 849 // We already have an attribute with the same AttributeType 850 // Just add the new values into it. 851 Attribute existingAttribute = this.attributes.get( oid ); 852 853 for ( Value<?> value : attribute ) 854 { 855 existingAttribute.add( value ); 856 } 857 858 // And update the upId 859 existingAttribute.setUpId( attribute.getUpId() ); 860 } 861 else 862 { 863 // The attributeType does not exist, add it 864 this.attributes.put( oid, attribute ); 865 } 866 } 867 else 868 { 869 // If the attribute already exist, we will add the new values. 870 if ( contains( attribute ) ) 871 { 872 Attribute existingAttribute = get( attribute.getId() ); 873 874 // Loop on all the values, and add them to the existing attribute 875 for ( Value<?> value : attribute ) 876 { 877 existingAttribute.add( value ); 878 } 879 } 880 else 881 { 882 // Stores the attribute into the entry 883 this.attributes.put( attribute.getId(), attribute ); 884 } 885 } 886 } 887 888 return this; 889 } 890 891 892 /** 893 * {@inheritDoc} 894 */ 895 public Entry add( String upId, byte[]... values ) throws LdapException 896 { 897 if ( Strings.isEmpty( upId ) ) 898 { 899 String message = I18n.err( I18n.ERR_04457_NULL_ATTRIBUTE_ID ); 900 LOG.error( message ); 901 throw new IllegalArgumentException( message ); 902 } 903 904 // First, transform the upID to a valid ID 905 String id = getId( upId ); 906 907 if ( schemaManager != null ) 908 { 909 add( upId, schemaManager.lookupAttributeTypeRegistry( id ), values ); 910 } 911 else 912 { 913 // Now, check to see if we already have such an attribute 914 Attribute attribute = attributes.get( id ); 915 916 if ( attribute != null ) 917 { 918 // This Attribute already exist, we add the values 919 // into it. (If the values already exists, they will 920 // not be added, but this is done in the add() method) 921 attribute.add( values ); 922 attribute.setUpId( upId ); 923 } 924 else 925 { 926 // We have to create a new Attribute and set the values 927 // and the upId 928 attributes.put( id, new DefaultAttribute( upId, values ) ); 929 } 930 } 931 932 return this; 933 } 934 935 936 /** 937 * {@inheritDoc} 938 */ 939 @Override 940 public Entry add( String upId, String... values ) throws LdapException 941 { 942 if ( Strings.isEmpty( upId ) ) 943 { 944 String message = I18n.err( I18n.ERR_04457_NULL_ATTRIBUTE_ID ); 945 LOG.error( message ); 946 throw new IllegalArgumentException( message ); 947 } 948 949 // First, transform the upID to a valid ID 950 String id = getId( upId ); 951 952 if ( schemaManager != null ) 953 { 954 add( upId, schemaManager.lookupAttributeTypeRegistry( upId ), values ); 955 } 956 else 957 { 958 // Now, check to see if we already have such an attribute 959 Attribute attribute = attributes.get( id ); 960 961 if ( attribute != null ) 962 { 963 // This Attribute already exist, we add the values 964 // into it. (If the values already exists, they will 965 // not be added, but this is done in the add() method) 966 attribute.add( values ); 967 attribute.setUpId( upId ); 968 } 969 else 970 { 971 // We have to create a new Attribute and set the values 972 // and the upId 973 attributes.put( id, new DefaultAttribute( upId, values ) ); 974 } 975 } 976 977 return this; 978 } 979 980 981 /** 982 * {@inheritDoc} 983 */ 984 @Override 985 public Entry add( String upId, Value<?>... values ) throws LdapException 986 { 987 if ( Strings.isEmpty( upId ) ) 988 { 989 String message = I18n.err( I18n.ERR_04457_NULL_ATTRIBUTE_ID ); 990 LOG.error( message ); 991 throw new IllegalArgumentException( message ); 992 } 993 994 // First, transform the upID to a valid ID 995 String id = getId( upId ); 996 997 if ( schemaManager != null ) 998 { 999 add( upId, schemaManager.lookupAttributeTypeRegistry( upId ), values ); 1000 } 1001 else 1002 { 1003 // Now, check to see if we already have such an attribute 1004 Attribute attribute = attributes.get( id ); 1005 1006 if ( attribute != null ) 1007 { 1008 // This Attribute already exist, we add the values 1009 // into it. (If the values already exists, they will 1010 // not be added, but this is done in the add() method) 1011 attribute.add( values ); 1012 attribute.setUpId( upId ); 1013 } 1014 else 1015 { 1016 // We have to create a new Attribute and set the values 1017 // and the upId 1018 attributes.put( id, new DefaultAttribute( upId, values ) ); 1019 } 1020 } 1021 1022 return this; 1023 } 1024 1025 1026 /** 1027 * Clone an entry. All the element are duplicated, so a modification on 1028 * the original object won't affect the cloned object, as a modification 1029 * on the cloned object has no impact on the original object 1030 */ 1031 @Override 1032 public Entry clone() 1033 { 1034 // First, clone the structure 1035 DefaultEntry clone = ( DefaultEntry ) shallowClone(); 1036 1037 // now clone all the attributes 1038 clone.attributes.clear(); 1039 1040 if ( schemaManager != null ) 1041 { 1042 for ( Attribute attribute : attributes.values() ) 1043 { 1044 String oid = attribute.getAttributeType().getOid(); 1045 clone.attributes.put( oid, attribute.clone() ); 1046 } 1047 } 1048 else 1049 { 1050 for ( Attribute attribute : attributes.values() ) 1051 { 1052 clone.attributes.put( attribute.getId(), attribute.clone() ); 1053 } 1054 1055 } 1056 1057 // We are done ! 1058 return clone; 1059 } 1060 1061 1062 /** 1063 * Shallow clone an entry. We don't clone the Attributes 1064 */ 1065 @SuppressWarnings("unchecked") 1066 @Override 1067 public Entry shallowClone() 1068 { 1069 try 1070 { 1071 // First, clone the structure 1072 DefaultEntry clone = ( DefaultEntry ) super.clone(); 1073 1074 // An Entry has a Dn and many attributes. 1075 // note that Dn is immutable now 1076 clone.dn = dn; 1077 1078 // then clone the ClientAttribute Map. 1079 clone.attributes = ( Map<String, Attribute> ) ( ( ( HashMap<String, Attribute> ) attributes ) 1080 .clone() ); 1081 1082 // We are done ! 1083 return clone; 1084 } 1085 catch ( CloneNotSupportedException cnse ) 1086 { 1087 return null; 1088 } 1089 } 1090 1091 1092 /** 1093 * {@inheritDoc} 1094 */ 1095 @Override 1096 public boolean contains( Attribute... attributes ) 1097 { 1098 if ( schemaManager == null ) 1099 { 1100 for ( Attribute attribute : attributes ) 1101 { 1102 if ( attribute == null ) 1103 { 1104 return this.attributes.size() == 0; 1105 } 1106 1107 if ( !this.attributes.containsKey( attribute.getId() ) ) 1108 { 1109 return false; 1110 } 1111 } 1112 } 1113 else 1114 { 1115 for ( Attribute entryAttribute : attributes ) 1116 { 1117 if ( entryAttribute == null ) 1118 { 1119 return this.attributes.size() == 0; 1120 } 1121 1122 AttributeType attributeType = entryAttribute.getAttributeType(); 1123 1124 if ( ( attributeType == null ) || !this.attributes.containsKey( attributeType.getOid() ) ) 1125 { 1126 return false; 1127 } 1128 } 1129 } 1130 1131 return true; 1132 } 1133 1134 1135 /** 1136 * {@inheritDoc} 1137 */ 1138 @Override 1139 public boolean containsAttribute( String... attributes ) 1140 { 1141 if ( schemaManager == null ) 1142 { 1143 for ( String attribute : attributes ) 1144 { 1145 String id = getId( attribute ); 1146 1147 if ( !this.attributes.containsKey( id ) ) 1148 { 1149 return false; 1150 } 1151 } 1152 1153 return true; 1154 } 1155 else 1156 { 1157 for ( String attribute : attributes ) 1158 { 1159 try 1160 { 1161 if ( !containsAttribute( schemaManager.lookupAttributeTypeRegistry( attribute ) ) ) 1162 { 1163 return false; 1164 } 1165 } 1166 catch ( LdapException ne ) 1167 { 1168 return false; 1169 } 1170 } 1171 1172 return true; 1173 } 1174 } 1175 1176 1177 /** 1178 * {@inheritDoc} 1179 */ 1180 @Override 1181 public boolean containsAttribute( AttributeType attributeType ) 1182 { 1183 if ( attributeType == null ) 1184 { 1185 return false; 1186 } 1187 1188 return attributes.containsKey( attributeType.getOid() ); 1189 } 1190 1191 1192 /** 1193 * {@inheritDoc} 1194 */ 1195 public boolean contains( AttributeType attributeType, byte[]... values ) 1196 { 1197 if ( attributeType == null ) 1198 { 1199 return false; 1200 } 1201 1202 Attribute attribute = attributes.get( attributeType.getOid() ); 1203 1204 if ( attribute != null ) 1205 { 1206 return attribute.contains( values ); 1207 } 1208 else 1209 { 1210 return false; 1211 } 1212 } 1213 1214 1215 /** 1216 * {@inheritDoc} 1217 */ 1218 @Override 1219 public boolean contains( AttributeType attributeType, String... values ) 1220 { 1221 if ( attributeType == null ) 1222 { 1223 return false; 1224 } 1225 1226 Attribute attribute = attributes.get( attributeType.getOid() ); 1227 1228 if ( attribute != null ) 1229 { 1230 return attribute.contains( values ); 1231 } 1232 else 1233 { 1234 return false; 1235 } 1236 } 1237 1238 1239 /** 1240 * {@inheritDoc} 1241 */ 1242 @Override 1243 public boolean contains( AttributeType attributeType, Value<?>... values ) 1244 { 1245 if ( attributeType == null ) 1246 { 1247 return false; 1248 } 1249 1250 Attribute attribute = attributes.get( attributeType.getOid() ); 1251 1252 if ( attribute != null ) 1253 { 1254 return attribute.contains( values ); 1255 } 1256 else 1257 { 1258 return false; 1259 } 1260 } 1261 1262 1263 /** 1264 * {@inheritDoc} 1265 */ 1266 public boolean contains( String upId, byte[]... values ) 1267 { 1268 if ( Strings.isEmpty( upId ) ) 1269 { 1270 return false; 1271 } 1272 1273 String id = getId( upId ); 1274 1275 if ( schemaManager != null ) 1276 { 1277 try 1278 { 1279 return contains( schemaManager.lookupAttributeTypeRegistry( id ), values ); 1280 } 1281 catch ( LdapException le ) 1282 { 1283 return false; 1284 } 1285 } 1286 1287 Attribute attribute = attributes.get( id ); 1288 1289 if ( attribute == null ) 1290 { 1291 return false; 1292 } 1293 1294 return attribute.contains( values ); 1295 } 1296 1297 1298 /** 1299 * {@inheritDoc} 1300 */ 1301 @Override 1302 public boolean contains( String upId, String... values ) 1303 { 1304 if ( Strings.isEmpty( upId ) ) 1305 { 1306 return false; 1307 } 1308 1309 String id = getId( upId ); 1310 1311 if ( schemaManager != null ) 1312 { 1313 try 1314 { 1315 return contains( schemaManager.lookupAttributeTypeRegistry( id ), values ); 1316 } 1317 catch ( LdapException le ) 1318 { 1319 return false; 1320 } 1321 } 1322 1323 Attribute attribute = attributes.get( id ); 1324 1325 if ( attribute == null ) 1326 { 1327 return false; 1328 } 1329 1330 return attribute.contains( values ); 1331 } 1332 1333 1334 /** 1335 * {@inheritDoc} 1336 */ 1337 @Override 1338 public boolean contains( String upId, Value<?>... values ) 1339 { 1340 if ( Strings.isEmpty( upId ) ) 1341 { 1342 return false; 1343 } 1344 1345 String id = getId( upId ); 1346 1347 if ( schemaManager != null ) 1348 { 1349 try 1350 { 1351 return contains( schemaManager.lookupAttributeTypeRegistry( id ), values ); 1352 } 1353 catch ( LdapException le ) 1354 { 1355 return false; 1356 } 1357 } 1358 1359 Attribute attribute = attributes.get( id ); 1360 1361 if ( attribute == null ) 1362 { 1363 return false; 1364 } 1365 1366 return attribute.contains( values ); 1367 } 1368 1369 1370 /** 1371 * {@inheritDoc} 1372 */ 1373 @Override 1374 public Attribute get( String alias ) 1375 { 1376 try 1377 { 1378 String id = getId( alias ); 1379 1380 if ( schemaManager != null ) 1381 { 1382 try 1383 { 1384 AttributeType attributeType = schemaManager.lookupAttributeTypeRegistry( id ); 1385 1386 return attributes.get( attributeType.getOid() ); 1387 } 1388 catch ( LdapException ne ) 1389 { 1390 String message = ne.getLocalizedMessage(); 1391 LOG.error( message ); 1392 return null; 1393 } 1394 } 1395 else 1396 { 1397 return attributes.get( id ); 1398 } 1399 } 1400 catch ( IllegalArgumentException iea ) 1401 { 1402 LOG.error( I18n.err( I18n.ERR_04134, alias ) ); 1403 return null; 1404 } 1405 } 1406 1407 1408 /** 1409 * {@inheritDoc} 1410 */ 1411 @Override 1412 public Attribute get( AttributeType attributeType ) 1413 { 1414 if ( attributeType != null ) 1415 { 1416 return attributes.get( attributeType.getOid() ); 1417 } 1418 else 1419 { 1420 return null; 1421 } 1422 } 1423 1424 1425 /** 1426 * {@inheritDoc} 1427 */ 1428 @Override 1429 public Collection<Attribute> getAttributes() 1430 { 1431 return Collections.unmodifiableMap( attributes ).values(); 1432 } 1433 1434 1435 /** 1436 * {@inheritDoc} 1437 */ 1438 public Attribute put( String upId, byte[]... values ) 1439 { 1440 if ( Strings.isEmpty( upId ) ) 1441 { 1442 String message = I18n.err( I18n.ERR_04457_NULL_ATTRIBUTE_ID ); 1443 LOG.error( message ); 1444 throw new IllegalArgumentException( message ); 1445 } 1446 1447 if ( schemaManager == null ) 1448 { 1449 // Get the normalized form of the ID 1450 String id = getId( upId ); 1451 1452 // Create a new attribute 1453 Attribute clientAttribute = new DefaultAttribute( upId, values ); 1454 1455 // Replace the previous one, and return it back 1456 return attributes.put( id, clientAttribute ); 1457 } 1458 else 1459 { 1460 try 1461 { 1462 return put( upId, getAttributeType( upId ), values ); 1463 } 1464 catch ( LdapException ne ) 1465 { 1466 String message = I18n.err( I18n.ERR_04464, upId, ne.getLocalizedMessage() ); 1467 LOG.error( message ); 1468 throw new IllegalArgumentException( message, ne ); 1469 } 1470 } 1471 } 1472 1473 1474 /** 1475 * {@inheritDoc} 1476 */ 1477 @Override 1478 public Attribute put( String upId, String... values ) 1479 { 1480 if ( Strings.isEmpty( upId ) ) 1481 { 1482 String message = I18n.err( I18n.ERR_04457_NULL_ATTRIBUTE_ID ); 1483 LOG.error( message ); 1484 throw new IllegalArgumentException( message ); 1485 } 1486 1487 if ( schemaManager == null ) 1488 { 1489 // Get the normalized form of the ID 1490 String id = getId( upId ); 1491 1492 // Create a new attribute 1493 Attribute clientAttribute = new DefaultAttribute( upId, values ); 1494 1495 // Replace the previous one, and return it back 1496 return attributes.put( id, clientAttribute ); 1497 } 1498 else 1499 { 1500 try 1501 { 1502 return put( upId, getAttributeType( upId ), values ); 1503 } 1504 catch ( LdapException ne ) 1505 { 1506 String message = I18n.err( I18n.ERR_04464, upId, ne.getLocalizedMessage() ); 1507 LOG.error( message ); 1508 throw new IllegalArgumentException( message, ne ); 1509 } 1510 } 1511 } 1512 1513 1514 /** 1515 * {@inheritDoc} 1516 */ 1517 @Override 1518 public Attribute put( String upId, Value<?>... values ) 1519 { 1520 if ( Strings.isEmpty( upId ) ) 1521 { 1522 String message = I18n.err( I18n.ERR_04457_NULL_ATTRIBUTE_ID ); 1523 LOG.error( message ); 1524 throw new IllegalArgumentException( message ); 1525 } 1526 1527 if ( schemaManager == null ) 1528 { 1529 // Get the normalized form of the ID 1530 String id = getId( upId ); 1531 1532 // Create a new attribute 1533 Attribute clientAttribute = new DefaultAttribute( upId, values ); 1534 1535 // Replace the previous one, and return it back 1536 return attributes.put( id, clientAttribute ); 1537 } 1538 else 1539 { 1540 try 1541 { 1542 return put( upId, getAttributeType( upId ), values ); 1543 } 1544 catch ( LdapException ne ) 1545 { 1546 String message = I18n.err( I18n.ERR_04464, upId, ne.getLocalizedMessage() ); 1547 LOG.error( message ); 1548 throw new IllegalArgumentException( message, ne ); 1549 } 1550 } 1551 } 1552 1553 1554 /** 1555 * {@inheritDoc} 1556 */ 1557 @Override 1558 public List<Attribute> put( Attribute... attributes ) throws LdapException 1559 { 1560 // First, get the existing attributes 1561 List<Attribute> previous = new ArrayList<>(); 1562 1563 if ( schemaManager == null ) 1564 { 1565 for ( Attribute attribute : attributes ) 1566 { 1567 String id = attribute.getId(); 1568 1569 if ( containsAttribute( id ) ) 1570 { 1571 // Store the attribute and remove it from the list 1572 previous.add( get( id ) ); 1573 this.attributes.remove( id ); 1574 } 1575 1576 // add the new one 1577 this.attributes.put( id, attribute ); 1578 } 1579 } 1580 else 1581 { 1582 for ( Attribute attribute : attributes ) 1583 { 1584 if ( attribute == null ) 1585 { 1586 String message = I18n.err( I18n.ERR_04462 ); 1587 LOG.error( message ); 1588 throw new IllegalArgumentException( message ); 1589 } 1590 1591 if ( attribute.getAttributeType() == null ) 1592 { 1593 AttributeType attributeType = schemaManager.lookupAttributeTypeRegistry( attribute.getId() ); 1594 attribute.apply( attributeType ); 1595 } 1596 1597 Attribute removed = this.attributes.put( attribute.getAttributeType().getOid(), attribute ); 1598 1599 if ( removed != null ) 1600 { 1601 previous.add( removed ); 1602 } 1603 } 1604 } 1605 1606 // return the previous attributes 1607 return previous; 1608 } 1609 1610 1611 /** 1612 * {@inheritDoc} 1613 */ 1614 public Attribute put( AttributeType attributeType, byte[]... values ) throws LdapException 1615 { 1616 return put( null, attributeType, values ); 1617 } 1618 1619 1620 /** 1621 * {@inheritDoc} 1622 */ 1623 @Override 1624 public Attribute put( AttributeType attributeType, String... values ) throws LdapException 1625 { 1626 return put( null, attributeType, values ); 1627 } 1628 1629 1630 /** 1631 * {@inheritDoc} 1632 */ 1633 @Override 1634 public Attribute put( AttributeType attributeType, Value<?>... values ) throws LdapException 1635 { 1636 return put( null, attributeType, values ); 1637 } 1638 1639 1640 /** 1641 * {@inheritDoc} 1642 */ 1643 public Attribute put( String upId, AttributeType attributeType, byte[]... values ) throws LdapException 1644 { 1645 if ( attributeType == null ) 1646 { 1647 try 1648 { 1649 attributeType = getAttributeType( upId ); 1650 } 1651 catch ( Exception e ) 1652 { 1653 String message = I18n.err( I18n.ERR_04477_NO_VALID_AT_FOR_THIS_ID ); 1654 LOG.error( message ); 1655 throw new IllegalArgumentException( message, e ); 1656 } 1657 } 1658 else 1659 { 1660 if ( !Strings.isEmpty( upId ) ) 1661 { 1662 AttributeType tempAT = getAttributeType( upId ); 1663 1664 if ( !tempAT.equals( attributeType ) ) 1665 { 1666 String message = I18n.err( I18n.ERR_04463, upId, attributeType ); 1667 LOG.error( message ); 1668 throw new IllegalArgumentException( message ); 1669 } 1670 } 1671 else 1672 { 1673 upId = getUpId( upId, attributeType ); 1674 } 1675 } 1676 1677 if ( attributeType.equals( objectClassAttributeType ) ) 1678 { 1679 String message = I18n.err( I18n.ERR_04461 ); 1680 LOG.error( message ); 1681 throw new UnsupportedOperationException( message ); 1682 } 1683 1684 Attribute attribute = new DefaultAttribute( upId, attributeType, values ); 1685 1686 return attributes.put( attributeType.getOid(), attribute ); 1687 } 1688 1689 1690 /** 1691 * {@inheritDoc} 1692 */ 1693 @Override 1694 public Attribute put( String upId, AttributeType attributeType, String... values ) throws LdapException 1695 { 1696 if ( attributeType == null ) 1697 { 1698 try 1699 { 1700 attributeType = getAttributeType( upId ); 1701 } 1702 catch ( Exception e ) 1703 { 1704 String message = I18n.err( I18n.ERR_04477_NO_VALID_AT_FOR_THIS_ID ); 1705 LOG.error( message ); 1706 throw new IllegalArgumentException( message, e ); 1707 } 1708 } 1709 else 1710 { 1711 if ( !Strings.isEmpty( upId ) ) 1712 { 1713 AttributeType tempAT = getAttributeType( upId ); 1714 1715 if ( !tempAT.equals( attributeType ) ) 1716 { 1717 String message = I18n.err( I18n.ERR_04463, upId, attributeType ); 1718 LOG.error( message ); 1719 throw new IllegalArgumentException( message ); 1720 } 1721 } 1722 else 1723 { 1724 upId = getUpId( upId, attributeType ); 1725 } 1726 } 1727 1728 Attribute attribute = new DefaultAttribute( upId, attributeType, values ); 1729 1730 return attributes.put( attributeType.getOid(), attribute ); 1731 } 1732 1733 1734 /** 1735 * {@inheritDoc} 1736 */ 1737 @Override 1738 public Attribute put( String upId, AttributeType attributeType, Value<?>... values ) throws LdapException 1739 { 1740 if ( attributeType == null ) 1741 { 1742 try 1743 { 1744 attributeType = getAttributeType( upId ); 1745 } 1746 catch ( Exception e ) 1747 { 1748 String message = I18n.err( I18n.ERR_04477_NO_VALID_AT_FOR_THIS_ID ); 1749 LOG.error( message ); 1750 throw new IllegalArgumentException( message, e ); 1751 } 1752 } 1753 else 1754 { 1755 if ( !Strings.isEmpty( upId ) ) 1756 { 1757 AttributeType tempAT = getAttributeType( upId ); 1758 1759 if ( !tempAT.equals( attributeType ) ) 1760 { 1761 String message = I18n.err( I18n.ERR_04463, upId, attributeType ); 1762 LOG.error( message ); 1763 throw new IllegalArgumentException( message ); 1764 } 1765 } 1766 else 1767 { 1768 upId = getUpId( upId, attributeType ); 1769 } 1770 } 1771 1772 Attribute attribute = new DefaultAttribute( upId, attributeType, values ); 1773 1774 return attributes.put( attributeType.getOid(), attribute ); 1775 } 1776 1777 1778 /** 1779 * {@inheritDoc} 1780 */ 1781 @Override 1782 public List<Attribute> remove( Attribute... attributes ) throws LdapException 1783 { 1784 List<Attribute> removedAttributes = new ArrayList<>(); 1785 1786 if ( schemaManager == null ) 1787 { 1788 for ( Attribute attribute : attributes ) 1789 { 1790 if ( containsAttribute( attribute.getId() ) ) 1791 { 1792 this.attributes.remove( attribute.getId() ); 1793 removedAttributes.add( attribute ); 1794 } 1795 } 1796 } 1797 else 1798 { 1799 for ( Attribute attribute : attributes ) 1800 { 1801 AttributeType attributeType = attribute.getAttributeType(); 1802 1803 if ( attributeType == null ) 1804 { 1805 String message = I18n.err( I18n.ERR_04460_ATTRIBUTE_TYPE_NULL_NOT_ALLOWED ); 1806 LOG.error( message ); 1807 throw new IllegalArgumentException( message ); 1808 } 1809 1810 if ( this.attributes.containsKey( attributeType.getOid() ) ) 1811 { 1812 this.attributes.remove( attributeType.getOid() ); 1813 removedAttributes.add( attribute ); 1814 } 1815 } 1816 } 1817 1818 return removedAttributes; 1819 } 1820 1821 1822 /** 1823 * {@inheritDoc} 1824 */ 1825 public boolean remove( AttributeType attributeType, byte[]... values ) throws LdapException 1826 { 1827 if ( attributeType == null ) 1828 { 1829 return false; 1830 } 1831 1832 try 1833 { 1834 Attribute attribute = attributes.get( attributeType.getOid() ); 1835 1836 if ( attribute == null ) 1837 { 1838 // Can't remove values from a not existing attribute ! 1839 return false; 1840 } 1841 1842 int nbOldValues = attribute.size(); 1843 1844 // Remove the values 1845 attribute.remove( values ); 1846 1847 if ( attribute.size() == 0 ) 1848 { 1849 // No mare values, remove the attribute 1850 attributes.remove( attributeType.getOid() ); 1851 1852 return true; 1853 } 1854 1855 return nbOldValues != attribute.size(); 1856 } 1857 catch ( IllegalArgumentException iae ) 1858 { 1859 LOG.error( I18n.err( I18n.ERR_04465, attributeType ) ); 1860 return false; 1861 } 1862 } 1863 1864 1865 /** 1866 * {@inheritDoc} 1867 */ 1868 @Override 1869 public boolean remove( AttributeType attributeType, String... values ) throws LdapException 1870 { 1871 if ( attributeType == null ) 1872 { 1873 return false; 1874 } 1875 1876 try 1877 { 1878 Attribute attribute = attributes.get( attributeType.getOid() ); 1879 1880 if ( attribute == null ) 1881 { 1882 // Can't remove values from a not existing attribute ! 1883 return false; 1884 } 1885 1886 int nbOldValues = attribute.size(); 1887 1888 // Remove the values 1889 attribute.remove( values ); 1890 1891 if ( attribute.size() == 0 ) 1892 { 1893 // No mare values, remove the attribute 1894 attributes.remove( attributeType.getOid() ); 1895 1896 return true; 1897 } 1898 1899 return nbOldValues != attribute.size(); 1900 } 1901 catch ( IllegalArgumentException iae ) 1902 { 1903 LOG.error( I18n.err( I18n.ERR_04465, attributeType ) ); 1904 return false; 1905 } 1906 } 1907 1908 1909 /** 1910 * {@inheritDoc} 1911 */ 1912 @Override 1913 public boolean remove( AttributeType attributeType, Value<?>... values ) throws LdapException 1914 { 1915 if ( attributeType == null ) 1916 { 1917 return false; 1918 } 1919 1920 try 1921 { 1922 Attribute attribute = attributes.get( attributeType.getOid() ); 1923 1924 if ( attribute == null ) 1925 { 1926 // Can't remove values from a not existing attribute ! 1927 return false; 1928 } 1929 1930 int nbOldValues = attribute.size(); 1931 1932 // Remove the values 1933 attribute.remove( values ); 1934 1935 if ( attribute.size() == 0 ) 1936 { 1937 // No mare values, remove the attribute 1938 attributes.remove( attributeType.getOid() ); 1939 1940 return true; 1941 } 1942 1943 return nbOldValues != attribute.size(); 1944 } 1945 catch ( IllegalArgumentException iae ) 1946 { 1947 LOG.error( I18n.err( I18n.ERR_04465, attributeType ) ); 1948 return false; 1949 } 1950 } 1951 1952 1953 /** 1954 * <p> 1955 * Removes the attribute with the specified AttributeTypes. 1956 * </p> 1957 * <p> 1958 * The removed attribute are returned by this method. 1959 * </p> 1960 * <p> 1961 * If there is no attribute with the specified AttributeTypes, 1962 * the return value is <code>null</code>. 1963 * </p> 1964 * 1965 * @param attributes the AttributeTypes to be removed 1966 */ 1967 @Override 1968 public void removeAttributes( AttributeType... attributes ) 1969 { 1970 if ( ( attributes == null ) || ( attributes.length == 0 ) || ( schemaManager == null ) ) 1971 { 1972 return; 1973 } 1974 1975 for ( AttributeType attributeType : attributes ) 1976 { 1977 if ( attributeType == null ) 1978 { 1979 continue; 1980 } 1981 1982 this.attributes.remove( attributeType.getOid() ); 1983 } 1984 } 1985 1986 1987 /** 1988 * {@inheritDoc} 1989 */ 1990 @Override 1991 public void removeAttributes( String... attributes ) 1992 { 1993 if ( attributes.length == 0 ) 1994 { 1995 return; 1996 } 1997 1998 if ( schemaManager == null ) 1999 { 2000 for ( String attribute : attributes ) 2001 { 2002 Attribute attr = get( attribute ); 2003 2004 if ( attr != null ) 2005 { 2006 this.attributes.remove( attr.getId() ); 2007 } 2008 else 2009 { 2010 String message = I18n.err( I18n.ERR_04137, attribute ); 2011 LOG.warn( message ); 2012 continue; 2013 } 2014 } 2015 } 2016 else 2017 { 2018 for ( String attribute : attributes ) 2019 { 2020 AttributeType attributeType = null; 2021 2022 try 2023 { 2024 attributeType = schemaManager.lookupAttributeTypeRegistry( attribute ); 2025 } 2026 catch ( LdapException ne ) 2027 { 2028 String message = "The attribute '" + attribute + "' does not exist in the entry"; 2029 LOG.warn( message ); 2030 continue; 2031 } 2032 2033 this.attributes.remove( attributeType.getOid() ); 2034 } 2035 } 2036 } 2037 2038 2039 /** 2040 * <p> 2041 * Removes the specified binary values from an attribute. 2042 * </p> 2043 * <p> 2044 * If at least one value is removed, this method returns <code>true</code>. 2045 * </p> 2046 * <p> 2047 * If there is no more value after having removed the values, the attribute 2048 * will be removed too. 2049 * </p> 2050 * <p> 2051 * If the attribute does not exist, nothing is done and the method returns 2052 * <code>false</code> 2053 * </p> 2054 * 2055 * @param upId The attribute ID 2056 * @param values the values to be removed 2057 * @return <code>true</code> if at least a value is removed, <code>false</code> 2058 * if not all the values have been removed or if the attribute does not exist. 2059 */ 2060 public boolean remove( String upId, byte[]... values ) throws LdapException 2061 { 2062 if ( Strings.isEmpty( upId ) ) 2063 { 2064 String message = I18n.err( I18n.ERR_04457_NULL_ATTRIBUTE_ID ); 2065 LOG.info( message ); 2066 return false; 2067 } 2068 2069 if ( schemaManager == null ) 2070 { 2071 String id = getId( upId ); 2072 2073 Attribute attribute = get( id ); 2074 2075 if ( attribute == null ) 2076 { 2077 // Can't remove values from a not existing attribute ! 2078 return false; 2079 } 2080 2081 int nbOldValues = attribute.size(); 2082 2083 // Remove the values 2084 attribute.remove( values ); 2085 2086 if ( attribute.size() == 0 ) 2087 { 2088 // No mare values, remove the attribute 2089 attributes.remove( id ); 2090 2091 return true; 2092 } 2093 2094 return nbOldValues != attribute.size(); 2095 } 2096 else 2097 { 2098 try 2099 { 2100 AttributeType attributeType = getAttributeType( upId ); 2101 2102 return remove( attributeType, values ); 2103 } 2104 catch ( LdapException ne ) 2105 { 2106 LOG.error( I18n.err( I18n.ERR_04465, upId ) ); 2107 return false; 2108 } 2109 catch ( IllegalArgumentException iae ) 2110 { 2111 LOG.error( I18n.err( I18n.ERR_04466, upId ) ); 2112 return false; 2113 } 2114 } 2115 2116 } 2117 2118 2119 /** 2120 * <p> 2121 * Removes the specified String values from an attribute. 2122 * </p> 2123 * <p> 2124 * If at least one value is removed, this method returns <code>true</code>. 2125 * </p> 2126 * <p> 2127 * If there is no more value after having removed the values, the attribute 2128 * will be removed too. 2129 * </p> 2130 * <p> 2131 * If the attribute does not exist, nothing is done and the method returns 2132 * <code>false</code> 2133 * </p> 2134 * 2135 * @param upId The attribute ID 2136 * @param values the attributes to be removed 2137 * @return <code>true</code> if at least a value is removed, <code>false</code> 2138 * if not all the values have been removed or if the attribute does not exist. 2139 */ 2140 @Override 2141 public boolean remove( String upId, String... values ) throws LdapException 2142 { 2143 if ( Strings.isEmpty( upId ) ) 2144 { 2145 String message = I18n.err( I18n.ERR_04457_NULL_ATTRIBUTE_ID ); 2146 LOG.info( message ); 2147 return false; 2148 } 2149 2150 if ( schemaManager == null ) 2151 { 2152 String id = getId( upId ); 2153 2154 Attribute attribute = get( id ); 2155 2156 if ( attribute == null ) 2157 { 2158 // Can't remove values from a not existing attribute ! 2159 return false; 2160 } 2161 2162 int nbOldValues = attribute.size(); 2163 2164 // Remove the values 2165 attribute.remove( values ); 2166 2167 if ( attribute.size() == 0 ) 2168 { 2169 // No mare values, remove the attribute 2170 attributes.remove( id ); 2171 2172 return true; 2173 } 2174 2175 return nbOldValues != attribute.size(); 2176 } 2177 else 2178 { 2179 try 2180 { 2181 AttributeType attributeType = getAttributeType( upId ); 2182 2183 return remove( attributeType, values ); 2184 } 2185 catch ( LdapException ne ) 2186 { 2187 LOG.error( I18n.err( I18n.ERR_04465, upId ) ); 2188 return false; 2189 } 2190 catch ( IllegalArgumentException iae ) 2191 { 2192 LOG.error( I18n.err( I18n.ERR_04466, upId ) ); 2193 return false; 2194 } 2195 } 2196 } 2197 2198 2199 /** 2200 * <p> 2201 * Removes the specified values from an attribute. 2202 * </p> 2203 * <p> 2204 * If at least one value is removed, this method returns <code>true</code>. 2205 * </p> 2206 * <p> 2207 * If there is no more value after having removed the values, the attribute 2208 * will be removed too. 2209 * </p> 2210 * <p> 2211 * If the attribute does not exist, nothing is done and the method returns 2212 * <code>false</code> 2213 * </p> 2214 * 2215 * @param upId The attribute ID 2216 * @param values the attributes to be removed 2217 * @return <code>true</code> if at least a value is removed, <code>false</code> 2218 * if not all the values have been removed or if the attribute does not exist. 2219 */ 2220 @Override 2221 public boolean remove( String upId, Value<?>... values ) throws LdapException 2222 { 2223 if ( Strings.isEmpty( upId ) ) 2224 { 2225 String message = I18n.err( I18n.ERR_04457_NULL_ATTRIBUTE_ID ); 2226 LOG.info( message ); 2227 return false; 2228 } 2229 2230 if ( schemaManager == null ) 2231 { 2232 String id = getId( upId ); 2233 2234 Attribute attribute = get( id ); 2235 2236 if ( attribute == null ) 2237 { 2238 // Can't remove values from a not existing attribute ! 2239 return false; 2240 } 2241 2242 int nbOldValues = attribute.size(); 2243 2244 // Remove the values 2245 attribute.remove( values ); 2246 2247 if ( attribute.size() == 0 ) 2248 { 2249 // No mare values, remove the attribute 2250 attributes.remove( id ); 2251 2252 return true; 2253 } 2254 2255 return nbOldValues != attribute.size(); 2256 } 2257 else 2258 { 2259 try 2260 { 2261 AttributeType attributeType = getAttributeType( upId ); 2262 2263 return remove( attributeType, values ); 2264 } 2265 catch ( LdapException ne ) 2266 { 2267 LOG.error( I18n.err( I18n.ERR_04465, upId ) ); 2268 return false; 2269 } 2270 catch ( IllegalArgumentException iae ) 2271 { 2272 LOG.error( I18n.err( I18n.ERR_04466, upId ) ); 2273 return false; 2274 } 2275 } 2276 } 2277 2278 2279 /** 2280 * Get this entry's Dn. 2281 * 2282 * @return The entry's Dn 2283 */ 2284 @Override 2285 public Dn getDn() 2286 { 2287 return dn; 2288 } 2289 2290 2291 /** 2292 * {@inheritDoc} 2293 */ 2294 @Override 2295 public void setDn( Dn dn ) 2296 { 2297 this.dn = dn; 2298 2299 // Rehash the object 2300 rehash(); 2301 } 2302 2303 2304 /** 2305 * {@inheritDoc} 2306 */ 2307 @Override 2308 public void setDn( String dn ) throws LdapInvalidDnException 2309 { 2310 setDn( new Dn( dn ) ); 2311 } 2312 2313 2314 /** 2315 * Remove all the attributes for this entry. The Dn is not reset 2316 */ 2317 @Override 2318 public void clear() 2319 { 2320 attributes.clear(); 2321 } 2322 2323 2324 /** 2325 * Returns an enumeration containing the zero or more attributes in the 2326 * collection. The behavior of the enumeration is not specified if the 2327 * attribute collection is changed. 2328 * 2329 * @return an enumeration of all contained attributes 2330 */ 2331 @Override 2332 public Iterator<Attribute> iterator() 2333 { 2334 return Collections.unmodifiableMap( attributes ).values().iterator(); 2335 } 2336 2337 2338 /** 2339 * Returns the number of attributes. 2340 * 2341 * @return the number of attributes 2342 */ 2343 @Override 2344 public int size() 2345 { 2346 return attributes.size(); 2347 } 2348 2349 2350 /** 2351 * This is the place where we serialize entries, and all theirs 2352 * elements. 2353 * <br> 2354 * The structure used to store the entry is the following : 2355 * <ul> 2356 * <li> 2357 * <b>[Dn]</b> : If it's null, stores an empty Dn 2358 * </li> 2359 * <li> 2360 * <b>[attributes number]</b> : the number of attributes. 2361 * </li> 2362 * <li> 2363 * <b>[attribute]*</b> : each attribute, if we have some 2364 * </li> 2365 * </ul> 2366 * 2367 * {@inheritDoc} 2368 */ 2369 @Override 2370 public void writeExternal( ObjectOutput out ) throws IOException 2371 { 2372 // First, the Dn 2373 if ( dn == null ) 2374 { 2375 // Write an empty Dn 2376 Dn.EMPTY_DN.writeExternal( out ); 2377 } 2378 else 2379 { 2380 // Write the Dn 2381 dn.writeExternal( out ); 2382 } 2383 2384 // Then the attributes. 2385 // Store the attributes' nulber first 2386 out.writeInt( attributes.size() ); 2387 2388 // Iterate through the keys. 2389 for ( Attribute attribute : attributes.values() ) 2390 { 2391 // Store the attribute 2392 attribute.writeExternal( out ); 2393 } 2394 2395 out.flush(); 2396 } 2397 2398 2399 /** 2400 * {@inheritDoc} 2401 */ 2402 @Override 2403 public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException 2404 { 2405 // Read the Dn 2406 dn = new Dn( schemaManager ); 2407 dn.readExternal( in ); 2408 2409 // Read the number of attributes 2410 int nbAttributes = in.readInt(); 2411 2412 // Read the attributes 2413 for ( int i = 0; i < nbAttributes; i++ ) 2414 { 2415 // Read each attribute 2416 Attribute attribute = new DefaultAttribute(); 2417 attribute.readExternal( in ); 2418 2419 if ( schemaManager != null ) 2420 { 2421 try 2422 { 2423 AttributeType attributeType = schemaManager.lookupAttributeTypeRegistry( attribute.getId() ); 2424 attribute.apply( attributeType ); 2425 2426 attributes.put( attributeType.getOid(), attribute ); 2427 } 2428 catch ( LdapException le ) 2429 { 2430 String message = le.getLocalizedMessage(); 2431 LOG.error( message ); 2432 throw new IOException( message, le ); 2433 } 2434 } 2435 else 2436 { 2437 attributes.put( attribute.getId(), attribute ); 2438 } 2439 } 2440 } 2441 2442 2443 /** 2444 * Get the hash code of this ClientEntry. The Attributes will be sorted 2445 * before the comparison can be done. 2446 * 2447 * @see java.lang.Object#hashCode() 2448 * @return the instance's hash code 2449 */ 2450 @Override 2451 public int hashCode() 2452 { 2453 if ( h == 0 ) 2454 { 2455 rehash(); 2456 } 2457 2458 return h; 2459 } 2460 2461 2462 /** 2463 * {@inheritDoc} 2464 */ 2465 @Override 2466 public boolean hasObjectClass( String... objectClasses ) 2467 { 2468 if ( ( objectClasses == null ) || ( objectClasses.length == 0 ) || ( objectClasses[0] == null ) ) 2469 { 2470 return false; 2471 } 2472 2473 for ( String objectClass : objectClasses ) 2474 { 2475 if ( schemaManager != null ) 2476 { 2477 if ( !contains( objectClassAttributeType, objectClass ) ) 2478 { 2479 return false; 2480 } 2481 } 2482 else 2483 { 2484 if ( !contains( "objectclass", objectClass ) ) 2485 { 2486 return false; 2487 } 2488 } 2489 } 2490 2491 return true; 2492 } 2493 2494 2495 /** 2496 * {@inheritDoc} 2497 */ 2498 @Override 2499 public boolean hasObjectClass( Attribute... objectClasses ) 2500 { 2501 if ( ( objectClasses == null ) || ( objectClasses.length == 0 ) || ( objectClasses[0] == null ) ) 2502 { 2503 return false; 2504 } 2505 2506 for ( Attribute objectClass : objectClasses ) 2507 { 2508 // We have to check that we are checking the ObjectClass attributeType 2509 if ( !objectClass.getAttributeType().equals( objectClassAttributeType ) ) 2510 { 2511 return false; 2512 } 2513 2514 Attribute attribute = attributes.get( objectClassAttributeType.getOid() ); 2515 2516 if ( attribute == null ) 2517 { 2518 // The entry does not have an ObjectClass attribute 2519 return false; 2520 } 2521 2522 for ( Value<?> value : objectClass ) 2523 { 2524 // Loop on all the values, and check if they are present 2525 if ( !attribute.contains( value.getString() ) ) 2526 { 2527 return false; 2528 } 2529 } 2530 } 2531 2532 return true; 2533 } 2534 2535 2536 /** 2537 * {@inheritDoc} 2538 */ 2539 @Override 2540 public boolean isSchemaAware() 2541 { 2542 return schemaManager != null; 2543 } 2544 2545 2546 /** 2547 * @see Object#equals(Object) 2548 */ 2549 @Override 2550 public boolean equals( Object o ) 2551 { 2552 // Short circuit 2553 if ( this == o ) 2554 { 2555 return true; 2556 } 2557 2558 if ( !( o instanceof Entry ) ) 2559 { 2560 return false; 2561 } 2562 2563 Entry other = ( Entry ) o; 2564 2565 // Both Dn must be equal 2566 if ( dn == null ) 2567 { 2568 if ( other.getDn() != null ) 2569 { 2570 return false; 2571 } 2572 } 2573 else 2574 { 2575 if ( !dn.equals( other.getDn() ) ) 2576 { 2577 return false; 2578 } 2579 } 2580 2581 // They must have the same number of attributes 2582 if ( size() != other.size() ) 2583 { 2584 return false; 2585 } 2586 2587 // Each attribute must be equal 2588 for ( Attribute attribute : other ) 2589 { 2590 if ( !attribute.equals( this.get( attribute.getId() ) ) ) 2591 { 2592 return false; 2593 } 2594 } 2595 2596 return true; 2597 } 2598 2599 2600 /** 2601 * @see Object#toString() 2602 */ 2603 @Override 2604 public String toString() 2605 { 2606 return toString( "" ); 2607 } 2608 2609 2610 /** 2611 * {@inheritDoc} 2612 */ 2613 @Override 2614 public String toString( String tabs ) 2615 { 2616 StringBuilder sb = new StringBuilder(); 2617 2618 sb.append( tabs ).append( "Entry\n" ); 2619 sb.append( tabs ).append( " dn" ); 2620 2621 if ( dn.isSchemaAware() ) 2622 { 2623 sb.append( "[n]" ); 2624 } 2625 2626 sb.append( ": " ); 2627 sb.append( dn.getName() ); 2628 sb.append( '\n' ); 2629 2630 // First dump the ObjectClass attribute 2631 if ( schemaManager != null ) 2632 { 2633 // First dump the ObjectClass attribute 2634 if ( containsAttribute( objectClassAttributeType.getOid() ) ) 2635 { 2636 Attribute objectClass = get( objectClassAttributeType ); 2637 2638 sb.append( objectClass.toString( tabs + " " ) ); 2639 } 2640 } 2641 else 2642 { 2643 if ( containsAttribute( "objectClass" ) ) 2644 { 2645 Attribute objectClass = get( "objectclass" ); 2646 2647 sb.append( objectClass.toString( tabs + " " ) ); 2648 } 2649 } 2650 2651 sb.append( '\n' ); 2652 2653 if ( attributes.size() != 0 ) 2654 { 2655 for ( Attribute attribute : attributes.values() ) 2656 { 2657 String id = attribute.getId(); 2658 2659 if ( schemaManager != null ) 2660 { 2661 AttributeType attributeType = schemaManager.getAttributeType( id ); 2662 2663 if ( attributeType == null ) 2664 { 2665 sb.append( tabs ).append( "id: " ).append( id ); 2666 } 2667 else if ( !attributeType.equals( objectClassAttributeType ) ) 2668 { 2669 sb.append( attribute.toString( tabs + " " ) ); 2670 sb.append( '\n' ); 2671 continue; 2672 } 2673 } 2674 else 2675 { 2676 if ( !id.equalsIgnoreCase( SchemaConstants.OBJECT_CLASS_AT ) 2677 && !id.equals( SchemaConstants.OBJECT_CLASS_AT_OID ) ) 2678 { 2679 sb.append( attribute.toString( tabs + " " ) ); 2680 sb.append( '\n' ); 2681 continue; 2682 } 2683 } 2684 } 2685 } 2686 2687 return sb.toString(); 2688 } 2689}