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