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 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
092 */
093public class NameForm extends AbstractSchemaObject
094{
095    /** The mandatory serialVersionUID */
096    public static final long serialVersionUID = 1L;
097
098    /** The structural object class OID this rule applies to */
099    private String structuralObjectClassOid;
100
101    /** The structural object class this rule applies to */
102    private ObjectClass structuralObjectClass;
103
104    /** The set of required attribute OIDs for this name form */
105    private List<String> mustAttributeTypeOids;
106
107    /** The set of required AttributeTypes for this name form */
108    private List<AttributeType> mustAttributeTypes;
109
110    /** The set of allowed attribute OIDs for this name form */
111    private List<String> mayAttributeTypeOids;
112
113    /** The set of allowed AttributeTypes for this name form */
114    private List<AttributeType> mayAttributeTypes;
115
116
117    /**
118     * Creates a new instance of MatchingRule.
119     *
120     * @param oid The MatchingRule OID
121     */
122    public NameForm( String oid )
123    {
124        super( SchemaObjectType.NAME_FORM, oid );
125
126        mustAttributeTypeOids = new ArrayList<>();
127        mayAttributeTypeOids = new ArrayList<>();
128
129        mustAttributeTypes = new ArrayList<>();
130        mayAttributeTypes = new ArrayList<>();
131    }
132
133
134    /**
135     * Gets the STRUCTURAL ObjectClass this name form specifies naming
136     * attributes for.
137     * 
138     * @return the ObjectClass's oid this NameForm is for
139     */
140    public String getStructuralObjectClassOid()
141    {
142        return structuralObjectClassOid;
143    }
144
145
146    /**
147     * Gets the STRUCTURAL ObjectClass this name form specifies naming
148     * attributes for.
149     * 
150     * @return the ObjectClass this NameForm is for
151     */
152    public ObjectClass getStructuralObjectClass()
153    {
154        return structuralObjectClass;
155    }
156
157
158    /**
159     * Sets the structural object class this rule applies to
160     * 
161     * @param structuralObjectClassOid the structural object class to set
162     */
163    public void setStructuralObjectClassOid( String structuralObjectClassOid )
164    {
165        if ( locked )
166        {
167            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
168        }
169
170        if ( !isReadOnly )
171        {
172            this.structuralObjectClassOid = structuralObjectClassOid;
173        }
174    }
175
176
177    /**
178     * Sets the structural object class this rule applies to
179     * 
180     * @param structuralObjectClass the structural object class to set
181     */
182    public void setStructuralObjectClass( ObjectClass structuralObjectClass )
183    {
184        if ( locked )
185        {
186            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
187        }
188
189        if ( !isReadOnly )
190        {
191            this.structuralObjectClass = structuralObjectClass;
192            this.structuralObjectClassOid = structuralObjectClass.getOid();
193        }
194    }
195
196
197    /**
198     * Gets all the AttributeTypes OIDs of the attributes this NameForm specifies as
199     * having to be used in the given objectClass for naming: as part of the
200     * Rdn.
201     * 
202     * @return the AttributeTypes OIDs of the must use attributes
203     */
204    public List<String> getMustAttributeTypeOids()
205    {
206        return Collections.unmodifiableList( mustAttributeTypeOids );
207    }
208
209
210    /**
211     * Gets all the AttributeTypes of the attributes this NameForm specifies as
212     * having to be used in the given objectClass for naming: as part of the
213     * Rdn.
214     * 
215     * @return the AttributeTypes of the must use attributes
216     */
217    public List<AttributeType> getMustAttributeTypes()
218    {
219        return Collections.unmodifiableList( mustAttributeTypes );
220    }
221
222
223    /**
224     * Sets the list of required AttributeTypes OIDs
225     *
226     * @param mustAttributeTypeOids the list of required AttributeTypes OIDs
227     */
228    public void setMustAttributeTypeOids( List<String> mustAttributeTypeOids )
229    {
230        if ( locked )
231        {
232            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
233        }
234
235        if ( !isReadOnly )
236        {
237            this.mustAttributeTypeOids = mustAttributeTypeOids;
238        }
239    }
240
241
242    /**
243     * Sets the list of required AttributeTypes
244     *
245     * @param mustAttributeTypes the list of required AttributeTypes
246     */
247    public void setMustAttributeTypes( List<AttributeType> mustAttributeTypes )
248    {
249        if ( locked )
250        {
251            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
252        }
253
254        if ( !isReadOnly )
255        {
256            this.mustAttributeTypes = mustAttributeTypes;
257
258            // update the OIDS now
259            mustAttributeTypeOids.clear();
260
261            for ( AttributeType may : mustAttributeTypes )
262            {
263                mustAttributeTypeOids.add( may.getOid() );
264            }
265        }
266    }
267
268
269    /**
270     * Add a required AttributeType OID
271     *
272     * @param oid The attributeType OID
273     */
274    public void addMustAttributeTypeOids( String oid )
275    {
276        if ( locked )
277        {
278            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
279        }
280
281        if ( !isReadOnly )
282        {
283            mustAttributeTypeOids.add( oid );
284        }
285    }
286
287
288    /**
289     * Add a required AttributeType
290     *
291     * @param attributeType The attributeType
292     */
293    public void addMustAttributeTypes( AttributeType attributeType )
294    {
295        if ( locked )
296        {
297            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
298        }
299
300        if ( !isReadOnly && !mustAttributeTypeOids.contains( attributeType.getOid() ) )
301        {
302            mustAttributeTypes.add( attributeType );
303            mustAttributeTypeOids.add( attributeType.getOid() );
304        }
305    }
306
307
308    /**
309     * Gets all the AttributeTypes OIDs of the attribute this NameForm specifies as
310     * being usable without requirement in the given objectClass for naming: as
311     * part of the Rdn.
312     * 
313     * @return the AttributeTypes OIDs of the may use attributes
314     */
315    public List<String> getMayAttributeTypeOids()
316    {
317        return Collections.unmodifiableList( mayAttributeTypeOids );
318    }
319
320
321    /**
322     * Gets all the AttributeTypes of the attribute this NameForm specifies as
323     * being useable without requirement in the given objectClass for naming: as
324     * part of the Rdn.
325     * 
326     * @return the AttributeTypes of the may use attributes
327     */
328    public List<AttributeType> getMayAttributeTypes()
329    {
330        return Collections.unmodifiableList( mayAttributeTypes );
331    }
332
333
334    /**
335     * Sets the list of allowed AttributeTypes
336     *
337     * @param mayAttributeTypeOids the list of allowed AttributeTypes
338     */
339    public void setMayAttributeTypeOids( List<String> mayAttributeTypeOids )
340    {
341        if ( locked )
342        {
343            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
344        }
345
346        if ( !isReadOnly )
347        {
348            this.mayAttributeTypeOids = mayAttributeTypeOids;
349        }
350    }
351
352
353    /**
354     * Sets the list of allowed AttributeTypes
355     *
356     * @param mayAttributeTypes the list of allowed AttributeTypes
357     */
358    public void setMayAttributeTypes( List<AttributeType> mayAttributeTypes )
359    {
360        if ( locked )
361        {
362            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
363        }
364
365        if ( !isReadOnly )
366        {
367            this.mayAttributeTypes = mayAttributeTypes;
368
369            // update the OIDS now
370            mayAttributeTypeOids.clear();
371
372            for ( AttributeType may : mayAttributeTypes )
373            {
374                mayAttributeTypeOids.add( may.getOid() );
375            }
376        }
377    }
378
379
380    /**
381     * Add an allowed AttributeType
382     *
383     * @param oid The attributeType oid
384     */
385    public void addMayAttributeTypeOids( String oid )
386    {
387        if ( locked )
388        {
389            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
390        }
391
392        if ( !isReadOnly )
393        {
394            mayAttributeTypeOids.add( oid );
395        }
396    }
397
398
399    /**
400     * Add an allowed AttributeType
401     *
402     * @param attributeType The attributeType
403     */
404    public void addMayAttributeTypes( AttributeType attributeType )
405    {
406        if ( locked )
407        {
408            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
409        }
410
411        if ( !isReadOnly && !mayAttributeTypeOids.contains( attributeType.getOid() ) )
412        {
413            mayAttributeTypes.add( attributeType );
414            mayAttributeTypeOids.add( attributeType.getOid() );
415        }
416    }
417
418
419    /**
420     * @see Object#toString()
421     */
422    @Override
423    public String toString()
424    {
425        return SchemaObjectRenderer.OPEN_LDAP_SCHEMA_RENDERER.render( this );
426    }
427
428
429    /**
430     * Copy a NameForm
431     */
432    @Override
433    public NameForm copy()
434    {
435        NameForm copy = new NameForm( oid );
436
437        // Copy the SchemaObject common data
438        copy.copy( this );
439
440        // Copy the MAY AttributeTypes OIDs
441        copy.mayAttributeTypeOids = new ArrayList<>();
442
443        for ( String oid : mayAttributeTypeOids )
444        {
445            copy.mayAttributeTypeOids.add( oid );
446        }
447
448        // Copy the MAY AttributeTypes (will be empty)
449        copy.mayAttributeTypes = new ArrayList<>();
450
451        // Copy the MUST AttributeTypes OIDs
452        copy.mustAttributeTypeOids = new ArrayList<>();
453
454        for ( String oid : mustAttributeTypeOids )
455        {
456            copy.mustAttributeTypeOids.add( oid );
457        }
458
459        // Copy the MUST AttributeTypes ( will be empty )
460        copy.mustAttributeTypes = new ArrayList<>();
461
462        // Copy the Structural ObjectClass OID
463        copy.structuralObjectClassOid = structuralObjectClassOid;
464
465        // All the references to other Registries object are set to null.
466        copy.structuralObjectClass = null;
467
468        return copy;
469    }
470
471
472    /**
473     * @see Object#equals(Object)
474     */
475    @Override
476    public boolean equals( Object o )
477    {
478        if ( !super.equals( o ) )
479        {
480            return false;
481        }
482
483        if ( !( o instanceof NameForm ) )
484        {
485            return false;
486        }
487
488        @SuppressWarnings("unused")
489        NameForm that = ( NameForm ) o;
490
491        // TODO : complete the checks
492        return true;
493    }
494
495
496    /**
497     * {@inheritDoc}
498     */
499    @Override
500    public void clear()
501    {
502        // Clear the common elements
503        super.clear();
504
505        // Clear the references
506        mayAttributeTypes.clear();
507        mayAttributeTypeOids.clear();
508        mustAttributeTypes.clear();
509        mustAttributeTypeOids.clear();
510        structuralObjectClass = null;
511    }
512}