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 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
112 */
113public class DitContentRule extends AbstractSchemaObject
114{
115    /** The mandatory serialVersionUID */
116    public static final long serialVersionUID = 1L;
117
118    /** The list of Auxiliary ObjectClass OIDs entries may belong to */
119    private List<String> auxObjectClassOids;
120
121    /** The list of Auxiliary ObjectClass entries may belong to */
122    private List<ObjectClass> auxObjectClasses;
123
124    /** The list of allowed AttributeType OIDs */
125    private List<String> mayAttributeTypeOids;
126
127    /** The list of allowed AttributeTypes */
128    private List<AttributeType> mayAttributeTypes;
129
130    /** The list of required AttributeType OIDs */
131    private List<String> mustAttributeTypeOids;
132
133    /** The list of required AttributeTypes */
134    private List<AttributeType> mustAttributeTypes;
135
136    /** The list of precluded AttributeType OIDs */
137    private List<String> notAttributeTypeOids;
138
139    /** The list of precluded AttributeTypes */
140    private List<AttributeType> notAttributeTypes;
141
142
143    /**
144     * Creates a DitContentRule object using a unique OID.
145     * 
146     * @param oid the OID for this DitContentRule
147     */
148    public DitContentRule( String oid )
149    {
150        super( SchemaObjectType.DIT_CONTENT_RULE, oid );
151
152        mayAttributeTypeOids = new ArrayList<>();
153        mustAttributeTypeOids = new ArrayList<>();
154        notAttributeTypeOids = new ArrayList<>();
155        auxObjectClassOids = new ArrayList<>();
156
157        mayAttributeTypes = new ArrayList<>();
158        mustAttributeTypes = new ArrayList<>();
159        notAttributeTypes = new ArrayList<>();
160        auxObjectClasses = new ArrayList<>();
161    }
162
163
164    /**
165     * @return the auxObjectClassOids
166     */
167    public List<String> getAuxObjectClassOids()
168    {
169        return auxObjectClassOids;
170    }
171
172
173    /**
174     * Add an Auxiliary ObjectClass Oid
175     *
176     * @param oid The ObjectClass oid
177     */
178    public void addAuxObjectClassOidOids( String oid )
179    {
180        if ( locked )
181        {
182            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
183        }
184
185        if ( !isReadOnly )
186        {
187            auxObjectClassOids.add( oid );
188        }
189    }
190
191
192    /**
193     * Add an Auxiliary ObjectClass
194     *
195     * @param objectClass The ObjectClass
196     */
197    public void addAuxObjectClasses( ObjectClass objectClass )
198    {
199        if ( locked )
200        {
201            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
202        }
203
204        if ( !isReadOnly && !auxObjectClassOids.contains( objectClass.getOid() ) )
205        {
206            auxObjectClasses.add( objectClass );
207            auxObjectClassOids.add( objectClass.getOid() );
208        }
209    }
210
211
212    /**
213     * @param auxObjectClassOids the auxObjectClassOids to set
214     */
215    public void setAuxObjectClassOids( List<String> auxObjectClassOids )
216    {
217        if ( locked )
218        {
219            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
220        }
221
222        if ( !isReadOnly )
223        {
224            this.auxObjectClassOids = auxObjectClassOids;
225        }
226    }
227
228
229    /**
230     * @param auxObjectClasses the auxObjectClasses to set
231     */
232    public void setAuxObjectClasses( List<ObjectClass> auxObjectClasses )
233    {
234        if ( locked )
235        {
236            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
237        }
238
239        if ( !isReadOnly )
240        {
241            this.auxObjectClasses = auxObjectClasses;
242
243            // update the OIDS now
244            auxObjectClassOids.clear();
245
246            for ( ObjectClass oc : auxObjectClasses )
247            {
248                auxObjectClassOids.add( oc.getOid() );
249            }
250        }
251    }
252
253
254    /**
255     * @return the auxObjectClasses
256     */
257    public List<ObjectClass> getAuxObjectClasses()
258    {
259        return auxObjectClasses;
260    }
261
262
263    /**
264     * @return the mayAttributeTypeOids
265     */
266    public List<String> getMayAttributeTypeOids()
267    {
268        return mayAttributeTypeOids;
269    }
270
271
272    /**
273     * Add an allowed AttributeType
274     *
275     * @param oid The attributeType oid
276     */
277    public void addMayAttributeTypeOids( String oid )
278    {
279        if ( locked )
280        {
281            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
282        }
283
284        if ( !isReadOnly )
285        {
286            mayAttributeTypeOids.add( oid );
287        }
288    }
289
290
291    /**
292     * Add an allowed AttributeType
293     *
294     * @param attributeType The attributeType
295     */
296    public void addMayAttributeTypes( AttributeType attributeType )
297    {
298        if ( locked )
299        {
300            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
301        }
302
303        if ( !isReadOnly && !mayAttributeTypeOids.contains( attributeType.getOid() ) )
304        {
305            mayAttributeTypes.add( attributeType );
306            mayAttributeTypeOids.add( attributeType.getOid() );
307        }
308    }
309
310
311    /**
312     * @param mayAttributeTypeOids the mayAttributeTypeOids to set
313     */
314    public void setMayAttributeTypeOids( List<String> mayAttributeTypeOids )
315    {
316        if ( locked )
317        {
318            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
319        }
320
321        if ( !isReadOnly )
322        {
323            this.mayAttributeTypeOids = mayAttributeTypeOids;
324        }
325    }
326
327
328    /**
329     * Sets the list of allowed AttributeTypes
330     *
331     * @param mayAttributeTypes the list of allowed AttributeTypes
332     */
333    public void setMayAttributeTypes( List<AttributeType> mayAttributeTypes )
334    {
335        if ( locked )
336        {
337            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
338        }
339
340        if ( !isReadOnly )
341        {
342            this.mayAttributeTypes = mayAttributeTypes;
343
344            // update the OIDS now
345            mayAttributeTypeOids.clear();
346
347            for ( AttributeType may : mayAttributeTypes )
348            {
349                mayAttributeTypeOids.add( may.getOid() );
350            }
351        }
352    }
353
354
355    /**
356     * @return the mayAttributeTypes
357     */
358    public List<AttributeType> getMayAttributeTypes()
359    {
360        return mayAttributeTypes;
361    }
362
363
364    /**
365     * @return the mustAttributeTypeOids
366     */
367    public List<String> getMustAttributeTypeOids()
368    {
369        return mustAttributeTypeOids;
370    }
371
372
373    /**
374     * Add a required AttributeType OID
375     *
376     * @param oid The attributeType OID
377     */
378    public void addMustAttributeTypeOids( String oid )
379    {
380        if ( locked )
381        {
382            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
383        }
384
385        if ( !isReadOnly )
386        {
387            mustAttributeTypeOids.add( oid );
388        }
389    }
390
391
392    /**
393     * Add a required AttributeType
394     *
395     * @param attributeType The attributeType
396     */
397    public void addMustAttributeTypes( AttributeType attributeType )
398    {
399        if ( locked )
400        {
401            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
402        }
403
404        if ( !isReadOnly && !mustAttributeTypeOids.contains( attributeType.getOid() ) )
405        {
406            mustAttributeTypes.add( attributeType );
407            mustAttributeTypeOids.add( attributeType.getOid() );
408        }
409    }
410
411
412    /**
413     * @param mustAttributeTypeOids the mustAttributeTypeOids to set
414     */
415    public void setMustAttributeTypeOids( List<String> mustAttributeTypeOids )
416    {
417        if ( locked )
418        {
419            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
420        }
421
422        if ( !isReadOnly )
423        {
424            this.mustAttributeTypeOids = mustAttributeTypeOids;
425        }
426    }
427
428
429    /**
430     * Sets the list of required AttributeTypes
431     *
432     * @param mustAttributeTypes the list of required AttributeTypes
433     */
434    public void setMustAttributeTypes( List<AttributeType> mustAttributeTypes )
435    {
436        if ( locked )
437        {
438            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
439        }
440
441        if ( !isReadOnly )
442        {
443            this.mustAttributeTypes = mustAttributeTypes;
444
445            // update the OIDS now
446            mustAttributeTypeOids.clear();
447
448            for ( AttributeType may : mustAttributeTypes )
449            {
450                mustAttributeTypeOids.add( may.getOid() );
451            }
452        }
453    }
454
455
456    /**
457     * @return the mustAttributeTypes
458     */
459    public List<AttributeType> getMustAttributeTypes()
460    {
461        return mustAttributeTypes;
462    }
463
464
465    /**
466     * @return the notAttributeTypeOids
467     */
468    public List<String> getNotAttributeTypeOids()
469    {
470        return notAttributeTypeOids;
471    }
472
473
474    /**
475     * Add a precluded AttributeType
476     *
477     * @param oid The attributeType oid
478     */
479    public void addNotAttributeTypeOids( String oid )
480    {
481        if ( locked )
482        {
483            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
484        }
485
486        if ( !isReadOnly )
487        {
488            notAttributeTypeOids.add( oid );
489        }
490    }
491
492
493    /**
494     * Add a precluded AttributeType
495     *
496     * @param attributeType The attributeType
497     */
498    public void addNotAttributeTypes( AttributeType attributeType )
499    {
500        if ( locked )
501        {
502            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
503        }
504
505        if ( !isReadOnly && !notAttributeTypeOids.contains( attributeType.getOid() ) )
506        {
507            notAttributeTypes.add( attributeType );
508            notAttributeTypeOids.add( attributeType.getOid() );
509        }
510    }
511
512
513    /**
514     * @param notAttributeTypeOids the notAttributeTypeOids to set
515     */
516    public void setNotAttributeTypeOids( List<String> notAttributeTypeOids )
517    {
518        if ( locked )
519        {
520            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
521        }
522
523        if ( !isReadOnly )
524        {
525            this.notAttributeTypeOids = notAttributeTypeOids;
526        }
527    }
528
529
530    /**
531     * Sets the list of precluded AttributeTypes
532     *
533     * @param notAttributeTypes the list of precluded AttributeTypes
534     */
535    public void setNotAttributeTypes( List<AttributeType> notAttributeTypes )
536    {
537        if ( locked )
538        {
539            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
540        }
541
542        if ( !isReadOnly )
543        {
544            this.notAttributeTypes = notAttributeTypes;
545
546            // update the OIDS now
547            notAttributeTypeOids.clear();
548
549            for ( AttributeType not : notAttributeTypes )
550            {
551                notAttributeTypeOids.add( not.getOid() );
552            }
553        }
554    }
555
556
557    /**
558     * @return the notAttributeTypes
559     */
560    public List<AttributeType> getNotAttributeTypes()
561    {
562        return notAttributeTypes;
563    }
564
565
566    /**
567     * @see Object#toString()
568     */
569    @Override
570    public String toString()
571    {
572        return SchemaObjectRenderer.OPEN_LDAP_SCHEMA_RENDERER.render( this );
573    }
574
575
576    /**
577     * Copy a DitContentRule
578     */
579    @Override
580    public DitContentRule copy()
581    {
582        DitContentRule copy = new DitContentRule( oid );
583
584        // Copy the SchemaObject common data
585        copy.copy( this );
586
587        // copy the AUX ObjectClasses OIDs
588        copy.auxObjectClassOids = new ArrayList<>();
589
590        for ( String oid : auxObjectClassOids )
591        {
592            copy.auxObjectClassOids.add( oid );
593        }
594
595        // copy the AUX ObjectClasses ( will be empty )
596        copy.auxObjectClasses = new ArrayList<>();
597
598        // Clone the MAY AttributeTypes OIDs
599        copy.mayAttributeTypeOids = new ArrayList<>();
600
601        for ( String oid : mayAttributeTypeOids )
602        {
603            copy.mayAttributeTypeOids.add( oid );
604        }
605
606        // Clone the MAY AttributeTypes ( will be empty )
607        copy.mayAttributeTypes = new ArrayList<>();
608
609        // Clone the MUST AttributeTypes OIDs
610        copy.mustAttributeTypeOids = new ArrayList<>();
611
612        for ( String oid : mustAttributeTypeOids )
613        {
614            copy.mustAttributeTypeOids.add( oid );
615        }
616
617        // Clone the MUST AttributeTypes ( will be empty )
618        copy.mustAttributeTypes = new ArrayList<>();
619
620        // Clone the NOT AttributeTypes OIDs
621        copy.notAttributeTypeOids = new ArrayList<>();
622
623        for ( String oid : notAttributeTypeOids )
624        {
625            copy.notAttributeTypeOids.add( oid );
626        }
627
628        // Clone the NOT AttributeTypes ( will be empty )
629        copy.notAttributeTypes = new ArrayList<>();
630
631        return copy;
632    }
633
634
635    /**
636     * @see Object#equals(Object)
637     */
638    @Override
639    public boolean equals( Object o )
640    {
641        if ( !super.equals( o ) )
642        {
643            return false;
644        }
645
646        if ( !( o instanceof DitContentRule ) )
647        {
648            return false;
649        }
650
651        @SuppressWarnings("unused")
652        DitContentRule that = ( DitContentRule ) o;
653
654        // TODO : complete the check
655        return true;
656    }
657
658
659    /**
660     * {@inheritDoc}
661     */
662    @Override
663    public void clear()
664    {
665        // Clear the common elements
666        super.clear();
667
668        // Clear the references
669        auxObjectClasses.clear();
670        auxObjectClassOids.clear();
671        mayAttributeTypes.clear();
672        mayAttributeTypeOids.clear();
673        mustAttributeTypes.clear();
674        mustAttributeTypeOids.clear();
675        notAttributeTypes.clear();
676        notAttributeTypeOids.clear();
677    }
678}