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