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