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 */
020package org.apache.directory.shared.ldap.model.schema;
021
022
023import java.util.ArrayList;
024import java.util.List;
025
026import org.apache.directory.shared.i18n.I18n;
027import org.apache.directory.shared.ldap.model.exception.LdapException;
028import org.apache.directory.shared.ldap.model.schema.registries.AttributeTypeRegistry;
029import org.apache.directory.shared.ldap.model.schema.registries.ObjectClassRegistry;
030import org.apache.directory.shared.ldap.model.schema.registries.Registries;
031
032
033/**
034 * A ditContentRule specification. ditContentRules identify the content of
035 * entries of a particular structural objectClass. They specify the AUXILIARY
036 * objectClasses and additional attribute types permitted to appear, or excluded
037 * from appearing in entries of the indicated STRUCTURAL objectClass.
038 * <p>
039 * According to ldapbis [MODELS]:
040 * </p>
041 * 
042 * <pre>
043 *  4.1.6. DIT Content Rules
044 *  
045 *    A DIT content rule is a &quot;rule governing the content of entries of a
046 *    particular structural object class&quot; [X.501].
047 *  
048 *    For DIT entries of a particular structural object class, a DIT content
049 *    rule specifies which auxiliary object classes the entries are allowed
050 *    to belong to and which additional attributes (by type) are required,
051 *    allowed or not allowed to appear in the entries.
052 *  
053 *    The list of precluded attributes cannot include any attribute listed
054 *    as mandatory in rule, the structural object class, or any of the
055 *    allowed auxiliary object classes.
056 *  
057 *    Each content rule is identified by the object identifier, as well as
058 *    any short names (descriptors), of the structural object class it
059 *    applies to.
060 *  
061 *    An entry may only belong to auxiliary object classes listed in the
062 *    governing content rule.
063 *  
064 *    An entry must contain all attributes required by the object classes
065 *    the entry belongs to as well as all attributed required by the
066 *    governing content rule.
067 *  
068 *    An entry may contain any non-precluded attributes allowed by the
069 *    object classes the entry belongs to as well as all attributes allowed
070 *    by the governing content rule.
071 *  
072 *    An entry cannot include any attribute precluded by the governing
073 *    content rule.
074 *  
075 *    An entry is governed by (if present and active in the subschema) the
076 *    DIT content rule which applies to the structural object class of the
077 *    entry (see Section 2.4.2).  If no active rule is present for the
078 *    entry's structural object class, the entry's content is governed by
079 *    the structural object class (and possibly other aspects of user and
080 *    system schema).
081 * 
082 *    DIT content rule descriptions are written according to the ABNF:
083 * 
084 *      DITContentRuleDescription = LPAREN WSP
085 *          numericoid                ; object identifier
086 *          [ SP &quot;NAME&quot; SP qdescrs ]  ; short names (descriptors)
087 *          [ SP &quot;DESC&quot; SP qdstring ] ; description
088 *          [ SP &quot;OBSOLETE&quot; ]         ; not active
089 *          [ SP &quot;AUX&quot; SP oids ]      ; auxiliary object classes
090 *          [ SP &quot;MUST&quot; SP oids ]     ; attribute types
091 *          [ SP &quot;MAY&quot; SP oids ]      ; attribute types
092 *          [ SP &quot;NOT&quot; SP oids ]      ; attribute types
093 *          extensions WSP RPAREN     ; extensions
094 * 
095 *    where:
096 * 
097 *      [numericoid] is the object identifier of the structural object class
098 *          associated with this DIT content rule;
099 *      NAME [qdescrs] are short names (descriptors) identifying this DIT
100 *          content rule;
101 *      DESC [qdstring] is a short descriptive string;
102 *      OBSOLETE indicates this DIT content rule use is not active;
103 *      AUX specifies a list of auxiliary object classes which entries
104 *          subject to this DIT content rule may belong to;
105 *      MUST, MAY, and NOT specify lists of attribute types which are
106 *          required, allowed, or precluded, respectively, from appearing in
107 *          entries subject to this DIT content rule; and
108 *      [extensions] describe extensions.
109 * </pre>
110 * 
111 * @see <a href="http://www.faqs.org/rfcs/rfc2252.html">RFC 2252 Section 5.4.3</a>
112 * @see <a
113 *      href="http://www.ietf.org/internet-drafts/draft-ietf-ldapbis-models-11.txt">ldapbis
114 *      [MODELS]</a>
115 * @see DescriptionUtils#getDescription(DITContentRule)
116 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
117 */
118// super.hashCode is final
119@SuppressWarnings("PMD.OverrideBothEqualsAndHashcode")
120public class DITContentRule extends AbstractSchemaObject
121{
122    /** The list of Auxiliary ObjectClass OIDs entries may belong to */
123    private List<String> auxObjectClassOids;
124
125    /** The list of Auxiliary ObjectClass entries may belong to */
126    private List<ObjectClass> auxObjectClasses;
127
128    /** The list of allowed AttributeType OIDs */
129    private List<String> mayAttributeTypeOids;
130
131    /** The list of allowed AttributeTypes */
132    private List<AttributeType> mayAttributeTypes;
133
134    /** The list of required AttributeType OIDs */
135    private List<String> mustAttributeTypeOids;
136
137    /** The list of required AttributeTypes */
138    private List<AttributeType> mustAttributeTypes;
139
140    /** The list of precluded AttributeType OIDs */
141    private List<String> notAttributeTypeOids;
142
143    /** The list of precluded AttributeTypes */
144    private List<AttributeType> notAttributeTypes;
145
146
147    /**
148     * Creates a DITContentRule object using a unique OID.
149     * 
150     * @param oid the OID for this DITContentRule
151     */
152    public DITContentRule( String oid )
153    {
154        super( SchemaObjectType.DIT_CONTENT_RULE, oid );
155
156        mayAttributeTypeOids = new ArrayList<String>();
157        mustAttributeTypeOids = new ArrayList<String>();
158        notAttributeTypeOids = new ArrayList<String>();
159        auxObjectClassOids = new ArrayList<String>();
160
161        mayAttributeTypes = new ArrayList<AttributeType>();
162        mustAttributeTypes = new ArrayList<AttributeType>();
163        notAttributeTypes = new ArrayList<AttributeType>();
164        auxObjectClasses = new ArrayList<ObjectClass>();
165    }
166
167
168    /**
169     * @return the auxObjectClassOids
170     */
171    public List<String> getAuxObjectClassOids()
172    {
173        return auxObjectClassOids;
174    }
175
176
177    /**
178     * Add an Auxiliary ObjectClass Oid
179     *
180     * @param oid The ObjectClass oid
181     */
182    public void addAuxObjectClassOidOids( String oid )
183    {
184        if ( locked )
185        {
186            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
187        }
188        
189        if ( !isReadOnly )
190        {
191            auxObjectClassOids.add( oid );
192        }
193    }
194
195
196    /**
197     * Add an Auxiliary ObjectClass
198     *
199     * @param objectClass The ObjectClass
200     */
201    public void addAuxObjectClasses( ObjectClass objectClass )
202    {
203        if ( locked )
204        {
205            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
206        }
207        
208        if ( !isReadOnly && !auxObjectClassOids.contains( objectClass.getOid() ) )
209        {
210            auxObjectClasses.add( objectClass );
211            auxObjectClassOids.add( objectClass.getOid() );
212        }
213    }
214
215
216    /**
217     * @param auxObjectClassOids the auxObjectClassOids to set
218     */
219    public void setAuxObjectClassOids( List<String> auxObjectClassOids )
220    {
221        if ( locked )
222        {
223            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
224        }
225        
226        if ( !isReadOnly )
227        {
228            this.auxObjectClassOids = auxObjectClassOids;
229        }
230    }
231
232
233    /**
234     * @param auxObjectClasses the auxObjectClasses to set
235     */
236    public void setAuxObjectClasses( List<ObjectClass> auxObjectClasses )
237    {
238        if ( locked )
239        {
240            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
241        }
242        
243        if ( !isReadOnly )
244        {
245            this.auxObjectClasses = auxObjectClasses;
246
247            // update the OIDS now
248            auxObjectClassOids.clear();
249
250            for ( ObjectClass oc : auxObjectClasses )
251            {
252                auxObjectClassOids.add( oc.getOid() );
253            }
254        }
255    }
256
257
258    /**
259     * @return the auxObjectClasses
260     */
261    public List<ObjectClass> getAuxObjectClasses()
262    {
263        return auxObjectClasses;
264    }
265
266
267    /**
268     * @return the mayAttributeTypeOids
269     */
270    public List<String> getMayAttributeTypeOids()
271    {
272        return mayAttributeTypeOids;
273    }
274
275
276    /**
277     * Add an allowed AttributeType
278     *
279     * @param oid The attributeType oid
280     */
281    public void addMayAttributeTypeOids( String oid )
282    {
283        if ( locked )
284        {
285            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
286        }
287        
288        if ( !isReadOnly )
289        {
290            mayAttributeTypeOids.add( oid );
291        }
292    }
293
294
295    /**
296     * Add an allowed AttributeType
297     *
298     * @param attributeType The attributeType
299     */
300    public void addMayAttributeTypes( AttributeType attributeType )
301    {
302        if ( locked )
303        {
304            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
305        }
306        
307        if ( !isReadOnly && !mayAttributeTypeOids.contains( attributeType.getOid() ) )
308        {
309            mayAttributeTypes.add( attributeType );
310            mayAttributeTypeOids.add( attributeType.getOid() );
311        }
312    }
313
314
315    /**
316     * @param mayAttributeTypeOids the mayAttributeTypeOids to set
317     */
318    public void setMayAttributeTypeOids( List<String> mayAttributeTypeOids )
319    {
320        if ( locked )
321        {
322            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
323        }
324        
325        if ( !isReadOnly )
326        {
327            this.mayAttributeTypeOids = mayAttributeTypeOids;
328        }
329    }
330
331
332    /**
333     * Sets the list of allowed AttributeTypes
334     *
335     * @param mayAttributeTypes the list of allowed AttributeTypes
336     */
337    public void setMayAttributeTypes( List<AttributeType> mayAttributeTypes )
338    {
339        if ( locked )
340        {
341            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
342        }
343        
344        if ( !isReadOnly )
345        {
346            this.mayAttributeTypes = mayAttributeTypes;
347
348            // update the OIDS now
349            mayAttributeTypeOids.clear();
350
351            for ( AttributeType may : mayAttributeTypes )
352            {
353                mayAttributeTypeOids.add( may.getOid() );
354            }
355        }
356    }
357
358
359    /**
360     * @return the mayAttributeTypes
361     */
362    public List<AttributeType> getMayAttributeTypes()
363    {
364        return mayAttributeTypes;
365    }
366
367
368    /**
369     * @return the mustAttributeTypeOids
370     */
371    public List<String> getMustAttributeTypeOids()
372    {
373        return mustAttributeTypeOids;
374    }
375
376
377    /**
378     * Add a required AttributeType OID
379     *
380     * @param oid The attributeType OID
381     */
382    public void addMustAttributeTypeOids( String oid )
383    {
384        if ( locked )
385        {
386            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
387        }
388        
389        if ( !isReadOnly )
390        {
391            mustAttributeTypeOids.add( oid );
392        }
393    }
394
395
396    /**
397     * Add a required AttributeType
398     *
399     * @param attributeType The attributeType
400     */
401    public void addMustAttributeTypes( AttributeType attributeType )
402    {
403        if ( locked )
404        {
405            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
406        }
407        
408        if ( !isReadOnly && !mustAttributeTypeOids.contains( attributeType.getOid() ) )
409        {
410            mustAttributeTypes.add( attributeType );
411            mustAttributeTypeOids.add( attributeType.getOid() );
412        }
413    }
414
415
416    /**
417     * @param mustAttributeTypeOids the mustAttributeTypeOids to set
418     */
419    public void setMustAttributeTypeOids( List<String> mustAttributeTypeOids )
420    {
421        if ( locked )
422        {
423            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
424        }
425        
426        if ( !isReadOnly )
427        {
428            this.mustAttributeTypeOids = mustAttributeTypeOids;
429        }
430    }
431
432
433    /**
434     * Sets the list of required AttributeTypes
435     *
436     * @param mustAttributeTypes the list of required AttributeTypes
437     */
438    public void setMustAttributeTypes( List<AttributeType> mustAttributeTypes )
439    {
440        if ( locked )
441        {
442            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
443        }
444        
445        if ( !isReadOnly )
446        {
447            this.mustAttributeTypes = mustAttributeTypes;
448
449            // update the OIDS now
450            mustAttributeTypeOids.clear();
451
452            for ( AttributeType may : mustAttributeTypes )
453            {
454                mustAttributeTypeOids.add( may.getOid() );
455            }
456        }
457    }
458
459
460    /**
461     * @return the mustAttributeTypes
462     */
463    public List<AttributeType> getMustAttributeTypes()
464    {
465        return mustAttributeTypes;
466    }
467
468
469    /**
470     * @return the notAttributeTypeOids
471     */
472    public List<String> getNotAttributeTypeOids()
473    {
474        return notAttributeTypeOids;
475    }
476
477
478    /**
479     * Add a precluded AttributeType
480     *
481     * @param oid The attributeType oid
482     */
483    public void addNotAttributeTypeOids( String oid )
484    {
485        if ( locked )
486        {
487            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
488        }
489        
490        if ( !isReadOnly )
491        {
492            notAttributeTypeOids.add( oid );
493        }
494    }
495
496
497    /**
498     * Add a precluded AttributeType
499     *
500     * @param attributeType The attributeType
501     */
502    public void addNotAttributeTypes( AttributeType attributeType )
503    {
504        if ( locked )
505        {
506            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
507        }
508        
509        if ( !isReadOnly && !notAttributeTypeOids.contains( attributeType.getOid() ) )
510        {
511            notAttributeTypes.add( attributeType );
512            notAttributeTypeOids.add( attributeType.getOid() );
513        }
514    }
515
516
517    /**
518     * @param notAttributeTypeOids the notAttributeTypeOids to set
519     */
520    public void setNotAttributeTypeOids( List<String> notAttributeTypeOids )
521    {
522        if ( locked )
523        {
524            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
525        }
526        
527        if ( !isReadOnly )
528        {
529            this.notAttributeTypeOids = notAttributeTypeOids;
530        }
531    }
532
533
534    /**
535     * Sets the list of precluded AttributeTypes
536     *
537     * @param notAttributeTypes the list of precluded AttributeTypes
538     */
539    public void setNotAttributeTypes( List<AttributeType> notAttributeTypes )
540    {
541        if ( locked )
542        {
543            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
544        }
545        
546        if ( !isReadOnly )
547        {
548            this.notAttributeTypes = notAttributeTypes;
549
550            // update the OIDS now
551            notAttributeTypeOids.clear();
552
553            for ( AttributeType not : notAttributeTypes )
554            {
555                notAttributeTypeOids.add( not.getOid() );
556            }
557        }
558    }
559
560
561    /**
562     * @return the notAttributeTypes
563     */
564    public List<AttributeType> getNotAttributeTypes()
565    {
566        return notAttributeTypes;
567    }
568
569
570    /**
571     * Inject the DITContentRule into the registries, updating the references to
572     * other SchemaObject
573     *
574     * @param registries The Registries
575     * @exception If the addition failed
576     */
577    public void addToRegistries( Registries registries ) throws LdapException
578    {
579        if ( registries != null )
580        {
581            AttributeTypeRegistry atRegistry = registries.getAttributeTypeRegistry();
582            ObjectClassRegistry ocRegistry = registries.getObjectClassRegistry();
583
584            if ( mayAttributeTypeOids != null )
585            {
586                mayAttributeTypes = new ArrayList<AttributeType>( mayAttributeTypeOids.size() );
587
588                for ( String oid : mayAttributeTypeOids )
589                {
590                    mayAttributeTypes.add( atRegistry.lookup( oid ) );
591                }
592            }
593
594            if ( mustAttributeTypeOids != null )
595            {
596                mustAttributeTypes = new ArrayList<AttributeType>( mustAttributeTypeOids.size() );
597
598                for ( String oid : mustAttributeTypeOids )
599                {
600                    mustAttributeTypes.add( atRegistry.lookup( oid ) );
601                }
602            }
603
604            if ( notAttributeTypeOids != null )
605            {
606                notAttributeTypes = new ArrayList<AttributeType>( notAttributeTypeOids.size() );
607
608                for ( String oid : notAttributeTypeOids )
609                {
610                    notAttributeTypes.add( atRegistry.lookup( oid ) );
611                }
612            }
613
614            if ( auxObjectClassOids != null )
615            {
616                auxObjectClasses = new ArrayList<ObjectClass>( auxObjectClassOids.size() );
617
618                for ( String oid : auxObjectClassOids )
619                {
620                    auxObjectClasses.add( ocRegistry.lookup( oid ) );
621                }
622            }
623        }
624    }
625
626
627    /**
628     * @see Object#toString()
629     */
630    public String toString()
631    {
632        return objectType + " " + DescriptionUtils.getDescription( this );
633    }
634
635
636    /**
637     * Copy a DITContentRule
638     */
639    public DITContentRule copy()
640    {
641        DITContentRule copy = new DITContentRule( oid );
642
643        // Copy the SchemaObject common data
644        copy.copy( this );
645
646        // copy the AUX ObjectClasses OIDs
647        copy.auxObjectClassOids = new ArrayList<String>();
648
649        for ( String oid : auxObjectClassOids )
650        {
651            copy.auxObjectClassOids.add( oid );
652        }
653
654        // copy the AUX ObjectClasses ( will be empty )
655        copy.auxObjectClasses = new ArrayList<ObjectClass>();
656
657        // Clone the MAY AttributeTypes OIDs
658        copy.mayAttributeTypeOids = new ArrayList<String>();
659
660        for ( String oid : mayAttributeTypeOids )
661        {
662            copy.mayAttributeTypeOids.add( oid );
663        }
664
665        // Clone the MAY AttributeTypes ( will be empty )
666        copy.mayAttributeTypes = new ArrayList<AttributeType>();
667
668        // Clone the MUST AttributeTypes OIDs
669        copy.mustAttributeTypeOids = new ArrayList<String>();
670
671        for ( String oid : mustAttributeTypeOids )
672        {
673            copy.mustAttributeTypeOids.add( oid );
674        }
675
676        // Clone the MUST AttributeTypes ( will be empty )
677        copy.mustAttributeTypes = new ArrayList<AttributeType>();
678
679        // Clone the NOT AttributeTypes OIDs
680        copy.notAttributeTypeOids = new ArrayList<String>();
681
682        for ( String oid : notAttributeTypeOids )
683        {
684            copy.notAttributeTypeOids.add( oid );
685        }
686
687        // Clone the NOT AttributeTypes ( will be empty )
688        copy.notAttributeTypes = new ArrayList<AttributeType>();
689
690        return copy;
691    }
692
693
694    /**
695     * @see Object#equals(Object)
696     */
697    @Override
698    @SuppressWarnings("PMD.UnusedLocalVariable") // Remove me when the TODO is fixed 
699    public boolean equals( Object o )
700    {
701        if ( !super.equals( o ) )
702        {
703            return false;
704        }
705
706        if ( !( o instanceof DITContentRule ) )
707        {
708            return false;
709        }
710
711        @SuppressWarnings("unused")
712        DITContentRule that = ( DITContentRule ) o;
713
714        // TODO : complete the check
715        return true;
716    }
717
718
719    /**
720     * {@inheritDoc}
721     */
722    public void clear()
723    {
724        // Clear the common elements
725        super.clear();
726
727        // Clear the references
728        auxObjectClasses.clear();
729        auxObjectClassOids.clear();
730        mayAttributeTypes.clear();
731        mayAttributeTypeOids.clear();
732        mustAttributeTypes.clear();
733        mustAttributeTypeOids.clear();
734        notAttributeTypes.clear();
735        notAttributeTypeOids.clear();
736    }
737}