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