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