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.Collections;
025    import java.util.List;
026    
027    import org.apache.directory.shared.i18n.I18n;
028    import org.apache.directory.shared.ldap.exception.LdapException;
029    
030    import org.apache.directory.shared.ldap.schema.registries.AttributeTypeRegistry;
031    import org.apache.directory.shared.ldap.schema.registries.Registries;
032    
033    
034    /**
035     * A nameForm description. NameForms define the relationship between a
036     * STRUCTURAL objectClass definition and the attributeTypes allowed to be used
037     * for the naming of an Entry of that objectClass: it defines which attributes
038     * can be used for the RDN.
039     * <p>
040     * According to ldapbis [MODELS]:
041     * </p>
042     * 
043     * <pre>
044     *  4.1.7.2. Name Forms
045     *  
046     *   A name form &quot;specifies a permissible RDN for entries of a particular
047     *   structural object class.  A name form identifies a named object
048     *   class and one or more attribute types to be used for naming (i.e.
049     *   for the RDN).  Name forms are primitive pieces of specification
050     *   used in the definition of DIT structure rules&quot; [X.501].
051     * 
052     *   Each name form indicates the structural object class to be named,
053     *   a set of required attribute types, and a set of allowed attributes
054     *   types.  A particular attribute type cannot be listed in both sets.
055     * 
056     *   Entries governed by the form must be named using a value from each
057     *   required attribute type and zero or more values from the allowed
058     *   attribute types.
059     * 
060     *   Each name form is identified by an object identifier (OID) and,
061     *   optionally, one or more short names (descriptors).
062     * 
063     *   Name form descriptions are written according to the ABNF:
064     * 
065     *     NameFormDescription = LPAREN WSP
066     *         numericoid                ; object identifier
067     *         [ SP &quot;NAME&quot; SP qdescrs ]  ; short names (descriptors)
068     *         [ SP &quot;DESC&quot; SP qdstring ] ;String description
069     *         [ SP &quot;OBSOLETE&quot; ]         ; not active
070     *         SP &quot;OC&quot; SP oid            ; structural object class
071     *         SP &quot;MUST&quot; SP oids         ; attribute types
072     *         [ SP &quot;MAY&quot; SP oids ]      ; attribute types
073     *         extensions WSP RPAREN     ; extensions
074     * 
075     *   where:
076     * 
077     *     [numericoid] is object identifier which identifies this name form;
078     *     NAME [qdescrs] are short names (descriptors) identifying this name
079     *         form;
080     *     DESC [qdstring] is a short descriptive string;
081     *     OBSOLETE indicates this name form is not active;
082     *     OC identifies the structural object class this rule applies to,
083     *     MUST and MAY specify the sets of required and allowed, respectively,
084     *         naming attributes for this name form; and
085     *     [extensions] describe extensions.
086     * 
087     *   All attribute types in the required (&quot;MUST&quot;) and allowed (&quot;MAY&quot;) lists
088     *   shall be different.
089     * </pre>
090     * 
091     * @see <a href="http://www.faqs.org/rfcs/rfc225String2.html">RFC2252 Section 6.22</a>
092     * @see <a
093     *      href="http://www.ietf.org/internet-drafts/draft-ietf-ldapbis-models-11.txt">ldapbis
094     *      [MODELS]</a>
095     * @see DescriptionUtils#getDescription(NameForm)
096     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
097     * @version $Rev: 928015 $
098     */
099    public class NameForm extends AbstractSchemaObject
100    {
101        /** The serialVersionUID */
102        private static final long serialVersionUID = 1L;
103    
104        /** The structural object class OID this rule applies to */
105        private String structuralObjectClassOid;
106    
107        /** The structural object class this rule applies to */
108        private ObjectClass structuralObjectClass;
109    
110        /** The set of required attribute OIDs for this name form */
111        private List<String> mustAttributeTypeOids;
112    
113        /** The set of required AttributeTypes for this name form */
114        private List<AttributeType> mustAttributeTypes;
115    
116        /** The set of allowed attribute OIDs for this name form */
117        private List<String> mayAttributeTypeOids;
118    
119        /** The set of allowed AttributeTypes for this name form */
120        private List<AttributeType> mayAttributeTypes;
121    
122    
123        /**
124         * Creates a new instance of MatchingRule.
125         *
126         * @param oid The MatchingRule OID
127         * @param registries The Registries reference
128         */
129        public NameForm( String oid )
130        {
131            super( SchemaObjectType.NAME_FORM, oid );
132    
133            mustAttributeTypeOids = new ArrayList<String>();
134            mayAttributeTypeOids = new ArrayList<String>();
135    
136            mustAttributeTypes = new ArrayList<AttributeType>();
137            mayAttributeTypes = new ArrayList<AttributeType>();
138        }
139    
140    
141        /**
142         * Inject the NameForm into the registries, updating the references to
143         * other SchemaObject
144         *
145         * @param registries The Registries
146         */
147        public void addToRegistries( Registries registries ) throws LdapException
148        {
149            if ( registries != null )
150            {
151                AttributeTypeRegistry atRegistry = registries.getAttributeTypeRegistry();
152    
153                structuralObjectClass = registries.getObjectClassRegistry().lookup( structuralObjectClassOid );
154    
155                if ( mayAttributeTypeOids != null )
156                {
157                    mayAttributeTypes = new ArrayList<AttributeType>( mayAttributeTypeOids.size() );
158    
159                    for ( String oid : mayAttributeTypeOids )
160                    {
161                        mayAttributeTypes.add( atRegistry.lookup( oid ) );
162                    }
163                }
164    
165                if ( mustAttributeTypeOids != null )
166                {
167                    mustAttributeTypes = new ArrayList<AttributeType>( mustAttributeTypeOids.size() );
168    
169                    for ( String oid : mustAttributeTypeOids )
170                    {
171                        mustAttributeTypes.add( atRegistry.lookup( oid ) );
172                    }
173                }
174            }
175        }
176    
177    
178        /**
179         * Gets the STRUCTURAL ObjectClass this name form specifies naming
180         * attributes for.
181         * 
182         * @return the ObjectClass's oid this NameForm is for
183         */
184        public String getStructuralObjectClassOid()
185        {
186            return structuralObjectClassOid;
187        }
188    
189    
190        /**
191         * Gets the STRUCTURAL ObjectClass this name form specifies naming
192         * attributes for.
193         * 
194         * @return the ObjectClass this NameForm is for
195         * @throws LdapException If the structuralObjectClass is invalid
196         */
197        public ObjectClass getStructuralObjectClass()
198        {
199            return structuralObjectClass;
200        }
201    
202    
203        /**
204         * Sets the structural object class this rule applies to
205         * 
206         * @param structuralObjectClass the structural object class to set
207         */
208        public void setStructuralObjectClassOid( String structuralObjectClassOid )
209        {
210            if ( locked )
211            {
212                throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
213            }
214            
215            if ( !isReadOnly )
216            {
217                this.structuralObjectClassOid = structuralObjectClassOid;
218            }
219        }
220    
221    
222        /**
223         * Sets the structural object class this rule applies to
224         * 
225         * @param structuralObjectClass the structural object class to set
226         */
227        public void setStructuralObjectClass( ObjectClass structuralObjectClass )
228        {
229            if ( locked )
230            {
231                throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
232            }
233            
234            if ( !isReadOnly )
235            {
236                this.structuralObjectClass = structuralObjectClass;
237                this.structuralObjectClassOid = structuralObjectClass.getOid();
238            }
239        }
240    
241    
242        /**
243         * Gets all the AttributeTypes OIDs of the attributes this NameForm specifies as
244         * having to be used in the given objectClass for naming: as part of the
245         * Rdn.
246         * 
247         * @return the AttributeTypes OIDs of the must use attributes
248         * @throws LdapException if there is a failure resolving one AttributeTyoe
249         */
250        public List<String> getMustAttributeTypeOids()
251        {
252            return Collections.unmodifiableList( mustAttributeTypeOids );
253        }
254    
255    
256        /**
257         * Gets all the AttributeTypes of the attributes this NameForm specifies as
258         * having to be used in the given objectClass for naming: as part of the
259         * Rdn.
260         * 
261         * @return the AttributeTypes of the must use attributes
262         */
263        public List<AttributeType> getMustAttributeTypes()
264        {
265            return Collections.unmodifiableList( mustAttributeTypes );
266        }
267    
268    
269        /**
270         * Sets the list of required AttributeTypes OIDs
271         *
272         * @param mustAttributeTypeOids the list of required AttributeTypes OIDs
273         */
274        public void setMustAttributeTypeOids( List<String> mustAttributeTypeOids )
275        {
276            if ( locked )
277            {
278                throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
279            }
280            
281            if ( !isReadOnly )
282            {
283                this.mustAttributeTypeOids = mustAttributeTypeOids;
284            }
285        }
286    
287    
288        /**
289         * Sets the list of required AttributeTypes
290         *
291         * @param mayAttributeTypes the list of required AttributeTypes
292         */
293        public void setMustAttributeTypes( List<AttributeType> mustAttributeTypes )
294        {
295            if ( locked )
296            {
297                throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
298            }
299            
300            if ( !isReadOnly )
301            {
302                this.mustAttributeTypes = mustAttributeTypes;
303    
304                // update the OIDS now
305                mustAttributeTypeOids.clear();
306    
307                for ( AttributeType may : mustAttributeTypes )
308                {
309                    mustAttributeTypeOids.add( may.getOid() );
310                }
311            }
312        }
313    
314    
315        /**
316         * Add a required AttributeType OID
317         *
318         * @param oid The attributeType OID
319         */
320        public void addMustAttributeTypeOids( String oid )
321        {
322            if ( locked )
323            {
324                throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
325            }
326            
327            if ( !isReadOnly )
328            {
329                mustAttributeTypeOids.add( oid );
330            }
331        }
332    
333    
334        /**
335         * Add a required AttributeType
336         *
337         * @param attributeType The attributeType
338         */
339        public void addMustAttributeTypes( AttributeType attributeType )
340        {
341            if ( locked )
342            {
343                throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
344            }
345            
346            if ( !isReadOnly )
347            {
348                if ( !mustAttributeTypeOids.contains( attributeType.getOid() ) )
349                {
350                    mustAttributeTypes.add( attributeType );
351                    mustAttributeTypeOids.add( attributeType.getOid() );
352                }
353            }
354        }
355    
356    
357        /**
358         * Gets all the AttributeTypes OIDs of the attribute this NameForm specifies as
359         * being usable without requirement in the given objectClass for naming: as
360         * part of the Rdn.
361         * 
362         * @return the AttributeTypes OIDs of the may use attributes
363         * @throws LdapException if there is a failure resolving one AttributeTyoe
364         */
365        public List<String> getMayAttributeTypeOids()
366        {
367            return Collections.unmodifiableList( mayAttributeTypeOids );
368        }
369    
370    
371        /**
372         * Gets all the AttributeTypes of the attribute this NameForm specifies as
373         * being useable without requirement in the given objectClass for naming: as
374         * part of the Rdn.
375         * 
376         * @return the AttributeTypes of the may use attributes
377         */
378        public List<AttributeType> getMayAttributeTypes()
379        {
380            return Collections.unmodifiableList( mayAttributeTypes );
381        }
382    
383    
384        /**
385         * Sets the list of allowed AttributeTypes
386         *
387         * @param mayAttributeTypeOids the list of allowed AttributeTypes
388         */
389        public void setMayAttributeTypeOids( List<String> mayAttributeTypeOids )
390        {
391            if ( locked )
392            {
393                throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
394            }
395            
396            if ( !isReadOnly )
397            {
398                this.mayAttributeTypeOids = mayAttributeTypeOids;
399            }
400        }
401    
402    
403        /**
404         * Sets the list of allowed AttributeTypes
405         *
406         * @param mayAttributeTypes the list of allowed AttributeTypes
407         */
408        public void setMayAttributeTypes( List<AttributeType> mayAttributeTypes )
409        {
410            if ( locked )
411            {
412                throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
413            }
414            
415            if ( !isReadOnly )
416            {
417                this.mayAttributeTypes = mayAttributeTypes;
418    
419                // update the OIDS now
420                mayAttributeTypeOids.clear();
421    
422                for ( AttributeType may : mayAttributeTypes )
423                {
424                    mayAttributeTypeOids.add( may.getOid() );
425                }
426            }
427        }
428    
429    
430        /**
431         * Add an allowed AttributeType
432         *
433         * @param oid The attributeType oid
434         */
435        public void addMayAttributeTypeOids( String oid )
436        {
437            if ( locked )
438            {
439                throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
440            }
441            
442            if ( !isReadOnly )
443            {
444                mayAttributeTypeOids.add( oid );
445            }
446        }
447    
448    
449        /**
450         * Add an allowed AttributeType
451         *
452         * @param attributeType The attributeType
453         */
454        public void addMayAttributeTypes( AttributeType attributeType )
455        {
456            if ( locked )
457            {
458                throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
459            }
460            
461            if ( !isReadOnly )
462            {
463                if ( !mayAttributeTypeOids.contains( attributeType.getOid() ) )
464                {
465                    mayAttributeTypes.add( attributeType );
466                    mayAttributeTypeOids.add( attributeType.getOid() );
467                }
468            }
469        }
470    
471    
472        /**
473         * @see Object#toString()
474         */
475        public String toString()
476        {
477            return objectType + " " + DescriptionUtils.getDescription( this );
478        }
479    
480    
481        /**
482         * Copy a NameForm
483         */
484        public NameForm copy()
485        {
486            NameForm copy = new NameForm( oid );
487    
488            // Copy the SchemaObject common data
489            copy.copy( this );
490    
491            // Copy the MAY AttributeTypes OIDs
492            copy.mayAttributeTypeOids = new ArrayList<String>();
493    
494            for ( String oid : mayAttributeTypeOids )
495            {
496                copy.mayAttributeTypeOids.add( oid );
497            }
498    
499            // Copy the MAY AttributeTypes (will be empty)
500            copy.mayAttributeTypes = new ArrayList<AttributeType>();
501    
502            // Copy the MUST AttributeTypes OIDs
503            copy.mustAttributeTypeOids = new ArrayList<String>();
504    
505            for ( String oid : mustAttributeTypeOids )
506            {
507                copy.mustAttributeTypeOids.add( oid );
508            }
509    
510            // Copy the MUST AttributeTypes ( will be empty )
511            copy.mustAttributeTypes = new ArrayList<AttributeType>();
512    
513            // Copy the Structural ObjectClass OID
514            copy.structuralObjectClassOid = structuralObjectClassOid;
515    
516            // All the references to other Registries object are set to null.
517            copy.structuralObjectClass = null;
518    
519            return copy;
520        }
521    
522    
523        /**
524         * @see Object#equals(Object)
525         */
526        public boolean equals( Object o )
527        {
528            if ( !super.equals( o ) )
529            {
530                return false;
531            }
532    
533            if ( !( o instanceof NameForm ) )
534            {
535                return false;
536            }
537    
538            NameForm that = ( NameForm ) o;
539    
540            // TODO : complete the checks
541            return true;
542        }
543    
544    
545        /**
546         * {@inheritDoc}
547         */
548        public void clear()
549        {
550            // Clear the common elements
551            super.clear();
552    
553            // Clear the references
554            mayAttributeTypes.clear();
555            mayAttributeTypeOids.clear();
556            mustAttributeTypes.clear();
557            mustAttributeTypeOids.clear();
558            structuralObjectClass = null;
559        }
560    }