View Javadoc

1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *  
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *  
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License. 
18   *  
19   */
20  package org.apache.directory.server.core.schema;
21  
22  
23  import java.text.ParseException;
24  import java.util.List;
25  
26  import javax.naming.NamingException;
27  
28  import org.apache.directory.server.constants.MetaSchemaConstants;
29  import org.apache.directory.server.schema.registries.Registries;
30  import org.apache.directory.shared.ldap.constants.SchemaConstants;
31  import org.apache.directory.shared.ldap.entry.EntryAttribute;
32  import org.apache.directory.shared.ldap.entry.Value;
33  import org.apache.directory.shared.ldap.exception.LdapInvalidAttributeValueException;
34  import org.apache.directory.shared.ldap.exception.LdapOperationNotSupportedException;
35  import org.apache.directory.shared.ldap.message.ResultCodeEnum;
36  import org.apache.directory.shared.ldap.schema.AttributeType;
37  import org.apache.directory.shared.ldap.schema.DITContentRule;
38  import org.apache.directory.shared.ldap.schema.DITStructureRule;
39  import org.apache.directory.shared.ldap.schema.MatchingRule;
40  import org.apache.directory.shared.ldap.schema.MatchingRuleUse;
41  import org.apache.directory.shared.ldap.schema.MutableSchemaObject;
42  import org.apache.directory.shared.ldap.schema.NameForm;
43  import org.apache.directory.shared.ldap.schema.ObjectClass;
44  import org.apache.directory.shared.ldap.schema.Syntax;
45  import org.apache.directory.shared.ldap.schema.syntax.AbstractSchemaDescription;
46  import org.apache.directory.shared.ldap.schema.syntax.AttributeTypeDescription;
47  import org.apache.directory.shared.ldap.schema.syntax.ComparatorDescription;
48  import org.apache.directory.shared.ldap.schema.syntax.DITContentRuleDescription;
49  import org.apache.directory.shared.ldap.schema.syntax.DITStructureRuleDescription;
50  import org.apache.directory.shared.ldap.schema.syntax.LdapSyntaxDescription;
51  import org.apache.directory.shared.ldap.schema.syntax.MatchingRuleDescription;
52  import org.apache.directory.shared.ldap.schema.syntax.MatchingRuleUseDescription;
53  import org.apache.directory.shared.ldap.schema.syntax.NameFormDescription;
54  import org.apache.directory.shared.ldap.schema.syntax.NormalizerDescription;
55  import org.apache.directory.shared.ldap.schema.syntax.ObjectClassDescription;
56  import org.apache.directory.shared.ldap.schema.syntax.SyntaxCheckerDescription;
57  import org.apache.directory.shared.ldap.schema.syntax.parser.AttributeTypeDescriptionSchemaParser;
58  import org.apache.directory.shared.ldap.schema.syntax.parser.ComparatorDescriptionSchemaParser;
59  import org.apache.directory.shared.ldap.schema.syntax.parser.DITContentRuleDescriptionSchemaParser;
60  import org.apache.directory.shared.ldap.schema.syntax.parser.DITStructureRuleDescriptionSchemaParser;
61  import org.apache.directory.shared.ldap.schema.syntax.parser.LdapSyntaxDescriptionSchemaParser;
62  import org.apache.directory.shared.ldap.schema.syntax.parser.MatchingRuleDescriptionSchemaParser;
63  import org.apache.directory.shared.ldap.schema.syntax.parser.MatchingRuleUseDescriptionSchemaParser;
64  import org.apache.directory.shared.ldap.schema.syntax.parser.NameFormDescriptionSchemaParser;
65  import org.apache.directory.shared.ldap.schema.syntax.parser.NormalizerDescriptionSchemaParser;
66  import org.apache.directory.shared.ldap.schema.syntax.parser.ObjectClassDescriptionSchemaParser;
67  import org.apache.directory.shared.ldap.schema.syntax.parser.SyntaxCheckerDescriptionSchemaParser;
68  
69  
70  /**
71   * Parses descriptions using a number of different parsers for schema descriptions.
72   * Also checks to make sure some things are valid as it's parsing paramters of
73   * certain entity types.
74   *
75   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
76   * @version $Rev$
77   */
78  public class DescriptionParsers
79  {
80      private static final String OTHER_SCHEMA = "other";
81      private static final String[] EMPTY = new String[0];
82      private static final Integer[] EMPTY_INT_ARRAY = new Integer[0];
83  
84      private static final ComparatorDescription[] EMPTY_COMPARATORS = new ComparatorDescription[0];
85      private static final NormalizerDescription[] EMPTY_NORMALIZERS = new NormalizerDescription[0];
86      private static final SyntaxCheckerDescription[] EMPTY_SYNTAX_CHECKERS = new SyntaxCheckerDescription[0];
87      private static final Syntax[] EMPTY_SYNTAXES = new Syntax[0];
88      private static final MatchingRule[] EMPTY_MATCHING_RULES = new MatchingRule[0];
89      private static final AttributeType[] EMPTY_ATTRIBUTE_TYPES = new AttributeType[0];
90      private static final ObjectClass[] EMPTY_OBJECT_CLASSES = new ObjectClass[0];
91      private static final MatchingRuleUse[] EMPTY_MATCHING_RULE_USES = new MatchingRuleUse[0];
92      private static final DITStructureRule[] EMPTY_DIT_STRUCTURE_RULES = new DITStructureRule[0];
93      private static final DITContentRule[] EMPTY_DIT_CONTENT_RULES = new DITContentRule[0];
94      private static final NameForm[] EMPTY_NAME_FORMS = new NameForm[0];
95  
96      private final Registries globalRegistries;
97      
98      private final ComparatorDescriptionSchemaParser comparatorParser =
99          new ComparatorDescriptionSchemaParser();
100     private final NormalizerDescriptionSchemaParser normalizerParser =
101         new NormalizerDescriptionSchemaParser();
102     private final SyntaxCheckerDescriptionSchemaParser syntaxCheckerParser =
103         new SyntaxCheckerDescriptionSchemaParser();
104     private final LdapSyntaxDescriptionSchemaParser syntaxParser =
105         new LdapSyntaxDescriptionSchemaParser();
106     private final MatchingRuleDescriptionSchemaParser matchingRuleParser =
107         new MatchingRuleDescriptionSchemaParser();
108     private final AttributeTypeDescriptionSchemaParser attributeTypeParser = 
109         new AttributeTypeDescriptionSchemaParser();
110     private final ObjectClassDescriptionSchemaParser objectClassParser = 
111         new ObjectClassDescriptionSchemaParser();
112     private final MatchingRuleUseDescriptionSchemaParser matchingRuleUseParser = 
113         new MatchingRuleUseDescriptionSchemaParser();
114     private final DITStructureRuleDescriptionSchemaParser ditStructureRuleParser =
115         new DITStructureRuleDescriptionSchemaParser();
116     private final DITContentRuleDescriptionSchemaParser ditContentRuleParser =
117         new DITContentRuleDescriptionSchemaParser();
118     private final NameFormDescriptionSchemaParser nameFormParser =
119         new NameFormDescriptionSchemaParser();
120     
121     private final SchemaPartitionDao dao;
122     
123     
124     /**
125      * Creates a description parser.
126      * 
127      * @param globalRegistries the registries to use while creating new schema entities
128      */
129     public DescriptionParsers( Registries globalRegistries, SchemaPartitionDao dao )
130     {
131         this.globalRegistries = globalRegistries;
132         this.dao = dao;
133     }
134 
135     
136     public SyntaxCheckerDescription[] parseSyntaxCheckers( EntryAttribute attr ) throws NamingException
137     {
138         if ( attr == null || attr.size() == 0 )
139         {
140             return EMPTY_SYNTAX_CHECKERS;
141         }
142         
143         SyntaxCheckerDescription[] syntaxCheckerDescriptions = new SyntaxCheckerDescription[attr.size()];
144         
145         int pos = 0;
146         
147         for ( Value<?> value:attr )
148         {
149             try
150             {
151                 syntaxCheckerDescriptions[pos++] = 
152                     syntaxCheckerParser.parseSyntaxCheckerDescription( (String)value.get() );
153             }
154             catch ( ParseException e )
155             {
156                 LdapInvalidAttributeValueException iave = new LdapInvalidAttributeValueException( 
157                     "The following does not conform to the syntaxCheckerDescription syntax: " + value, 
158                     ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX );
159                 iave.setRootCause( e );
160                 throw iave;
161             }
162         }
163         
164         return syntaxCheckerDescriptions;
165     }
166     
167     
168     public NormalizerDescription[] parseNormalizers( EntryAttribute attr ) throws NamingException
169     {
170         if ( attr == null || attr.size() == 0 )
171         {
172             return EMPTY_NORMALIZERS;
173         }
174         
175         NormalizerDescription[] normalizerDescriptions = new NormalizerDescription[attr.size()];
176         
177         int pos = 0;
178         
179         for ( Value<?> value:attr )
180         {
181             try
182             {
183                 normalizerDescriptions[pos++] = normalizerParser.parseNormalizerDescription( (String)value.get() );
184             }
185             catch ( ParseException e )
186             {
187                 LdapInvalidAttributeValueException iave = new LdapInvalidAttributeValueException( 
188                     "The following does not conform to the normalizerDescription syntax: " + value.get(), 
189                     ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX );
190                 iave.setRootCause( e );
191                 throw iave;
192             }
193         }
194         
195         return normalizerDescriptions;
196     }
197     
198 
199     public ComparatorDescription[] parseComparators( EntryAttribute attr ) throws NamingException
200     {
201         if ( attr == null || attr.size() == 0 )
202         {
203             return EMPTY_COMPARATORS;
204         }
205         
206         ComparatorDescription[] comparatorDescriptions = new ComparatorDescription[attr.size()];
207         
208         int pos = 0;
209         
210         for ( Value<?> value:attr )
211         {
212             try
213             {
214                 comparatorDescriptions[pos++] = comparatorParser.parseComparatorDescription( ( String ) value.get() );
215             }
216             catch ( ParseException e )
217             {
218                 LdapInvalidAttributeValueException iave = new LdapInvalidAttributeValueException( 
219                     "The following does not conform to the comparatorDescription syntax: " + value.get(), 
220                     ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX );
221                 iave.setRootCause( e );
222                 throw iave;
223             }
224         }
225         
226         return comparatorDescriptions;
227     }
228     
229 
230     /**
231      * Parses a set of attributeTypeDescriptions held within an attribute into 
232      * schema entities.
233      * 
234      * @param attr the attribute containing attributeTypeDescriptions
235      * @return the set of attributeType objects for the descriptions 
236      * @throws NamingException if there are problems parsing the descriptions
237      */
238     public AttributeType[] parseAttributeTypes( EntryAttribute attr ) throws Exception
239     {
240         if ( attr == null || attr.size() == 0 )
241         {
242             return EMPTY_ATTRIBUTE_TYPES;
243         }
244         
245         AttributeType[] attributeTypes = new AttributeType[attr.size()];
246         
247         int pos = 0;
248         
249         for ( Value<?> value:attr )
250         {
251             AttributeTypeDescription desc = null;
252             
253             try
254             {
255                 desc = attributeTypeParser.parseAttributeTypeDescription( ( String ) value.get() );
256             }
257             catch ( ParseException e )
258             {
259                 LdapInvalidAttributeValueException iave = new LdapInvalidAttributeValueException( 
260                     "The following does not conform to the attributeTypeDescription syntax: " + value.get(), 
261                     ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX );
262                 iave.setRootCause( e );
263                 throw iave;
264             }
265 
266             // if the supertype is provided make sure it exists in some schema
267             if ( desc.getSuperType() != null && ! dao.hasAttributeType( desc.getSuperType() ) )
268             {
269                 throw new LdapOperationNotSupportedException(
270                     "Cannot permit the addition of an attributeType with an invalid super type: " 
271                         + desc.getSuperType(), 
272                     ResultCodeEnum.UNWILLING_TO_PERFORM );
273             }
274 
275             // if the syntax is provided by the description make sure it exists in some schema
276             if ( desc.getSyntax() != null && ! dao.hasSyntax( desc.getSyntax() ) )
277             {
278                 throw new LdapOperationNotSupportedException(
279                     "Cannot permit the addition of an attributeType with an invalid syntax: " + desc.getSyntax(), 
280                     ResultCodeEnum.UNWILLING_TO_PERFORM );
281             }
282             
283             // if the matchingRule is provided make sure it exists in some schema
284             if ( desc.getEqualityMatchingRule() != null && ! dao.hasMatchingRule( desc.getEqualityMatchingRule() ) )
285             {
286                 throw new LdapOperationNotSupportedException(
287                     "Cannot permit the addition of an attributeType with an invalid EQUALITY matchingRule: " 
288                         + desc.getEqualityMatchingRule(), 
289                     ResultCodeEnum.UNWILLING_TO_PERFORM );
290             }
291 
292             // if the matchingRule is provided make sure it exists in some schema
293             if ( desc.getOrderingMatchingRule() != null && ! dao.hasMatchingRule( desc.getOrderingMatchingRule() ) )
294             {
295                 throw new LdapOperationNotSupportedException(
296                     "Cannot permit the addition of an attributeType with an invalid ORDERING matchingRule: " 
297                         + desc.getOrderingMatchingRule(), 
298                     ResultCodeEnum.UNWILLING_TO_PERFORM );
299             }
300 
301             // if the matchingRule is provided make sure it exists in some schema
302             if ( desc.getSubstringsMatchingRule() != null && ! dao.hasMatchingRule( desc.getSubstringsMatchingRule() ) )
303             {
304                 throw new LdapOperationNotSupportedException(
305                     "Cannot permit the addition of an attributeType with an invalid SUBSTRINGS matchingRule: " 
306                         + desc.getSubstringsMatchingRule(), 
307                     ResultCodeEnum.UNWILLING_TO_PERFORM );
308             }
309 
310             // if the equality matching rule is null and no super type is specified then there is
311             // definitely no equality matchingRule that can be resolved.  We cannot use an attribute
312             // without a matchingRule for search or for building indices not to mention lookups.
313             if ( desc.getEqualityMatchingRule() == null && desc.getSuperType() == null )
314             {
315                 throw new LdapOperationNotSupportedException(
316                     "Cannot permit the addition of an attributeType with an no EQUALITY matchingRule " +
317                     "\nand no super type from which to derive an EQUALITY matchingRule.", 
318                     ResultCodeEnum.UNWILLING_TO_PERFORM );
319             }
320             else if ( desc.getEqualityMatchingRule() == null )
321             {
322                 AttributeType superType = globalRegistries.getAttributeTypeRegistry().lookup( desc.getSuperType() );
323                 if ( superType.getEquality() == null )
324                 {
325                     throw new LdapOperationNotSupportedException(
326                         "Cannot permit the addition of an attributeType with which cannot resolve an " +
327                         "EQUALITY matchingRule from it's super type.", 
328                         ResultCodeEnum.UNWILLING_TO_PERFORM );
329                 }
330             }
331             
332             // a syntax is manditory for an attributeType and if not provided by the description 
333             // must be provided from some ancestor in the attributeType hierarchy; without either
334             // of these the description definitely cannot resolve a syntax and cannot be allowed.
335             // if a supertype exists then it must resolve a proper syntax somewhere in the hierarchy.
336             if ( desc.getSyntax() == null && desc.getSuperType() == null )
337             {
338                 throw new LdapOperationNotSupportedException(
339                     "Cannot permit the addition of an attributeType with an no syntax " +
340                     "\nand no super type from which to derive a syntax.", 
341                     ResultCodeEnum.UNWILLING_TO_PERFORM );
342             }
343             
344 
345             AttributeTypeImpl at = new AttributeTypeImpl( desc.getNumericOid(), globalRegistries );
346             at.setCanUserModify( desc.isUserModifiable() );
347             at.setCollective( desc.isCollective() );
348             at.setEqualityOid( desc.getEqualityMatchingRule() );
349             at.setOrderingOid( desc.getOrderingMatchingRule() );
350             at.setSingleValue( desc.isSingleValued() );
351             at.setSubstrOid( desc.getSubstringsMatchingRule() );
352             at.setSuperiorOid( desc.getSuperType() );
353             at.setSyntaxOid( desc.getSyntax() );
354             at.setUsage( desc.getUsage() );
355             
356             setSchemaObjectProperties( desc, at );
357 
358             attributeTypes[pos++] = at;
359         }
360         
361         return attributeTypes;
362     }
363     
364     
365     /**
366      * Parses a set of objectClassDescriptions held within an attribute into 
367      * schema entities.
368      * 
369      * @param attr the attribute containing objectClassDescriptions
370      * @return the set of objectClass objects for the descriptions 
371      * @throws NamingException if there are problems parsing the descriptions
372      */
373     public ObjectClass[] parseObjectClasses( EntryAttribute attr ) throws Exception
374     {
375         if ( attr == null || attr.size() == 0 )
376         {
377             return EMPTY_OBJECT_CLASSES;
378         }
379         
380         ObjectClass[] objectClasses = new ObjectClass[attr.size()];
381         
382         int pos = 0;
383         
384         for ( Value<?> value:attr )
385         {
386             ObjectClassDescription desc = null;
387             
388             try
389             {
390                 desc = objectClassParser.parseObjectClassDescription( ( String ) value.get() );
391             }
392             catch ( ParseException e )
393             {
394                 LdapInvalidAttributeValueException iave = new LdapInvalidAttributeValueException( 
395                     "The following does not conform to the objectClassDescription syntax: " + value.get(), 
396                     ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX );
397                 iave.setRootCause( e );
398                 throw iave;
399             }
400             
401             // if the super objectClasses are provided make sure it exists in some schema
402             if ( desc.getSuperiorObjectClasses() != null && desc.getSuperiorObjectClasses().size() > 0 )
403             {
404                 for ( String superior : desc.getSuperiorObjectClasses() )
405                 {
406                     if ( superior.equals( SchemaConstants.TOP_OC_OID ) || 
407                         superior.equalsIgnoreCase( SchemaConstants.TOP_OC ) )
408                     {
409                         continue;
410                     }
411                     
412                     if ( ! dao.hasObjectClass( superior ) )
413                     {
414                         throw new LdapOperationNotSupportedException(
415                             "Cannot permit the addition of an objectClass with an invalid superior objectClass: " 
416                                 + superior, 
417                             ResultCodeEnum.UNWILLING_TO_PERFORM );
418                     }
419                 }
420             }
421             
422             // if the may list is provided make sure attributes exists in some schema
423             if ( desc.getMayAttributeTypes() != null && desc.getMayAttributeTypes().size() > 0 )
424             {
425                 for ( String mayAttr : desc.getMayAttributeTypes() )
426                 {
427                     if ( ! dao.hasAttributeType( mayAttr ) )
428                     {
429                         throw new LdapOperationNotSupportedException(
430                             "Cannot permit the addition of an objectClass with an invalid " +
431                             "attributeType in the mayList: " + mayAttr, 
432                             ResultCodeEnum.UNWILLING_TO_PERFORM );
433                     }
434                 }
435             }
436             
437             // if the must list is provided make sure attributes exists in some schema
438             if ( desc.getMustAttributeTypes() != null && desc.getMustAttributeTypes().size() > 0 )
439             {
440                 for ( String mustAttr : desc.getMustAttributeTypes() )
441                 {
442                     if ( ! dao.hasAttributeType( mustAttr ) )
443                     {
444                         throw new LdapOperationNotSupportedException(
445                             "Cannot permit the addition of an objectClass with an invalid " +
446                             "attributeType in the mustList: " + mustAttr, 
447                             ResultCodeEnum.UNWILLING_TO_PERFORM );
448                     }
449                 }
450             }
451             
452             ObjectClassImpl oc = new ObjectClassImpl( desc.getNumericOid(), globalRegistries );
453             oc.setMayListOids( desc.getMayAttributeTypes().toArray( EMPTY) );
454             oc.setMustListOids( desc.getMustAttributeTypes().toArray( EMPTY ) );
455             oc.setSuperClassOids( desc.getSuperiorObjectClasses().toArray( EMPTY ) );
456             oc.setType( desc.getKind() );
457             setSchemaObjectProperties( desc, oc );
458             
459             objectClasses[pos++] = oc;
460         }
461         
462         return objectClasses;
463     }
464 
465 
466     /**
467      * Parses a set of matchingRuleUseDescriptions held within an attribute into 
468      * schema entities.
469      * 
470      * @param attr the attribute containing matchingRuleUseDescriptions
471      * @return the set of matchingRuleUse objects for the descriptions 
472      * @throws NamingException if there are problems parsing the descriptions
473      */
474     public MatchingRuleUse[] parseMatchingRuleUses( EntryAttribute attr ) throws NamingException
475     {
476         if ( attr == null || attr.size() == 0 )
477         {
478             return EMPTY_MATCHING_RULE_USES;
479         }
480         
481         MatchingRuleUse[] matchingRuleUses = new MatchingRuleUse[attr.size()];
482         
483         int pos = 0;
484         
485         for ( Value<?> value:attr )
486         {
487             MatchingRuleUseDescription desc = null;
488             
489             try
490             {
491                 desc = matchingRuleUseParser.parseMatchingRuleUseDescription( ( String ) value.get() );
492             }
493             catch ( ParseException e )
494             {
495                 LdapInvalidAttributeValueException iave = new LdapInvalidAttributeValueException( 
496                     "The following does not conform to the matchingRuleUseDescription syntax: " + value.get(), 
497                     ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX );
498                 iave.setRootCause( e );
499                 throw iave;
500             }
501             
502             MatchingRuleUseImpl mru = new MatchingRuleUseImpl( desc.getNumericOid(), globalRegistries );
503             mru.setApplicableAttributesOids( desc.getApplicableAttributes().toArray( EMPTY ) );
504             setSchemaObjectProperties( desc, mru );
505             
506             matchingRuleUses[pos++] = mru;
507         }
508 
509         return matchingRuleUses;
510     }
511 
512 
513     /**
514      * Parses a set of ldapSyntaxDescriptions held within an attribute into 
515      * schema entities.
516      * 
517      * @param attr the attribute containing ldapSyntaxDescriptions
518      * @return the set of Syntax objects for the descriptions 
519      * @throws NamingException if there are problems parsing the descriptions
520      */
521     public Syntax[] parseSyntaxes( EntryAttribute attr ) throws Exception
522     {
523         if ( attr == null || attr.size() == 0 )
524         {
525             return EMPTY_SYNTAXES;
526         }
527         
528         Syntax[] syntaxes = new Syntax[attr.size()];
529 
530         int pos = 0;
531         
532         for ( Value<?> value:attr )
533         {
534             LdapSyntaxDescription desc = null;
535             
536             try
537             {
538                 desc = syntaxParser.parseLdapSyntaxDescription( ( String ) value.get() );
539             }
540             catch ( ParseException e )
541             {
542                 LdapInvalidAttributeValueException iave = new LdapInvalidAttributeValueException( 
543                     "The following does not conform to the ldapSyntaxDescription syntax: " + value.get(), 
544                     ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX );
545                 iave.setRootCause( e );
546                 throw iave;
547             }
548             
549             if ( ! dao.hasSyntaxChecker( desc.getNumericOid() ) )
550             {
551                 throw new LdapOperationNotSupportedException(
552                     "Cannot permit the addition of a syntax without the prior creation of a " +
553                     "\nsyntaxChecker with the same object identifier of the syntax!",
554                     ResultCodeEnum.UNWILLING_TO_PERFORM );
555             }
556 
557             SyntaxImpl syntax = new SyntaxImpl( desc.getNumericOid(), globalRegistries.getSyntaxCheckerRegistry() );
558             setSchemaObjectProperties( desc, syntax );
559             syntax.setHumanReadable( isHumanReadable( desc ) );
560             syntaxes[pos++] = syntax;
561         }
562         
563         return syntaxes;
564     }
565 
566 
567     /**
568      * Parses a set of matchingRuleDescriptions held within an attribute into 
569      * schema entities.
570      * 
571      * @param attr the attribute containing matchingRuleDescriptions
572      * @return the set of matchingRule objects for the descriptions 
573      * @throws NamingException if there are problems parsing the descriptions
574      */
575     public MatchingRule[] parseMatchingRules( EntryAttribute attr ) throws Exception
576     {
577         if ( attr == null || attr.size() == 0 )
578         {
579             return EMPTY_MATCHING_RULES;
580         }
581         
582         MatchingRule[] matchingRules = new MatchingRule[attr.size()];
583 
584         int pos = 0;
585         
586         for ( Value<?> value:attr )
587         {
588             MatchingRuleDescription desc = null;
589 
590             try
591             {
592                 desc = matchingRuleParser.parseMatchingRuleDescription( ( String ) value.get() );
593             }
594             catch ( ParseException e )
595             {
596                 LdapInvalidAttributeValueException iave = new LdapInvalidAttributeValueException( 
597                     "The following does not conform to the matchingRuleDescription syntax: " + value.get(), 
598                     ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX );
599                 iave.setRootCause( e );
600                 throw iave;
601             }
602             
603             if ( ! dao.hasSyntax( desc.getSyntax() )  )
604             {
605                 throw new LdapOperationNotSupportedException(
606                     "Cannot create a matchingRule that depends on non-existant syntax: " + desc.getSyntax(),
607                     ResultCodeEnum.UNWILLING_TO_PERFORM );
608             }
609             
610             MatchingRuleImpl mr = new MatchingRuleImpl( desc.getNumericOid(), desc.getSyntax(), globalRegistries );
611             setSchemaObjectProperties( desc, mr );
612             
613             matchingRules[pos++] = mr;
614         }
615         
616         return matchingRules;
617     }
618     
619 
620     /**
621      * Parses a set of dITStructureRuleDescriptions held within an attribute into 
622      * schema entities.
623      * 
624      * @param attr the attribute containing dITStructureRuleDescriptions
625      * @return the set of DITStructureRule objects for the descriptions 
626      * @throws NamingException if there are problems parsing the descriptions
627      */
628     public DITStructureRule[] parseDitStructureRules( EntryAttribute attr ) throws NamingException
629     {
630         if ( attr == null || attr.size() == 0 )
631         {
632             return EMPTY_DIT_STRUCTURE_RULES;
633         }
634         
635         DITStructureRule[] ditStructureRules = new DITStructureRule[attr.size()];
636         
637         int pos = 0;
638         
639         for ( Value<?> value:attr )
640         {
641             DITStructureRuleDescription desc = null;
642      
643             try
644             {
645                 desc = ditStructureRuleParser.parseDITStructureRuleDescription( ( String ) value.get() );
646             }
647             catch ( ParseException e )
648             {
649                 LdapInvalidAttributeValueException iave = new LdapInvalidAttributeValueException( 
650                     "The following does not conform to the ditStructureRuleDescription syntax: " + value.get(), 
651                     ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX );
652                 iave.setRootCause( e );
653                 throw iave;
654             }
655             
656             DitStructureRuleImpl dsr = new DitStructureRuleImpl( desc.getNumericOid(), 
657                 desc.getRuleId(), globalRegistries );
658             dsr.setSuperClassRuleIds( desc.getSuperRules().toArray( EMPTY_INT_ARRAY ) );
659             
660             setSchemaObjectProperties( desc, dsr );
661 
662             ditStructureRules[pos++] = dsr;
663         }
664         
665         return ditStructureRules;
666     }
667 
668     
669     /**
670      * Parses a set of dITContentRuleDescriptions held within an attribute into 
671      * schema entities.
672      * 
673      * @param attr the attribute containing dITContentRuleDescriptions
674      * @return the set of DITContentRule objects for the descriptions 
675      * @throws NamingException if there are problems parsing the descriptions
676      */
677     public DITContentRule[] parseDitContentRules( EntryAttribute attr ) throws NamingException
678     {
679         if ( attr == null || attr.size() == 0 )
680         {
681             return EMPTY_DIT_CONTENT_RULES;
682         }
683         
684         DITContentRule[] ditContentRules = new DITContentRule[attr.size()];
685 
686         int pos = 0;
687         
688         for ( Value<?> value:attr )
689         {
690             DITContentRuleDescription desc = null;
691      
692             try
693             {
694                 desc = ditContentRuleParser.parseDITContentRuleDescription( ( String ) value.get() );
695             }
696             catch ( ParseException e )
697             {
698                 LdapInvalidAttributeValueException iave = new LdapInvalidAttributeValueException( 
699                     "The following does not conform to the ditContentRuleDescription syntax: " + value.get(), 
700                     ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX );
701                 iave.setRootCause( e );
702                 throw iave;
703             }
704             
705             DitContentRuleImpl dcr = new DitContentRuleImpl( desc.getNumericOid(), globalRegistries );
706             dcr.setAuxObjectClassOids( desc.getAuxiliaryObjectClasses().toArray( EMPTY ) );
707             dcr.setMayNameOids( desc.getMayAttributeTypes().toArray( EMPTY ) );
708             dcr.setMustNameOids( desc.getMustAttributeTypes().toArray( EMPTY ) );
709             dcr.setNotNameOids( desc.getNotAttributeTypes().toArray( EMPTY ) );
710             
711             setSchemaObjectProperties( desc, dcr );
712 
713             ditContentRules[pos++] = dcr;
714         }
715         
716         return ditContentRules;
717     }
718 
719     
720     /**
721      * Parses a set of nameFormDescriptions held within an attribute into 
722      * schema entities.
723      * 
724      * @param attr the attribute containing nameFormDescriptions
725      * @return the set of NameFormRule objects for the descriptions 
726      * @throws NamingException if there are problems parsing the descriptions
727      */
728     public NameForm[] parseNameForms( EntryAttribute attr ) throws NamingException
729     {
730         if ( attr == null || attr.size() == 0 )
731         {
732             return EMPTY_NAME_FORMS;
733         }
734         
735         NameForm[] nameForms = new NameForm[attr.size()];
736 
737         int pos = 0;
738         
739         for ( Value<?> value:attr )
740         {
741             NameFormDescription desc = null;
742             
743             try
744             {
745                 desc = nameFormParser.parseNameFormDescription( ( String  ) value.get() );
746             }
747             catch ( ParseException e )
748             {
749                 LdapInvalidAttributeValueException iave = new LdapInvalidAttributeValueException( 
750                     "The following does not conform to the nameFormDescription syntax: " + value.get(), 
751                     ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX );
752                 iave.setRootCause( e );
753                 throw iave;
754             }
755             
756             NameFormImpl nf = new NameFormImpl( desc.getNumericOid(), globalRegistries );
757             nf.setMayUseOids( desc.getMayAttributeTypes().toArray( EMPTY ) );
758             nf.setMustUseOids( desc.getMustAttributeTypes().toArray( EMPTY ) );
759             nf.setObjectClassOid( desc.getStructuralObjectClass() );
760             
761             setSchemaObjectProperties( desc, nf );
762             
763             nameForms[pos++] = nf;
764         }
765         
766         return nameForms;
767     }
768     
769     
770     /**
771      * Called to populate the common schema object properties using an abstract 
772      * description object.
773      *   
774      * @param desc the source description object to copy properties from
775      * @param obj the mutable schema object to copy properites to
776      */
777     private void setSchemaObjectProperties( AbstractSchemaDescription desc, MutableSchemaObject obj )
778     {
779         obj.setDescription( desc.getDescription() );
780         obj.setSchema( getSchema( desc ) );
781 
782         if ( ! ( desc instanceof LdapSyntaxDescription ) )
783         {
784             obj.setNames( desc.getNames().toArray( EMPTY ) );
785             obj.setObsolete( desc.isObsolete() );
786         }
787     }
788     
789     
790     /**
791      * Checks to see if the syntax description is human readable by checking 
792      * for the presence of the X-IS-HUMAN_READABLE schema extension.
793      * 
794      * @param desc the ldapSyntaxDescription 
795      * @return true if the syntax is human readable, false otherwise
796      */
797     private boolean isHumanReadable( LdapSyntaxDescription desc )
798     {
799         List<String> values = desc.getExtensions().get( MetaSchemaConstants.X_IS_HUMAN_READABLE );
800         
801         if ( values == null || values.size() == 0 )
802         {
803             return false;
804         }
805         else
806         {
807             String value = values.get( 0 );
808             if ( value.equals( "TRUE" ) )
809             {
810                 return true;
811             }
812             else
813             {
814                 return false;
815             }
816         }
817     }
818     
819     
820     /**
821      * Gets the schema name for the schema description by looking up the value 
822      * of the X-SCHEMA schema extension of the description. 
823      * 
824      * @param desc the schema description 
825      * @return the schema name for the schema entity
826      */
827     private String getSchema( AbstractSchemaDescription desc ) 
828     {
829         List<String> values = desc.getExtensions().get( MetaSchemaConstants.X_SCHEMA );
830         
831         if ( values == null )
832         {
833             return OTHER_SCHEMA;
834         }
835         else 
836         {
837             return values.get( 0 );
838         }
839     }
840 }