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     */
020    package org.apache.directory.shared.ldap.schema;
021    
022    
023    import java.util.ArrayList;
024    import java.util.List;
025    
026    import javax.naming.NamingException;
027    
028    import org.apache.directory.shared.i18n.I18n;
029    import org.apache.directory.shared.ldap.exception.LdapSchemaViolationException;
030    import org.apache.directory.shared.ldap.message.ResultCodeEnum;
031    import org.apache.directory.shared.ldap.schema.registries.AttributeTypeRegistry;
032    import org.apache.directory.shared.ldap.schema.registries.ObjectClassRegistry;
033    import org.apache.directory.shared.ldap.schema.registries.Registries;
034    
035    
036    /**
037     * An objectClass definition.
038     * <p>
039     * According to ldapbis [MODELS]:
040     * </p>
041     * 
042     * <pre>
043     *  Object Class definitions are written according to the ABNF:
044     *  
045     *    ObjectClassDescription = LPAREN WSP
046     *        numericoid                ; object identifier
047     *        [ SP &quot;NAME&quot; SP qdescrs ]  ; short names (descriptors)
048     *        [ SP &quot;DESC&quot; SP qdstring ] ; description
049     *        [ SP &quot;OBSOLETE&quot; ]         ; not active
050     *        [ SP &quot;SUP&quot; SP oids ]      ; superior object classes
051     *        [ SP kind ]               ; kind of class
052     *        [ SP &quot;MUST&quot; SP oids ]     ; attribute types
053     *        [ SP &quot;MAY&quot; SP oids ]      ; attribute types
054     *        extensions WSP RPAREN
055     * 
056     *     kind = &quot;ABSTRACT&quot; / &quot;STRUCTURAL&quot; / &quot;AUXILIARY&quot;
057     * 
058     *   where:
059     *     [numericoid] is object identifier assigned to this object class;
060     *     NAME [qdescrs] are short names (descriptors) identifying this object
061     *         class;
062     *     DESC [qdstring] is a short descriptive string;
063     *     OBSOLETE indicates this object class is not active;
064     *     SUP [oids] specifies the direct superclasses of this object class;
065     *     the kind of object class is indicated by one of ABSTRACT,
066     *         STRUCTURAL, or AUXILIARY, default is STRUCTURAL;
067     *     MUST and MAY specify the sets of required and allowed attribute
068     *         types, respectively; and
069     *    [extensions] describe extensions.
070     * </pre>
071     * 
072     * @see <a href="http://www.faqs.org/rfcs/rfc2252.html">RFC2252 Section 4.4</a>
073     * @see <a
074     *      href="http://www.ietf.org/internet-drafts/draft-ietf-ldapbis-models-11.txt">ldapbis
075     *      [MODELS]</a>
076     * @see DescriptionUtils#getDescription(ObjectClass)
077     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
078     * @version $Rev: 919765 $
079     */
080    public class ObjectClass extends AbstractSchemaObject
081    {
082        /** The serialVersionUID */
083        private static final long serialVersionUID = 1L;
084    
085        /** The ObjectClass type : ABSTRACT, AUXILIARY or STRUCTURAL */
086        private ObjectClassTypeEnum objectClassType = ObjectClassTypeEnum.STRUCTURAL;
087    
088        /** The ObjectClass superior OIDs */
089        private List<String> superiorOids;
090    
091        /** The ObjectClass superiors */
092        private List<ObjectClass> superiors;
093    
094        /** The list of allowed AttributeType OIDs */
095        private List<String> mayAttributeTypeOids;
096    
097        /** The list of allowed AttributeTypes */
098        private List<AttributeType> mayAttributeTypes;
099    
100        /** The list of required AttributeType OIDs */
101        private List<String> mustAttributeTypeOids;
102    
103        /** The list of required AttributeTypes */
104        private List<AttributeType> mustAttributeTypes;
105    
106    
107        /**
108         * Creates a new instance of MatchingRuleUseDescription
109         * @param oid the OID for this objectClass
110         */
111        public ObjectClass( String oid )
112        {
113            super( SchemaObjectType.OBJECT_CLASS, oid );
114    
115            mayAttributeTypeOids = new ArrayList<String>();
116            mustAttributeTypeOids = new ArrayList<String>();
117            superiorOids = new ArrayList<String>();
118    
119            mayAttributeTypes = new ArrayList<AttributeType>();
120            mustAttributeTypes = new ArrayList<AttributeType>();
121            superiors = new ArrayList<ObjectClass>();
122            objectClassType = ObjectClassTypeEnum.STRUCTURAL;
123        }
124    
125    
126        private void buildSuperiors( List<Throwable> errors, Registries registries )
127        {
128            ObjectClassRegistry ocRegistry = registries.getObjectClassRegistry();
129    
130            if ( superiorOids != null )
131            {
132                superiors = new ArrayList<ObjectClass>( superiorOids.size() );
133    
134                for ( String superiorName : superiorOids )
135                {
136                    try
137                    {
138                        ObjectClass superior = ocRegistry.lookup( ocRegistry.getOidByName( superiorName ) );
139    
140                        // Before adding the superior, check that the ObjectClass type is consistent
141                        switch ( objectClassType )
142                        {
143                            case ABSTRACT:
144                                if ( superior.objectClassType != ObjectClassTypeEnum.ABSTRACT )
145                                {
146                                    // An ABSTRACT OC can only inherit from ABSTRACT OCs
147                                    String msg = I18n.err( I18n.ERR_04318, oid , superior.getObjectType() , superior );
148    
149                                    Throwable error = new LdapSchemaViolationException( msg,
150                                        ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX );
151                                    errors.add( error );
152                                    return;
153                                }
154    
155                                break;
156    
157                            case AUXILIARY:
158                                if ( superior.objectClassType == ObjectClassTypeEnum.STRUCTURAL )
159                                {
160                                    // An AUXILIARY OC can only inherit from STRUCTURAL OCs
161                                    String msg = I18n.err( I18n.ERR_04319, oid, superior );
162    
163                                    Throwable error = new LdapSchemaViolationException( msg,
164                                        ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX );
165                                    errors.add( error );
166                                    return;
167                                }
168    
169                                break;
170    
171                            case STRUCTURAL:
172                                if ( superior.objectClassType == ObjectClassTypeEnum.AUXILIARY )
173                                {
174                                    // A STRUCTURAL OC can only inherit from AUXILIARY OCs
175                                    String msg = I18n.err( I18n.ERR_04320, oid, superior );
176    
177                                    Throwable error = new LdapSchemaViolationException( msg,
178                                        ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX );
179                                    errors.add( error );
180                                    return;
181                                }
182    
183                                break;
184                        }
185    
186                        superiors.add( superior );
187                    }
188                    catch ( NamingException ne )
189                    {
190                        // Cannot find the OC
191                        String msg = I18n.err( I18n.ERR_04321, oid, superiorName );
192    
193                        Throwable error = new LdapSchemaViolationException( msg, ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX );
194                        errors.add( error );
195                        return;
196                    }
197                }
198            }
199        }
200    
201    
202        private void buildMay( List<Throwable> errors, Registries registries )
203        {
204            AttributeTypeRegistry atRegistry = registries.getAttributeTypeRegistry();
205    
206            if ( mayAttributeTypeOids != null )
207            {
208                mayAttributeTypes = new ArrayList<AttributeType>( mayAttributeTypeOids.size() );
209    
210                for ( String mayAttributeTypeName : mayAttributeTypeOids )
211                {
212                    try
213                    {
214                        AttributeType attributeType = atRegistry.lookup( mayAttributeTypeName );
215    
216                        if ( mayAttributeTypes.contains( attributeType ) )
217                        {
218                            // Already registered : this is an error
219                            String msg = I18n.err( I18n.ERR_04322, oid, mayAttributeTypeName );
220                            Throwable error = new LdapSchemaViolationException( msg,
221                                ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX );
222                            errors.add( error );
223                            break;
224                        }
225    
226                        mayAttributeTypes.add( attributeType );
227                    }
228                    catch ( NamingException ne )
229                    {
230                        // Cannot find the AT
231                        String msg = I18n.err( I18n.ERR_04323, oid, mayAttributeTypeName );
232    
233                        Throwable error = new LdapSchemaViolationException( msg, ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX );
234                        errors.add( error );
235                        break;
236                    }
237                }
238            }
239        }
240    
241    
242        private void buildMust( List<Throwable> errors, Registries registries )
243        {
244            AttributeTypeRegistry atRegistry = registries.getAttributeTypeRegistry();
245    
246            if ( mustAttributeTypeOids != null )
247            {
248                mustAttributeTypes = new ArrayList<AttributeType>( mustAttributeTypeOids.size() );
249    
250                for ( String mustAttributeTypeName : mustAttributeTypeOids )
251                {
252                    try
253                    {
254                        AttributeType attributeType = atRegistry.lookup( mustAttributeTypeName );
255    
256                        if ( mustAttributeTypes.contains( attributeType ) )
257                        {
258                            // Already registered : this is an error
259                            String msg = I18n.err( I18n.ERR_04324, oid, mustAttributeTypeName );
260    
261                            Throwable error = new LdapSchemaViolationException( msg,
262                                ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX );
263                            errors.add( error );
264                            break;
265                        }
266    
267                        // Check that the MUST AT is not also present in the MAY AT
268                        if ( mayAttributeTypes.contains( attributeType ) )
269                        {
270                            // Already registered : this is an error
271                            String msg = I18n.err( I18n.ERR_04325, oid, mustAttributeTypeName );
272    
273                            Throwable error = new LdapSchemaViolationException( msg,
274                                ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX );
275                            errors.add( error );
276                            break;
277                        }
278    
279                        mustAttributeTypes.add( attributeType );
280                    }
281                    catch ( NamingException ne )
282                    {
283                        // Cannot find the AT
284                        String msg = I18n.err( I18n.ERR_04326, oid, mustAttributeTypeName );
285    
286                        Throwable error = new LdapSchemaViolationException( msg, ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX );
287                        errors.add( error );
288                        break;
289                    }
290                }
291            }
292        }
293    
294    
295        /**
296         * Inject the ObjectClass into the registries, updating the references to
297         * other SchemaObject
298         *
299         * @param errors The errors we got while adding the ObjectClass to the registries
300         * @param registries The Registries
301         * @throws Exception on failure
302         *
303         */
304        public void addToRegistries( List<Throwable> errors, Registries registries ) throws NamingException
305        {
306            if ( registries != null )
307            {
308                // The superiors
309                buildSuperiors( errors, registries );
310    
311                // The MAY AttributeTypes
312                buildMay( errors, registries );
313    
314                // The MUST AttributeTypes
315                buildMust( errors, registries );
316    
317                /**
318                 * Add the OC references (using and usedBy) : 
319                 * OC -> AT (MAY and MUST)
320                 * OC -> OC (SUPERIORS)
321                 */
322                for ( AttributeType mayAttributeType : mayAttributeTypes )
323                {
324                    registries.addReference( this, mayAttributeType );
325                }
326    
327                for ( AttributeType mustAttributeType : mustAttributeTypes )
328                {
329                    registries.addReference( this, mustAttributeType );
330                }
331    
332                for ( ObjectClass superiorObjectClass : superiors )
333                {
334                    registries.addReference( this, superiorObjectClass );
335                }
336            }
337        }
338    
339        
340        /**
341         * Remove the ObjectClass from the registries, updating the references to
342         * other SchemaObject.
343         * 
344         * If one of the referenced SchemaObject does not exist (SUPERIORS, MAY, MUST), 
345         * an exception is thrown.
346         *
347         * @param errors The errors we got while removing the ObjectClass from the registries
348         * @param registries The Registries
349         * @exception If the ObjectClass is not valid 
350         */
351        public void removeFromRegistries( List<Throwable> errors, Registries registries ) throws NamingException
352        {
353            if ( registries != null )
354            {
355                ObjectClassRegistry objectClassRegistry = registries.getObjectClassRegistry();
356    
357                // Unregister this ObjectClass into the Descendant map
358                objectClassRegistry.unregisterDescendants( this, superiors );
359    
360                /**
361                 * Remove the OC references (using and usedBy) : 
362                 * OC -> AT (for MAY and MUST)
363                 * OC -> OC
364                 */
365                if ( mayAttributeTypes != null )
366                {
367                    for ( AttributeType may : mayAttributeTypes )
368                    {
369                        registries.delReference( this, may );
370                    }
371                }
372    
373                if ( mustAttributeTypes != null )
374                {
375                    for ( AttributeType must : mustAttributeTypes )
376                    {
377                        registries.delReference( this, must );
378                    }
379                }
380    
381                if ( superiors != null )
382                {
383                    for ( ObjectClass superior : superiors )
384                    {
385                        registries.delReference( this, superior );
386                    }
387                }
388            }
389        }
390    
391    
392        /**
393         * @return the mayAttributeTypeOids
394         */
395        public List<String> getMayAttributeTypeOids()
396        {
397            return mayAttributeTypeOids;
398        }
399    
400    
401        /**
402         * @return the mayAttributeTypes
403         */
404        public List<AttributeType> getMayAttributeTypes()
405        {
406            return mayAttributeTypes;
407        }
408    
409    
410        /**
411         * Add some allowed AttributeType
412         *
413         * @param oids The attributeType oids
414         */
415        public void addMayAttributeTypeOids( String... oids )
416        {
417            if ( !isReadOnly )
418            {
419                for ( String oid : oids )
420                {
421                    mayAttributeTypeOids.add( oid );
422                }
423            }
424        }
425    
426    
427        /**
428         * Add some allowed AttributeTypes
429         *
430         * @param attributeTypes The attributeTypes
431         */
432        public void addMayAttributeTypes( AttributeType... attributeTypes )
433        {
434            if ( !isReadOnly )
435            {
436                for ( AttributeType attributeType : attributeTypes )
437                {
438                    if ( !mayAttributeTypeOids.contains( attributeType.getOid() ) )
439                    {
440                        mayAttributeTypes.add( attributeType );
441                        mayAttributeTypeOids.add( attributeType.getOid() );
442                    }
443                }
444            }
445        }
446    
447    
448        /**
449         * @param mayAttributeTypeOids the mayAttributeTypeOids to set
450         */
451        public void setMayAttributeTypeOids( List<String> mayAttributeTypeOids )
452        {
453            if ( !isReadOnly )
454            {
455                this.mayAttributeTypeOids = mayAttributeTypeOids;
456            }
457        }
458    
459    
460        /**
461         * Sets the list of allowed AttributeTypes
462         *
463         * @param mayAttributeTypes the list of allowed AttributeTypes
464         */
465        public void setMayAttributeTypes( List<AttributeType> mayAttributeTypes )
466        {
467            if ( !isReadOnly )
468            {
469                this.mayAttributeTypes = mayAttributeTypes;
470    
471                // update the OIDS now
472                mayAttributeTypeOids.clear();
473    
474                for ( AttributeType may : mayAttributeTypes )
475                {
476                    mayAttributeTypeOids.add( may.getOid() );
477                }
478            }
479        }
480    
481    
482        /**
483         * Update the associated MAY AttributeType, even if the SchemaObject is readOnly
484         *
485         * @param mayAttributeTypes the list of allowed AttributeTypes
486         */
487        public void updateMayAttributeTypes( List<AttributeType> mayAttributeTypes )
488        {
489            this.mayAttributeTypes.clear();
490            this.mayAttributeTypes.addAll( mayAttributeTypes );
491    
492            // update the OIDS now
493            mayAttributeTypeOids.clear();
494    
495            for ( AttributeType may : mayAttributeTypes )
496            {
497                mayAttributeTypeOids.add( may.getOid() );
498            }
499        }
500    
501    
502        /**
503         * @return the mustAttributeTypeOids
504         */
505        public List<String> getMustAttributeTypeOids()
506        {
507            return mustAttributeTypeOids;
508        }
509    
510    
511        /**
512         * @return the mustAttributeTypes
513         */
514        public List<AttributeType> getMustAttributeTypes()
515        {
516            return mustAttributeTypes;
517        }
518    
519    
520        /**
521         * Add some required AttributeType OIDs
522         *
523         * @param oid The attributeType OIDs
524         */
525        public void addMustAttributeTypeOids( String... oids )
526        {
527            if ( !isReadOnly )
528            {
529                for ( String oid : oids )
530                {
531                    mustAttributeTypeOids.add( oid );
532                }
533            }
534        }
535    
536    
537        /**
538         * Add some required AttributeTypes
539         *
540         * @param attributeTypes The attributeTypse
541         */
542        public void addMustAttributeTypes( AttributeType... attributeTypes )
543        {
544            if ( !isReadOnly )
545            {
546                for ( AttributeType attributeType : attributeTypes )
547                {
548                    if ( !mustAttributeTypeOids.contains( attributeType.getOid() ) )
549                    {
550                        mustAttributeTypes.add( attributeType );
551                        mustAttributeTypeOids.add( attributeType.getOid() );
552                    }
553                }
554            }
555        }
556    
557    
558        /**
559         * @param mustAttributeTypeOids the mustAttributeTypeOids to set
560         */
561        public void setMustAttributeTypeOids( List<String> mustAttributeTypeOids )
562        {
563            if ( !isReadOnly )
564            {
565                this.mustAttributeTypeOids = mustAttributeTypeOids;
566            }
567        }
568    
569    
570        /**
571         * Sets the list of required AttributeTypes
572         *
573         * @param mustAttributeTypes the list of required AttributeTypes
574         */
575        public void setMustAttributeTypes( List<AttributeType> mustAttributeTypes )
576        {
577            if ( !isReadOnly )
578            {
579                this.mustAttributeTypes = mustAttributeTypes;
580    
581                // update the OIDS now
582                mustAttributeTypeOids.clear();
583    
584                for ( AttributeType may : mustAttributeTypes )
585                {
586                    mustAttributeTypeOids.add( may.getOid() );
587                }
588            }
589        }
590    
591    
592        /**
593         * Update the associated MUST AttributeType, even if the SchemaObject is readOnly
594         *
595         * @param mayAttributeTypes the list of allowed AttributeTypes
596         */
597        public void updateMustAttributeTypes( List<AttributeType> mustAttributeTypes )
598        {
599            this.mustAttributeTypes.clear();
600            this.mustAttributeTypes.addAll( mustAttributeTypes );
601    
602            // update the OIDS now
603            mustAttributeTypeOids.clear();
604    
605            for ( AttributeType must : mustAttributeTypes )
606            {
607                mustAttributeTypeOids.add( must.getOid() );
608            }
609        }
610    
611    
612        /**
613         * Gets the superclasses of this ObjectClass.
614         * 
615         * @return the superclasses
616         * @throws NamingException if there is a failure resolving the object
617         */
618        public List<ObjectClass> getSuperiors()
619        {
620            return superiors;
621        }
622    
623    
624        /**
625         * Gets the superclasses OIDsof this ObjectClass.
626         * 
627         * @return the superclasses OIDs
628         */
629        public List<String> getSuperiorOids()
630        {
631            return superiorOids;
632        }
633    
634    
635        /**
636         * Add some superior ObjectClass OIDs
637         *
638         * @param oids The superior ObjectClass OIDs
639         */
640        public void addSuperiorOids( String... oids )
641        {
642            if ( !isReadOnly )
643            {
644                for ( String oid : oids )
645                {
646                    if ( !superiorOids.contains( oid ) )
647                    {
648                        superiorOids.add( oid );
649                    }
650                }
651            }
652        }
653    
654    
655        /**
656         * Add some superior ObjectClasses
657         *
658         * @param objectClasses The superior ObjectClasses
659         */
660        public void addSuperior( ObjectClass... objectClasses )
661        {
662            if ( !isReadOnly )
663            {
664                for ( ObjectClass objectClass : objectClasses )
665                {
666                    if ( !superiorOids.contains( objectClass.getOid() ) )
667                    {
668                        superiorOids.add( objectClass.getOid() );
669                        superiors.add( objectClass );
670                    }
671                }
672            }
673        }
674    
675    
676        /**
677         * Sets the superior object classes
678         * 
679         * @param superiors the object classes to set
680         */
681        public void setSuperiors( List<ObjectClass> superiors )
682        {
683            if ( !isReadOnly )
684            {
685                this.superiors = superiors;
686    
687                // update the OIDS now
688                superiorOids.clear();
689    
690                for ( ObjectClass oc : superiors )
691                {
692                    superiorOids.add( oc.getOid() );
693                }
694            }
695        }
696    
697    
698        /**
699         * Update the associated SUPERIORS ObjectClasses, even if the SchemaObject is readOnly
700         * 
701         * @param superiors the object classes to set
702         */
703        public void updateSuperiors( List<ObjectClass> superiors )
704        {
705            this.superiors.clear();
706            this.superiors.addAll( superiors );
707    
708            // update the OIDS now
709            superiorOids.clear();
710    
711            for ( ObjectClass oc : superiors )
712            {
713                superiorOids.add( oc.getOid() );
714            }
715        }
716    
717    
718        /**
719         * Sets the superior object class OIDs
720         * 
721         * @param superiorOids the object class OIDs to set
722         */
723        public void setSuperiorOids( List<String> superiorOids )
724        {
725            if ( !isReadOnly )
726            {
727                this.superiorOids = superiorOids;
728            }
729        }
730    
731    
732        /**
733         * Gets the type of this ObjectClass as a type safe enum.
734         * 
735         * @return the ObjectClass type as an enum
736         */
737        public ObjectClassTypeEnum getType()
738        {
739            return objectClassType;
740        }
741    
742    
743        /**
744         * Set the ObjectClass type, one of ABSTRACT, AUXILIARY or STRUCTURAL.
745         * 
746         * @param objectClassType The ObjectClassType value
747         */
748        public void setType( ObjectClassTypeEnum objectClassType )
749        {
750            if ( !isReadOnly )
751            {
752                this.objectClassType = objectClassType;
753            }
754        }
755    
756    
757        /**
758         * Tells if the current ObjectClass is STRUCTURAL
759         * 
760         * @return <code>true</code> if the ObjectClass is STRUCTURAL
761         */
762        public boolean isStructural()
763        {
764            return objectClassType == ObjectClassTypeEnum.STRUCTURAL;
765        }
766    
767    
768        /**
769         * Tells if the current ObjectClass is ABSTRACT
770         * 
771         * @return <code>true</code> if the ObjectClass is ABSTRACT
772         */
773        public boolean isAbstract()
774        {
775            return objectClassType == ObjectClassTypeEnum.ABSTRACT;
776        }
777    
778    
779        /**
780         * Tells if the current ObjectClass is AUXILIARY
781         * 
782         * @return <code>true</code> if the ObjectClass is AUXILIARY
783         */
784        public boolean isAuxiliary()
785        {
786            return objectClassType == ObjectClassTypeEnum.AUXILIARY;
787        }
788    
789    
790        /**
791         * @see Object#toString()
792         */
793        public String toString()
794        {
795            return objectType + " " + DescriptionUtils.getDescription( this );
796        }
797    
798    
799        /**
800         * Copy an ObjectClass
801         */
802        public ObjectClass copy()
803        {
804            ObjectClass copy = new ObjectClass( oid );
805    
806            // Copy the SchemaObject common data
807            copy.copy( this );
808    
809            // Copy the ObjectClass type
810            copy.objectClassType = objectClassType;
811    
812            // Copy the Superiors ObjectClasses OIDs
813            copy.superiorOids = new ArrayList<String>();
814    
815            for ( String oid : superiorOids )
816            {
817                copy.superiorOids.add( oid );
818            }
819    
820            // Copy the Superiors ObjectClasses ( will be empty )
821            copy.superiors = new ArrayList<ObjectClass>();
822    
823            // Copy the MAY AttributeTypes OIDs
824            copy.mayAttributeTypeOids = new ArrayList<String>();
825    
826            for ( String oid : mayAttributeTypeOids )
827            {
828                copy.mayAttributeTypeOids.add( oid );
829            }
830    
831            // Copy the MAY AttributeTypes ( will be empty )
832            copy.mayAttributeTypes = new ArrayList<AttributeType>();
833    
834            // Copy the MUST AttributeTypes OIDs
835            copy.mustAttributeTypeOids = new ArrayList<String>();
836    
837            for ( String oid : mustAttributeTypeOids )
838            {
839                copy.mustAttributeTypeOids.add( oid );
840            }
841    
842            // Copy the MUST AttributeTypes ( will be empty )
843            copy.mustAttributeTypes = new ArrayList<AttributeType>();
844    
845            return copy;
846        }
847    
848    
849        /**
850         * @see Object#equals(Object)
851         */
852        public boolean equals( Object o )
853        {
854            if ( !super.equals( o ) )
855            {
856                return false;
857            }
858    
859            if ( !( o instanceof ObjectClass ) )
860            {
861                return false;
862            }
863    
864            ObjectClass that = ( ObjectClass ) o;
865    
866            // The ObjectClassType
867            if ( objectClassType != that.objectClassType )
868            {
869                return false;
870            }
871    
872            // The Superiors OIDs
873            if ( superiorOids.size() != that.superiorOids.size() )
874            {
875                return false;
876            }
877    
878            // One way
879            for ( String oid : superiorOids )
880            {
881                if ( !that.superiorOids.contains( oid ) )
882                {
883                    return false;
884                }
885            }
886    
887            // The other way
888            for ( String oid : that.superiorOids )
889            {
890                if ( !superiorOids.contains( oid ) )
891                {
892                    return false;
893                }
894            }
895    
896            // The Superiors
897            if ( superiors.size() != that.superiors.size() )
898            {
899                return false;
900            }
901    
902            // One way
903            for ( ObjectClass oid : superiors )
904            {
905                if ( !that.superiors.contains( oid ) )
906                {
907                    return false;
908                }
909            }
910    
911            // The other way
912            for ( ObjectClass oid : that.superiors )
913            {
914                if ( !superiors.contains( oid ) )
915                {
916                    return false;
917                }
918            }
919    
920            // The MAY OIDs
921            if ( mayAttributeTypeOids.size() != that.mayAttributeTypeOids.size() )
922            {
923                return false;
924            }
925    
926            // One way
927            for ( String oid : mayAttributeTypeOids )
928            {
929                if ( !that.mayAttributeTypeOids.contains( oid ) )
930                {
931                    return false;
932                }
933            }
934    
935            // The other way
936            for ( String oid : that.mayAttributeTypeOids )
937            {
938                if ( !mayAttributeTypeOids.contains( oid ) )
939                {
940                    return false;
941                }
942            }
943    
944            // The MAY
945            if ( mayAttributeTypes.size() != that.mayAttributeTypes.size() )
946            {
947                return false;
948            }
949    
950            // One way
951            for ( AttributeType oid : mayAttributeTypes )
952            {
953                if ( !that.mayAttributeTypes.contains( oid ) )
954                {
955                    return false;
956                }
957            }
958    
959            // The other way
960            for ( AttributeType oid : that.mayAttributeTypes )
961            {
962                if ( !mayAttributeTypes.contains( oid ) )
963                {
964                    return false;
965                }
966            }
967    
968            // The MUST OIDs
969            if ( mustAttributeTypeOids.size() != that.mustAttributeTypeOids.size() )
970            {
971                return false;
972            }
973    
974            // One way
975            for ( String oid : mustAttributeTypeOids )
976            {
977                if ( !that.mustAttributeTypeOids.contains( oid ) )
978                {
979                    return false;
980                }
981            }
982    
983            // The other way
984            for ( String oid : that.mustAttributeTypeOids )
985            {
986                if ( !mustAttributeTypeOids.contains( oid ) )
987                {
988                    return false;
989                }
990            }
991    
992            // The MUST
993            if ( mustAttributeTypes.size() != that.mustAttributeTypes.size() )
994            {
995                return false;
996            }
997    
998            // One way
999            for ( AttributeType oid : mustAttributeTypes )
1000            {
1001                if ( !that.mustAttributeTypes.contains( oid ) )
1002                {
1003                    return false;
1004                }
1005            }
1006    
1007            // The other way
1008            for ( AttributeType oid : that.mustAttributeTypes )
1009            {
1010                if ( !mustAttributeTypes.contains( oid ) )
1011                {
1012                    return false;
1013                }
1014            }
1015    
1016            return true;
1017        }
1018    
1019    
1020        /**
1021         * {@inheritDoc}
1022         */
1023        public void clear()
1024        {
1025            // Clear the common elements
1026            super.clear();
1027    
1028            // Clear the references
1029            mayAttributeTypes.clear();
1030            mayAttributeTypeOids.clear();
1031            mustAttributeTypes.clear();
1032            mustAttributeTypeOids.clear();
1033            superiors.clear();
1034            superiorOids.clear();
1035        }
1036    }