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.server.core.schema;
021    
022    
023    import java.text.ParseException;
024    import java.util.ArrayList;
025    import java.util.List;
026    
027    import org.apache.directory.server.i18n.I18n;
028    import org.apache.directory.shared.ldap.constants.MetaSchemaConstants;
029    import org.apache.directory.shared.ldap.constants.SchemaConstants;
030    import org.apache.directory.shared.ldap.entry.EntryAttribute;
031    import org.apache.directory.shared.ldap.entry.Value;
032    import org.apache.directory.shared.ldap.exception.LdapException;
033    import org.apache.directory.shared.ldap.exception.LdapInvalidAttributeValueException;
034    import org.apache.directory.shared.ldap.exception.LdapUnwillingToPerformException;
035    import org.apache.directory.shared.ldap.message.ResultCodeEnum;
036    import org.apache.directory.shared.ldap.schema.AttributeType;
037    import org.apache.directory.shared.ldap.schema.DITContentRule;
038    import org.apache.directory.shared.ldap.schema.DITStructureRule;
039    import org.apache.directory.shared.ldap.schema.LdapSyntax;
040    import org.apache.directory.shared.ldap.schema.MatchingRule;
041    import org.apache.directory.shared.ldap.schema.MatchingRuleUse;
042    import org.apache.directory.shared.ldap.schema.NameForm;
043    import org.apache.directory.shared.ldap.schema.ObjectClass;
044    import org.apache.directory.shared.ldap.schema.SchemaManager;
045    import org.apache.directory.shared.ldap.schema.parsers.AttributeTypeDescriptionSchemaParser;
046    import org.apache.directory.shared.ldap.schema.parsers.DITContentRuleDescriptionSchemaParser;
047    import org.apache.directory.shared.ldap.schema.parsers.DITStructureRuleDescriptionSchemaParser;
048    import org.apache.directory.shared.ldap.schema.parsers.LdapComparatorDescription;
049    import org.apache.directory.shared.ldap.schema.parsers.LdapComparatorDescriptionSchemaParser;
050    import org.apache.directory.shared.ldap.schema.parsers.LdapSyntaxDescriptionSchemaParser;
051    import org.apache.directory.shared.ldap.schema.parsers.MatchingRuleDescriptionSchemaParser;
052    import org.apache.directory.shared.ldap.schema.parsers.MatchingRuleUseDescriptionSchemaParser;
053    import org.apache.directory.shared.ldap.schema.parsers.NameFormDescriptionSchemaParser;
054    import org.apache.directory.shared.ldap.schema.parsers.NormalizerDescription;
055    import org.apache.directory.shared.ldap.schema.parsers.NormalizerDescriptionSchemaParser;
056    import org.apache.directory.shared.ldap.schema.parsers.ObjectClassDescriptionSchemaParser;
057    import org.apache.directory.shared.ldap.schema.parsers.SyntaxCheckerDescription;
058    import org.apache.directory.shared.ldap.schema.parsers.SyntaxCheckerDescriptionSchemaParser;
059    
060    
061    /**
062     * Parses descriptions using a number of different parsers for schema descriptions.
063     * Also checks to make sure some things are valid as it's parsing paramters of
064     * certain entity types.
065     *
066     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
067     * @version $Rev$
068     */
069    public class DescriptionParsers
070    {
071        /** Empty arrays of SchemaOjects */
072        private static final LdapComparatorDescription[] EMPTY_COMPARATORS         = new LdapComparatorDescription[0];
073        private static final NormalizerDescription[]     EMPTY_NORMALIZERS         = new NormalizerDescription[0];
074        private static final SyntaxCheckerDescription[]  EMPTY_SYNTAX_CHECKERS     = new SyntaxCheckerDescription[0];
075        private static final LdapSyntax[]                EMPTY_SYNTAXES            = new LdapSyntax[0];
076        private static final MatchingRule[]              EMPTY_MATCHING_RULES      = new MatchingRule[0];
077        private static final AttributeType[]             EMPTY_ATTRIBUTE_TYPES     = new AttributeType[0];
078        private static final ObjectClass[]               EMPTY_OBJECT_CLASSES      = new ObjectClass[0];
079        private static final MatchingRuleUse[]           EMPTY_MATCHING_RULE_USES  = new MatchingRuleUse[0];
080        private static final DITStructureRule[]          EMPTY_DIT_STRUCTURE_RULES = new DITStructureRule[0];
081        private static final DITContentRule[]            EMPTY_DIT_CONTENT_RULES   = new DITContentRule[0];
082        private static final NameForm[]                  EMPTY_NAME_FORMS          = new NameForm[0];
083    
084        /** The SchemaObject description's parsers */
085        private final LdapComparatorDescriptionSchemaParser   comparatorParser      = new LdapComparatorDescriptionSchemaParser();
086        private final NormalizerDescriptionSchemaParser       normalizerParser       = new NormalizerDescriptionSchemaParser();
087        private final SyntaxCheckerDescriptionSchemaParser    syntaxCheckerParser    = new SyntaxCheckerDescriptionSchemaParser();
088        private final LdapSyntaxDescriptionSchemaParser       syntaxParser           = new LdapSyntaxDescriptionSchemaParser();
089        private final MatchingRuleDescriptionSchemaParser     matchingRuleParser     = new MatchingRuleDescriptionSchemaParser();
090        private final AttributeTypeDescriptionSchemaParser    attributeTypeParser    = new AttributeTypeDescriptionSchemaParser();
091        private final ObjectClassDescriptionSchemaParser      objectClassParser      = new ObjectClassDescriptionSchemaParser();
092        private final MatchingRuleUseDescriptionSchemaParser  matchingRuleUseParser  = new MatchingRuleUseDescriptionSchemaParser();
093        private final DITStructureRuleDescriptionSchemaParser ditStructureRuleParser = new DITStructureRuleDescriptionSchemaParser();
094        private final DITContentRuleDescriptionSchemaParser   ditContentRuleParser   = new DITContentRuleDescriptionSchemaParser();
095        private final NameFormDescriptionSchemaParser         nameFormParser         = new NameFormDescriptionSchemaParser();
096    
097        /** The SchemaManager instance */
098        private final SchemaManager schemaManager;
099    
100        /**
101         * Creates a description parser.
102         * 
103         * @param globalRegistries the registries to use while creating new schema entities
104         */
105        public DescriptionParsers( SchemaManager schemaManager )
106        {
107            this.schemaManager = schemaManager;
108        }
109    
110    
111        /**
112         * Parse the SyntaxCheckers description
113         *
114         * @param attr The attribute containing the SC description
115         * @return The array of SyntaxCheckerDescription instances
116         * @throws LdapInvalidAttributeValueException If something went wrong
117         */
118        public SyntaxCheckerDescription[] parseSyntaxCheckers( EntryAttribute attr ) throws LdapInvalidAttributeValueException
119        {
120            if ( ( attr == null ) || ( attr.size() == 0 ) )
121            {
122                return EMPTY_SYNTAX_CHECKERS;
123            }
124    
125            SyntaxCheckerDescription[] syntaxCheckerDescriptions = new SyntaxCheckerDescription[attr.size()];
126    
127            int pos = 0;
128    
129            for ( Value<?> value : attr )
130            {
131                try
132                {
133                    syntaxCheckerDescriptions[pos++] = syntaxCheckerParser
134                        .parseSyntaxCheckerDescription( value.getString() );
135                }
136                catch ( ParseException e )
137                {
138                    LdapInvalidAttributeValueException iave = new LdapInvalidAttributeValueException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, I18n.err( I18n.ERR_405, 
139                            value ) );
140                    iave.initCause( e );
141                    throw iave;
142                }
143            }
144    
145            return syntaxCheckerDescriptions;
146        }
147    
148    
149        public NormalizerDescription[] parseNormalizers( EntryAttribute attr ) throws LdapInvalidAttributeValueException
150        {
151            if ( attr == null || attr.size() == 0 )
152            {
153                return EMPTY_NORMALIZERS;
154            }
155    
156            NormalizerDescription[] normalizerDescriptions = new NormalizerDescription[attr.size()];
157    
158            int pos = 0;
159    
160            for ( Value<?> value : attr )
161            {
162                try
163                {
164                    normalizerDescriptions[pos++] = normalizerParser.parseNormalizerDescription( value.getString() );
165                }
166                catch ( ParseException e )
167                {
168                    LdapInvalidAttributeValueException iave = new LdapInvalidAttributeValueException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, I18n.err( I18n.ERR_406, 
169                            value.getString() ) );
170                    iave.initCause( e );
171                    throw iave;
172                }
173            }
174    
175            return normalizerDescriptions;
176        }
177    
178    
179        public LdapComparatorDescription[] parseComparators( EntryAttribute attr ) throws LdapInvalidAttributeValueException
180        {
181            if ( attr == null || attr.size() == 0 )
182            {
183                return EMPTY_COMPARATORS;
184            }
185    
186            LdapComparatorDescription[] comparatorDescriptions = new LdapComparatorDescription[attr.size()];
187    
188            int pos = 0;
189    
190            for ( Value<?> value : attr )
191            {
192                try
193                {
194                    comparatorDescriptions[pos++] = comparatorParser.parseComparatorDescription( value.getString() );
195                }
196                catch ( ParseException e )
197                {
198                    LdapInvalidAttributeValueException iave = new LdapInvalidAttributeValueException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, I18n.err( I18n.ERR_407,
199                            value.getString() ) );
200                    iave.initCause( e );
201                    throw iave;
202                }
203            }
204    
205            return comparatorDescriptions;
206        }
207    
208    
209        /**
210         * Parses a set of attributeTypeDescriptions held within an attribute into 
211         * schema entities.
212         * 
213         * @param attr the attribute containing attributeTypeDescriptions
214         * @return the set of attributeType objects for the descriptions 
215         * @throws LdapException if there are problems parsing the descriptions
216         */
217        public AttributeType[] parseAttributeTypes( EntryAttribute attr ) throws LdapException
218        {
219            if ( attr == null || attr.size() == 0 )
220            {
221                return EMPTY_ATTRIBUTE_TYPES;
222            }
223    
224            AttributeType[] attributeTypes = new AttributeType[attr.size()];
225    
226            int pos = 0;
227    
228            for ( Value<?> value : attr )
229            {
230                AttributeType attributeType = null;
231    
232                try
233                {
234                    attributeType = attributeTypeParser.parseAttributeTypeDescription( value.getString() );
235                }
236                catch ( ParseException e )
237                {
238                    LdapInvalidAttributeValueException iave = new LdapInvalidAttributeValueException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, I18n.err( I18n.ERR_408,
239                            value.getString() ) );
240                    iave.initCause( e );
241                    throw iave;
242                }
243    
244                // if the supertype is provided make sure it exists in some schema
245                if ( ( attributeType.getSuperiorOid() != null ) && !schemaManager.getAttributeTypeRegistry().contains( attributeType.getSuperiorOid() ) )
246                {
247                    throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM,
248                        I18n.err( I18n.ERR_409, attributeType.getSuperiorOid() ) );
249                }
250    
251                // if the syntax is provided by the description make sure it exists in some schema
252                if ( attributeType.getSyntaxOid() != null && !schemaManager.getLdapSyntaxRegistry().contains( attributeType.getSyntaxOid() ) )
253                {
254                    throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM,
255                        I18n.err( I18n.ERR_410, attributeType.getSyntaxOid() ) );
256                }
257    
258                // if the matchingRule is provided make sure it exists in some schema
259                if ( attributeType.getEqualityOid() != null && !schemaManager.getMatchingRuleRegistry().contains( attributeType.getEqualityOid() ) )
260                {
261                    throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM,
262                        I18n.err( I18n.ERR_411, attributeType.getEqualityOid() ) );
263                }
264    
265                // if the matchingRule is provided make sure it exists in some schema
266                if ( attributeType.getOrderingOid() != null && !schemaManager.getMatchingRuleRegistry().contains( attributeType.getOrderingOid() ) )
267                {
268                    throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM,
269                        I18n.err( I18n.ERR_412, attributeType.getOrderingOid() ) );
270                }
271    
272                // if the matchingRule is provided make sure it exists in some schema
273                if ( attributeType.getSubstringOid() != null && !schemaManager.getMatchingRuleRegistry().contains( attributeType.getSubstringOid() ) )
274                {
275                    throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM,
276                        I18n.err( I18n.ERR_413, attributeType.getSubstringOid() ) );
277                }
278    
279                // if the equality matching rule is null and no super type is specified then there is
280                // definitely no equality matchingRule that can be resolved.  We cannot use an attribute
281                // without a matchingRule for search or for building indices not to mention lookups.
282                if ( attributeType.getEqualityOid() == null )
283                {
284                    if ( attributeType.getSuperiorOid() == null )
285                    {
286                        throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, I18n.err( I18n.ERR_414 ) );
287                    }
288                    else
289                    {
290                        AttributeType superType = schemaManager
291                            .lookupAttributeTypeRegistry( attributeType.getSuperiorOid() );
292    
293                        if ( superType == null )
294                        {
295                            throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, I18n.err( I18n.ERR_415 ) );
296                        }
297                    }
298                }
299    
300                // a syntax is mandatory for an attributeType and if not provided by the description 
301                // must be provided from some ancestor in the attributeType hierarchy; without either
302                // of these the description definitely cannot resolve a syntax and cannot be allowed.
303                // if a supertype exists then it must resolve a proper syntax somewhere in the hierarchy.
304                if ( attributeType.getSyntaxOid() == null && attributeType.getSuperiorOid() == null )
305                {
306                    throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, I18n.err( I18n.ERR_416 ) );
307                }
308    
309                List<Throwable> errors = new ArrayList<Throwable>();
310    
311                attributeType.setRegistries( schemaManager.getRegistries() );
312    
313                /*
314                // Inject the schema
315                
316                if ( ( attributeType.getExtensions() == null )
317                    || ( attributeType.getExtensions().get( MetaSchemaConstants.X_SCHEMA ) == null ) )
318                {
319                    throw new LdapUnwillingToPerformException(
320                        "Cannot permit the addition of an attributeType not associated with a schema ",
321                        ResultCodeEnum.UNWILLING_TO_PERFORM );
322                }
323    
324                String schemaName = attributeType.getExtensions().get( MetaSchemaConstants.X_SCHEMA ).get( 0 );
325                attributeType.setSchemaName( schemaName );
326                */
327    
328                attributeTypes[pos++] = attributeType;
329            }
330    
331            return attributeTypes;
332        }
333    
334    
335        /**
336         * Parses a set of objectClassDescriptions held within an attribute into 
337         * schema entities.
338         * 
339         * @param attr the attribute containing objectClassDescriptions
340         * @return the set of objectClass objects for the descriptions 
341         * @throws LdapException if there are problems parsing the descriptions
342         */
343        public ObjectClass[] parseObjectClasses( EntryAttribute attr ) throws LdapException
344        {
345            if ( attr == null || attr.size() == 0 )
346            {
347                return EMPTY_OBJECT_CLASSES;
348            }
349    
350            ObjectClass[] objectClasses = new ObjectClass[attr.size()];
351    
352            int pos = 0;
353    
354            for ( Value<?> value : attr )
355            {
356                ObjectClass objectClass = null;
357    
358                try
359                {
360                    objectClass = objectClassParser.parseObjectClassDescription( value.getString() );
361                }
362                catch ( ParseException e )
363                {
364                    LdapInvalidAttributeValueException iave = new LdapInvalidAttributeValueException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, I18n.err( I18n.ERR_417, 
365                            value.getString() ) );
366                    iave.initCause( e );
367                    throw iave;
368                }
369    
370                // if the super objectClasses are provided make sure it exists in some schema
371                if ( objectClass.getSuperiorOids() != null && objectClass.getSuperiorOids().size() > 0 )
372                {
373                    for ( String superiorOid : objectClass.getSuperiorOids() )
374                    {
375                        if ( superiorOid.equals( SchemaConstants.TOP_OC_OID )
376                            || superiorOid.equalsIgnoreCase( SchemaConstants.TOP_OC ) )
377                        {
378                            continue;
379                        }
380    
381                        if ( !schemaManager.getObjectClassRegistry().contains( superiorOid ) )
382                        {
383                            throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM,
384                                I18n.err( I18n.ERR_418, superiorOid ) );
385                        }
386                    }
387                }
388    
389                // if the may list is provided make sure attributes exists in some schema
390                if ( objectClass.getMayAttributeTypeOids() != null && objectClass.getMayAttributeTypeOids().size() > 0 )
391                {
392                    for ( String mayAttrOid : objectClass.getMayAttributeTypeOids() )
393                    {
394                        if ( !schemaManager.getAttributeTypeRegistry().contains( mayAttrOid ) )
395                        {
396                            throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM,
397                                I18n.err( I18n.ERR_419, mayAttrOid ) );
398                        }
399                    }
400                }
401    
402                // if the must list is provided make sure attributes exists in some schema
403                if ( objectClass.getMustAttributeTypeOids() != null && objectClass.getMustAttributeTypeOids().size() > 0 )
404                {
405                    for ( String mustAttrOid : objectClass.getMustAttributeTypeOids() )
406                    {
407                        if ( !schemaManager.getAttributeTypeRegistry().contains( mustAttrOid ) )
408                        {
409                            throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM,
410                                I18n.err( I18n.ERR_420, mustAttrOid ) );
411                        }
412                    }
413                }
414    
415                List<Throwable> errors = new ArrayList<Throwable>();
416                objectClass.setRegistries( schemaManager.getRegistries() );
417    
418                objectClasses[pos++] = objectClass;
419            }
420    
421            return objectClasses;
422        }
423    
424    
425        /**
426         * Parses a set of matchingRuleUseDescriptions held within an attribute into 
427         * schema entities.
428         * 
429         * @param attr the attribute containing matchingRuleUseDescriptions
430         * @return the set of matchingRuleUse objects for the descriptions 
431         * @throws LdapException if there are problems parsing the descriptions
432         */
433        public MatchingRuleUse[] parseMatchingRuleUses( EntryAttribute attr ) throws LdapException
434        {
435            if ( attr == null || attr.size() == 0 )
436            {
437                return EMPTY_MATCHING_RULE_USES;
438            }
439    
440            MatchingRuleUse[] matchingRuleUses = new MatchingRuleUse[attr.size()];
441    
442            int pos = 0;
443    
444            for ( Value<?> value : attr )
445            {
446                MatchingRuleUse matchingRuleUse = null;
447    
448                try
449                {
450                    matchingRuleUse = matchingRuleUseParser.parseMatchingRuleUseDescription( value.getString() );
451                    matchingRuleUse.setSpecification( value.getString() );
452                }
453                catch ( ParseException e )
454                {
455                    LdapInvalidAttributeValueException iave = new LdapInvalidAttributeValueException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, I18n.err( I18n.ERR_421, 
456                            value.getString() ) );
457                    iave.initCause( e );
458                    throw iave;
459                }
460    
461                matchingRuleUses[pos++] = matchingRuleUse;
462            }
463    
464            return matchingRuleUses;
465        }
466    
467    
468        /**
469         * Parses a set of ldapSyntaxes held within an attribute into 
470         * schema entities.
471         * 
472         * @param attr the attribute containing ldapSyntaxes
473         * @return the set of Syntax objects for the descriptions 
474         * @throws LdapException if there are problems parsing the descriptions
475         */
476        public LdapSyntax[] parseLdapSyntaxes( EntryAttribute attr ) throws LdapException
477        {
478            if ( attr == null || attr.size() == 0 )
479            {
480                return EMPTY_SYNTAXES;
481            }
482    
483            LdapSyntax[] syntaxes = new LdapSyntax[attr.size()];
484    
485            int pos = 0;
486    
487            for ( Value<?> value : attr )
488            {
489                LdapSyntax ldapSyntax = null;
490    
491                try
492                {
493                    ldapSyntax = syntaxParser.parseLdapSyntaxDescription( value.getString() );
494                    ldapSyntax.setSpecification( value.getString() );
495                }
496                catch ( ParseException e )
497                {
498                    LdapInvalidAttributeValueException iave = new LdapInvalidAttributeValueException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, I18n.err( I18n.ERR_422, 
499                            value.getString() ) );
500                    iave.initCause( e );
501                    throw iave;
502                }
503    
504                if ( !schemaManager.getSyntaxCheckerRegistry().contains( ldapSyntax.getOid() ) )
505                {
506                    throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, I18n.err( I18n.ERR_423 ) );
507                }
508    
509                ldapSyntax.setHumanReadable( isHumanReadable( ldapSyntax ) );
510                syntaxes[pos++] = ldapSyntax;
511            }
512    
513            return syntaxes;
514        }
515    
516    
517        /**
518         * Parses a set of matchingRuleDescriptions held within an attribute into 
519         * schema entities.
520         * 
521         * @param attr the attribute containing matchingRuleDescriptions
522         * @return the set of matchingRule objects for the descriptions 
523         * @throws LdapException if there are problems parsing the descriptions
524         */
525        public MatchingRule[] parseMatchingRules( EntryAttribute attr ) throws LdapException
526        {
527            if ( attr == null || attr.size() == 0 )
528            {
529                return EMPTY_MATCHING_RULES;
530            }
531    
532            MatchingRule[] matchingRules = new MatchingRule[attr.size()];
533    
534            int pos = 0;
535    
536            for ( Value<?> value : attr )
537            {
538                MatchingRule matchingRule = null;
539    
540                try
541                {
542                    matchingRule = matchingRuleParser.parseMatchingRuleDescription( value.getString() );
543                    matchingRule.setSpecification( value.getString() );
544                }
545                catch ( ParseException e )
546                {
547                    LdapInvalidAttributeValueException iave = new LdapInvalidAttributeValueException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, I18n.err( I18n.ERR_424, 
548                            value.getString() ) );
549                    iave.initCause( e );
550                    throw iave;
551                }
552    
553                if ( !schemaManager.getLdapSyntaxRegistry().contains( matchingRule.getSyntaxOid() ) )
554                {
555                    throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM,
556                        I18n.err( I18n.ERR_425, matchingRule.getSyntaxOid() ) );
557                }
558    
559                matchingRules[pos++] = matchingRule;
560            }
561    
562            return matchingRules;
563        }
564    
565    
566        /**
567         * Parses a set of dITStructureRuleDescriptions held within an attribute into 
568         * schema entities.
569         * 
570         * @param attr the attribute containing dITStructureRuleDescriptions
571         * @return the set of DITStructureRule objects for the descriptions 
572         * @throws LdapException if there are problems parsing the descriptions
573         */
574        public DITStructureRule[] parseDitStructureRules( EntryAttribute attr ) throws LdapException
575        {
576            if ( attr == null || attr.size() == 0 )
577            {
578                return EMPTY_DIT_STRUCTURE_RULES;
579            }
580    
581            DITStructureRule[] ditStructureRules = new DITStructureRule[attr.size()];
582    
583            int pos = 0;
584    
585            for ( Value<?> value : attr )
586            {
587                DITStructureRule ditStructureRule = null;
588    
589                try
590                {
591                    ditStructureRule = ditStructureRuleParser.parseDITStructureRuleDescription( value.getString() );
592                    ditStructureRule.setSpecification( value.getString() );
593                }
594                catch ( ParseException e )
595                {
596                    LdapInvalidAttributeValueException iave = new LdapInvalidAttributeValueException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, I18n.err( I18n.ERR_426, 
597                            value.getString() ) );
598                    iave.initCause( e );
599                    throw iave;
600                }
601    
602                ditStructureRules[pos++] = ditStructureRule;
603            }
604    
605            return ditStructureRules;
606        }
607    
608    
609        /**
610         * Parses a set of dITContentRuleDescriptions held within an attribute into 
611         * schema entities.
612         * 
613         * @param attr the attribute containing dITContentRuleDescriptions
614         * @return the set of DITContentRule objects for the descriptions 
615         * @throws LdapException if there are problems parsing the descriptions
616         */
617        public DITContentRule[] parseDitContentRules( EntryAttribute attr ) throws LdapException
618        {
619            if ( attr == null || attr.size() == 0 )
620            {
621                return EMPTY_DIT_CONTENT_RULES;
622            }
623    
624            DITContentRule[] ditContentRules = new DITContentRule[attr.size()];
625    
626            int pos = 0;
627    
628            for ( Value<?> value : attr )
629            {
630                DITContentRule ditContentRule = null;
631    
632                try
633                {
634                    ditContentRule = ditContentRuleParser.parseDITContentRuleDescription( value.getString() );
635                    ditContentRule.setSpecification( value.getString() );
636                }
637                catch ( ParseException e )
638                {
639                    LdapInvalidAttributeValueException iave = new LdapInvalidAttributeValueException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, I18n.err( I18n.ERR_427, 
640                            value.getString() ) );
641                    iave.initCause( e );
642                    throw iave;
643                }
644    
645                ditContentRules[pos++] = ditContentRule;
646            }
647    
648            return ditContentRules;
649        }
650    
651    
652        /**
653         * Parses a set of nameFormDescriptions held within an attribute into 
654         * schema entities.
655         * 
656         * @param attr the attribute containing nameFormDescriptions
657         * @return the set of NameFormRule objects for the descriptions 
658         * @throws LdapException if there are problems parsing the descriptions
659         */
660        public NameForm[] parseNameForms( EntryAttribute attr ) throws LdapException
661        {
662            if ( attr == null || attr.size() == 0 )
663            {
664                return EMPTY_NAME_FORMS;
665            }
666    
667            NameForm[] nameForms = new NameForm[attr.size()];
668    
669            int pos = 0;
670    
671            for ( Value<?> value : attr )
672            {
673                NameForm nameForm = null;
674    
675                try
676                {
677                    nameForm = nameFormParser.parseNameFormDescription( value.getString() );
678                    nameForm.setSpecification( value.getString() );
679                }
680                catch ( ParseException e )
681                {
682                    LdapInvalidAttributeValueException iave = new LdapInvalidAttributeValueException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, I18n.err( I18n.ERR_428, 
683                            value.getString() ) );
684                    iave.initCause( e );
685                    throw iave;
686                }
687    
688                nameForms[pos++] = nameForm;
689            }
690    
691            return nameForms;
692        }
693    
694    
695        /**
696         * Checks to see if the syntax description is human readable by checking 
697         * for the presence of the X-IS-HUMAN_READABLE schema extension.
698         * 
699         * @param desc the ldapSyntax 
700         * @return true if the syntax is human readable, false otherwise
701         */
702        private boolean isHumanReadable( LdapSyntax ldapSyntax )
703        {
704            List<String> values = ldapSyntax.getExtensions().get( MetaSchemaConstants.X_IS_HUMAN_READABLE );
705    
706            if ( values == null || values.size() == 0 )
707            {
708                return false;
709            }
710            else
711            {
712                String value = values.get( 0 );
713                if ( value.equals( "TRUE" ) )
714                {
715                    return true;
716                }
717                else
718                {
719                    return false;
720                }
721            }
722        }
723    }