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