001    /*
002     * CDDL HEADER START
003     *
004     * The contents of this file are subject to the terms of the
005     * Common Development and Distribution License, Version 1.0 only
006     * (the "License").  You may not use this file except in compliance
007     * with the License.
008     *
009     * You can obtain a copy of the license at
010     * trunk/opends/resource/legal-notices/OpenDS.LICENSE
011     * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
012     * See the License for the specific language governing permissions
013     * and limitations under the License.
014     *
015     * When distributing Covered Code, include this CDDL HEADER in each
016     * file and include the License file at
017     * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
018     * add the following below this CDDL HEADER, with the fields enclosed
019     * by brackets "[]" replaced with your own identifying information:
020     *      Portions Copyright [yyyy] [name of copyright owner]
021     *
022     * CDDL HEADER END
023     *
024     *
025     *      Copyright 2006-2008 Sun Microsystems, Inc.
026     */
027    package org.opends.server.core;
028    import org.opends.messages.Message;
029    
030    
031    
032    import java.io.File;
033    import java.util.ArrayList;
034    import java.util.Arrays;
035    import java.util.LinkedList;
036    import java.util.List;
037    
038    import org.opends.server.api.ConfigHandler;
039    import org.opends.server.config.ConfigException;
040    import org.opends.server.schema.AttributeTypeSyntax;
041    import org.opends.server.schema.DITContentRuleSyntax;
042    import org.opends.server.schema.DITStructureRuleSyntax;
043    import org.opends.server.schema.MatchingRuleUseSyntax;
044    import org.opends.server.schema.NameFormSyntax;
045    import org.opends.server.schema.ObjectClassSyntax;
046    import org.opends.server.types.Attribute;
047    import org.opends.server.types.AttributeType;
048    import org.opends.server.types.AttributeValue;
049    import org.opends.server.types.DirectoryException;
050    import org.opends.server.types.DITContentRule;
051    import org.opends.server.types.DITStructureRule;
052    import org.opends.server.types.Entry;
053    import org.opends.server.types.InitializationException;
054    import org.opends.server.types.LDIFImportConfig;
055    import org.opends.server.types.MatchingRuleUse;
056    import org.opends.server.types.Modification;
057    import org.opends.server.types.ModificationType;
058    import org.opends.server.types.NameForm;
059    import org.opends.server.types.ObjectClass;
060    import org.opends.server.types.Schema;
061    import org.opends.server.util.LDIFReader;
062    
063    import static org.opends.server.config.ConfigConstants.*;
064    import org.opends.server.types.DebugLogLevel;
065    import static org.opends.server.loggers.debug.DebugLogger.*;
066    import static org.opends.server.loggers.ErrorLogger.*;
067    import org.opends.server.loggers.debug.DebugTracer;
068    import static org.opends.messages.ConfigMessages.*;
069    import static org.opends.server.schema.SchemaConstants.*;
070    import static org.opends.server.util.ServerConstants.*;
071    import static org.opends.server.util.StaticUtils.*;
072    
073    
074    
075    /**
076     * This class defines a utility that will be used to manage the interaction with
077     * the Directory Server schema.  It will be used to initially load all of the
078     * matching rules and attribute syntaxes that have been defined in the
079     * configuration, and will then read the actual schema definitions.  At present,
080     * only attribute types and objectclasses are supported in the schema config
081     * files.  Other components like DIT content rules, DIT structure rules, name
082     * forms, and matching rule use definitions will be ignored.
083     */
084    public class SchemaConfigManager
085    {
086      /**
087       * The tracer object for the debug logger.
088       */
089      private static final DebugTracer TRACER = getTracer();
090    
091      // The schema that has been parsed from the server configuration.
092      private Schema schema;
093    
094      // The configuration handler for the Directory Server.
095      private ConfigHandler configHandler;
096    
097    
098    
099      /**
100       * Creates a new instance of this schema config manager.
101       */
102      public SchemaConfigManager()
103      {
104        configHandler = DirectoryServer.getConfigHandler();
105    
106        schema = new Schema();
107      }
108    
109    
110    
111      /**
112       * Retrieves the path to the directory containing the server schema files.
113       *
114       * @return  The path to the directory containing the server schema files.
115       */
116      public static String getSchemaDirectoryPath()
117      {
118        File schemaDir =
119                  DirectoryServer.getEnvironmentConfig().getSchemaDirectory();
120        if (schemaDir != null) {
121          return schemaDir.getAbsolutePath();
122        } else {
123          return null;
124        }
125      }
126    
127    
128    
129      /**
130       * Retrieves a reference to the schema information that has been read from the
131       * server configuration.  Note that this information will not be complete
132       * until the <CODE>initializeMatchingRules</CODE>,
133       * <CODE>initializeAttributeSyntaxes</CODE>, and
134       * <CODE>initializeAttributeTypesAndObjectClasses</CODE> methods have been
135       * called.
136       *
137       * @return  A reference to the schema information that has been read from the
138       *          server configuration.
139       */
140      public Schema getSchema()
141      {
142        return schema;
143      }
144    
145    
146    
147      /**
148       * Initializes all the matching rules defined in the Directory Server
149       * configuration.  This should only be called at Directory Server startup.
150       *
151       * @throws  ConfigException  If a configuration problem causes the matching
152       *                           rule initialization process to fail.
153       *
154       * @throws  InitializationException  If a problem occurs while initializing
155       *                                   the matching rules that is not related to
156       *                                   the server configuration.
157       */
158      public void initializeMatchingRules()
159             throws ConfigException, InitializationException
160      {
161        MatchingRuleConfigManager matchingRuleConfigManager =
162             new MatchingRuleConfigManager();
163        matchingRuleConfigManager.initializeMatchingRules();
164      }
165    
166    
167    
168      /**
169       * Initializes all the attribute syntaxes defined in the Directory Server
170       * configuration.  This should only be called at Directory Server startup.
171       *
172       * @throws  ConfigException  If a configuration problem causes the syntax
173       *                           initialization process to fail.
174       *
175       * @throws  InitializationException  If a problem occurs while initializing
176       *                                   the syntaxes that is not related to the
177       *                                   server configuration.
178       */
179      public void initializeAttributeSyntaxes()
180             throws ConfigException, InitializationException
181      {
182        AttributeSyntaxConfigManager syntaxConfigManager =
183             new AttributeSyntaxConfigManager();
184        syntaxConfigManager.initializeAttributeSyntaxes();
185      }
186    
187    
188    
189      /**
190       * Initializes all the attribute type, object class, name form, DIT content
191       * rule, DIT structure rule, and matching rule use definitions by reading the
192       * server schema files.  These files will be located in a single directory and
193       * will be processed in lexicographic order.  However, to make the order
194       * easier to understand, they may be prefixed with a two digit number (with a
195       * leading zero if necessary) so that they will be read in numeric order.
196       * This should only be called at Directory Server startup.
197       *
198       * @throws  ConfigException  If a configuration problem causes the schema
199       *                           element initialization to fail.
200       *
201       * @throws  InitializationException  If a problem occurs while initializing
202       *                                   the schema elements that is not related
203       *                                   to the server configuration.
204       */
205      public void initializeSchemaFromFiles()
206             throws ConfigException, InitializationException
207      {
208        // Construct the path to the directory that should contain the schema files
209        // and make sure that it exists and is a directory.  Get a list of the files
210        // in that directory sorted in alphabetic order.
211        String schemaDirPath          = getSchemaDirectoryPath();
212        File schemaDir                = new File(schemaDirPath);
213        long oldestModificationTime   = -1L;
214        long youngestModificationTime = -1L;
215        String[] fileNames;
216    
217        try
218        {
219          if (schemaDirPath == null || ! schemaDir.exists())
220          {
221            Message message = ERR_CONFIG_SCHEMA_NO_SCHEMA_DIR.get(schemaDirPath);
222            throw new InitializationException(message);
223          }
224          else if (! schemaDir.isDirectory())
225          {
226            Message message =
227                ERR_CONFIG_SCHEMA_DIR_NOT_DIRECTORY.get(schemaDirPath);
228            throw new InitializationException(message);
229          }
230    
231          File[] schemaDirFiles = schemaDir.listFiles();
232          ArrayList<String> fileList = new ArrayList<String>(schemaDirFiles.length);
233          for (File f : schemaDirFiles)
234          {
235            if (f.isFile())
236            {
237              fileList.add(f.getName());
238            }
239    
240            long modificationTime = f.lastModified();
241            if ((oldestModificationTime <= 0L) ||
242                (modificationTime < oldestModificationTime))
243            {
244              oldestModificationTime = modificationTime;
245            }
246    
247            if ((youngestModificationTime <= 0) ||
248                (modificationTime > youngestModificationTime))
249            {
250              youngestModificationTime = modificationTime;
251            }
252          }
253    
254          fileNames = new String[fileList.size()];
255          fileList.toArray(fileNames);
256          Arrays.sort(fileNames);
257        }
258        catch (InitializationException ie)
259        {
260          if (debugEnabled())
261          {
262            TRACER.debugCaught(DebugLogLevel.ERROR, ie);
263          }
264    
265          throw ie;
266        }
267        catch (Exception e)
268        {
269          if (debugEnabled())
270          {
271            TRACER.debugCaught(DebugLogLevel.ERROR, e);
272          }
273    
274          Message message = ERR_CONFIG_SCHEMA_CANNOT_LIST_FILES.get(
275              schemaDirPath, getExceptionMessage(e));
276          throw new InitializationException(message, e);
277        }
278    
279    
280        // If the oldest and youngest modification timestamps didn't get set for
281        // some reason, then set them to the current time.
282        if (oldestModificationTime <= 0)
283        {
284          oldestModificationTime = System.currentTimeMillis();
285        }
286    
287        if (youngestModificationTime <= 0)
288        {
289          youngestModificationTime = oldestModificationTime;
290        }
291    
292        schema.setOldestModificationTime(oldestModificationTime);
293        schema.setYoungestModificationTime(youngestModificationTime);
294    
295    
296        // Iterate through the schema files and read them as an LDIF file containing
297        // a single entry.  Then get the attributeTypes and objectClasses attributes
298        // from that entry and parse them to initialize the server schema.
299        for (String schemaFile : fileNames)
300        {
301          loadSchemaFile(schema, schemaFile, false);
302        }
303      }
304    
305    
306    
307      /**
308       * Loads the contents of the specified schema file into the provided schema.
309       *
310       * @param  schema      The schema in which the contents of the schema file are
311       *                     to be loaded.
312       * @param  schemaFile  The name of the schema file to be loaded into the
313       *                     provided schema.
314       *
315       * @return  A list of the modifications that could be performed in order to
316       *          obtain the contents of the file.
317       *
318       * @throws  ConfigException  If a configuration problem causes the schema
319       *                           element initialization to fail.
320       *
321       * @throws  InitializationException  If a problem occurs while initializing
322       *                                   the schema elements that is not related
323       *                                   to the server configuration.
324       */
325      public static List<Modification> loadSchemaFile(Schema schema,
326                                                      String schemaFile)
327             throws ConfigException, InitializationException
328      {
329        return loadSchemaFile(schema, schemaFile, true);
330      }
331    
332    
333    
334      /**
335       * Loads the contents of the specified schema file into the provided schema.
336       *
337       * @param  schema       The schema in which the contents of the schema file
338       *                      are to be loaded.
339       * @param  schemaFile   The name of the schema file to be loaded into the
340       *                      provided schema.
341       * @param  failOnError  If {@code true}, indicates that this method should
342       *                      throw an exception if certain kinds of errors occur.
343       *                      If {@code false}, indicates that this method should
344       *                      log an error message and return without an exception.
345       *                      This should only be {@code false} when called from
346       *                      {@code initializeSchemaFromFiles}.
347       *
348       * @return  A list of the modifications that could be performed in order to
349       *          obtain the contents of the file, or {@code null} if a problem
350       *          occurred and {@code failOnError} is {@code false}.
351       *
352       * @throws  ConfigException  If a configuration problem causes the schema
353       *                           element initialization to fail.
354       *
355       * @throws  InitializationException  If a problem occurs while initializing
356       *                                   the schema elements that is not related
357       *                                   to the server configuration.
358       */
359      private static List<Modification> loadSchemaFile(Schema schema,
360                                                       String schemaFile,
361                                                       boolean failOnError)
362             throws ConfigException, InitializationException
363      {
364        // Create an LDIF reader to use when reading the files.
365        String schemaDirPath = getSchemaDirectoryPath();
366        LDIFReader reader;
367        try
368        {
369          File f = new File(schemaDirPath, schemaFile);
370          reader = new LDIFReader(new LDIFImportConfig(f.getAbsolutePath()));
371        }
372        catch (Exception e)
373        {
374          if (debugEnabled())
375          {
376            TRACER.debugCaught(DebugLogLevel.ERROR, e);
377          }
378    
379          Message message = WARN_CONFIG_SCHEMA_CANNOT_OPEN_FILE.get(
380                  schemaFile, schemaDirPath, getExceptionMessage(e));
381    
382          if (failOnError)
383          {
384            throw new ConfigException(message);
385          }
386          else
387          {
388            logError(message);
389            return null;
390          }
391        }
392    
393    
394        // Read the LDIF entry from the file and close the file.
395        Entry entry;
396        try
397        {
398          entry = reader.readEntry(false);
399    
400          if (entry == null)
401          {
402            // The file was empty -- skip it.
403            reader.close();
404            return new LinkedList<Modification>();
405          }
406        }
407        catch (Exception e)
408        {
409          if (debugEnabled())
410          {
411            TRACER.debugCaught(DebugLogLevel.ERROR, e);
412          }
413    
414          Message message = WARN_CONFIG_SCHEMA_CANNOT_READ_LDIF_ENTRY.get(
415                  schemaFile, schemaDirPath, getExceptionMessage(e));
416    
417          if (failOnError)
418          {
419            throw new InitializationException(message, e);
420          }
421          else
422          {
423            logError(message);
424            return null;
425          }
426        }
427    
428        // If there are any more entries in the file, then print a warning message.
429        try
430        {
431          Entry e = reader.readEntry(false);
432          if (e != null)
433          {
434            Message message = WARN_CONFIG_SCHEMA_MULTIPLE_ENTRIES_IN_FILE.get(
435                schemaFile, schemaDirPath);
436            logError(message);
437          }
438        }
439        catch (Exception e)
440        {
441          if (debugEnabled())
442          {
443            TRACER.debugCaught(DebugLogLevel.ERROR, e);
444          }
445    
446          Message message = WARN_CONFIG_SCHEMA_UNPARSEABLE_EXTRA_DATA_IN_FILE.get(
447              schemaFile, schemaDirPath, getExceptionMessage(e));
448          logError(message);
449        }
450    
451        try
452        {
453          reader.close();
454        }
455        catch (Exception e)
456        {
457          if (debugEnabled())
458          {
459            TRACER.debugCaught(DebugLogLevel.ERROR, e);
460          }
461        }
462    
463    
464        // Get the attributeTypes attribute from the entry.
465        LinkedList<Modification> mods = new LinkedList<Modification>();
466        AttributeTypeSyntax attrTypeSyntax;
467        try
468        {
469          attrTypeSyntax = (AttributeTypeSyntax)
470                           schema.getSyntax(SYNTAX_ATTRIBUTE_TYPE_OID);
471          if (attrTypeSyntax == null)
472          {
473            attrTypeSyntax = new AttributeTypeSyntax();
474            attrTypeSyntax.initializeSyntax(null);
475          }
476        }
477        catch (Exception e)
478        {
479          if (debugEnabled())
480          {
481            TRACER.debugCaught(DebugLogLevel.ERROR, e);
482          }
483    
484          attrTypeSyntax = new AttributeTypeSyntax();
485          attrTypeSyntax.initializeSyntax(null);
486        }
487    
488        AttributeType attributeAttrType =
489             schema.getAttributeType(ATTR_ATTRIBUTE_TYPES_LC);
490        if (attributeAttrType == null)
491        {
492          attributeAttrType =
493               DirectoryServer.getDefaultAttributeType(ATTR_ATTRIBUTE_TYPES,
494                                                       attrTypeSyntax);
495        }
496    
497        List<Attribute> attrList = entry.getAttribute(attributeAttrType);
498        if ((attrList != null) && (! attrList.isEmpty()))
499        {
500          for (Attribute a : attrList)
501          {
502            mods.add(new Modification(ModificationType.ADD, a.duplicate()));
503          }
504        }
505    
506    
507        // Get the objectClasses attribute from the entry.
508        ObjectClassSyntax ocSyntax;
509        try
510        {
511          ocSyntax = (ObjectClassSyntax) schema.getSyntax(SYNTAX_OBJECTCLASS_OID);
512          if (ocSyntax == null)
513          {
514            ocSyntax = new ObjectClassSyntax();
515            ocSyntax.initializeSyntax(null);
516          }
517        }
518        catch (Exception e)
519        {
520          if (debugEnabled())
521          {
522            TRACER.debugCaught(DebugLogLevel.ERROR, e);
523          }
524    
525          ocSyntax = new ObjectClassSyntax();
526          ocSyntax.initializeSyntax(null);
527        }
528    
529        AttributeType objectclassAttrType =
530             schema.getAttributeType(ATTR_OBJECTCLASSES_LC);
531        if (objectclassAttrType == null)
532        {
533          objectclassAttrType =
534               DirectoryServer.getDefaultAttributeType(ATTR_OBJECTCLASSES,
535                                                       ocSyntax);
536        }
537    
538        List<Attribute> ocList = entry.getAttribute(objectclassAttrType);
539        if ((ocList != null) && (! ocList.isEmpty()))
540        {
541          for (Attribute a : ocList)
542          {
543            mods.add(new Modification(ModificationType.ADD, a.duplicate()));
544          }
545        }
546    
547    
548        // Get the name forms attribute from the entry.
549        NameFormSyntax nfSyntax;
550        try
551        {
552          nfSyntax = (NameFormSyntax) schema.getSyntax(SYNTAX_NAME_FORM_OID);
553          if (nfSyntax == null)
554          {
555            nfSyntax = new NameFormSyntax();
556            nfSyntax.initializeSyntax(null);
557          }
558        }
559        catch (Exception e)
560        {
561          if (debugEnabled())
562          {
563            TRACER.debugCaught(DebugLogLevel.ERROR, e);
564          }
565    
566          nfSyntax = new NameFormSyntax();
567          nfSyntax.initializeSyntax(null);
568        }
569    
570        AttributeType nameFormAttrType =
571             schema.getAttributeType(ATTR_NAME_FORMS_LC);
572        if (nameFormAttrType == null)
573        {
574          nameFormAttrType =
575               DirectoryServer.getDefaultAttributeType(ATTR_NAME_FORMS, nfSyntax);
576        }
577    
578        List<Attribute> nfList = entry.getAttribute(nameFormAttrType);
579        if ((nfList != null) && (! nfList.isEmpty()))
580        {
581          for (Attribute a : nfList)
582          {
583            mods.add(new Modification(ModificationType.ADD, a.duplicate()));
584          }
585        }
586    
587    
588        // Get the DIT content rules attribute from the entry.
589        DITContentRuleSyntax dcrSyntax;
590        try
591        {
592          dcrSyntax = (DITContentRuleSyntax)
593                      schema.getSyntax(SYNTAX_DIT_CONTENT_RULE_OID);
594          if (dcrSyntax == null)
595          {
596            dcrSyntax = new DITContentRuleSyntax();
597            dcrSyntax.initializeSyntax(null);
598          }
599        }
600        catch (Exception e)
601        {
602          if (debugEnabled())
603          {
604            TRACER.debugCaught(DebugLogLevel.ERROR, e);
605          }
606    
607          dcrSyntax = new DITContentRuleSyntax();
608          dcrSyntax.initializeSyntax(null);
609        }
610    
611        AttributeType dcrAttrType =
612             schema.getAttributeType(ATTR_DIT_CONTENT_RULES_LC);
613        if (dcrAttrType == null)
614        {
615          dcrAttrType =
616               DirectoryServer.getDefaultAttributeType(ATTR_DIT_CONTENT_RULES,
617                                                       dcrSyntax);
618        }
619    
620        List<Attribute> dcrList = entry.getAttribute(dcrAttrType);
621        if ((dcrList != null) && (! dcrList.isEmpty()))
622        {
623          for (Attribute a : dcrList)
624          {
625            mods.add(new Modification(ModificationType.ADD, a.duplicate()));
626          }
627        }
628    
629    
630        // Get the DIT structure rules attribute from the entry.
631        DITStructureRuleSyntax dsrSyntax;
632        try
633        {
634          dsrSyntax = (DITStructureRuleSyntax)
635                      schema.getSyntax(SYNTAX_DIT_STRUCTURE_RULE_OID);
636          if (dsrSyntax == null)
637          {
638            dsrSyntax = new DITStructureRuleSyntax();
639            dsrSyntax.initializeSyntax(null);
640          }
641        }
642        catch (Exception e)
643        {
644          if (debugEnabled())
645          {
646            TRACER.debugCaught(DebugLogLevel.ERROR, e);
647          }
648    
649          dsrSyntax = new DITStructureRuleSyntax();
650          dsrSyntax.initializeSyntax(null);
651        }
652    
653        AttributeType dsrAttrType =
654             schema.getAttributeType(ATTR_DIT_STRUCTURE_RULES_LC);
655        if (dsrAttrType == null)
656        {
657          dsrAttrType =
658               DirectoryServer.getDefaultAttributeType(ATTR_DIT_STRUCTURE_RULES,
659                                                       dsrSyntax);
660        }
661    
662        List<Attribute> dsrList = entry.getAttribute(dsrAttrType);
663        if ((dsrList != null) && (! dsrList.isEmpty()))
664        {
665          for (Attribute a : dsrList)
666          {
667            mods.add(new Modification(ModificationType.ADD, a.duplicate()));
668          }
669        }
670    
671    
672        // Get the matching rule uses attribute from the entry.
673        MatchingRuleUseSyntax mruSyntax;
674        try
675        {
676          mruSyntax = (MatchingRuleUseSyntax)
677                      schema.getSyntax(SYNTAX_MATCHING_RULE_USE_OID);
678          if (mruSyntax == null)
679          {
680            mruSyntax = new MatchingRuleUseSyntax();
681            mruSyntax.initializeSyntax(null);
682          }
683        }
684        catch (Exception e)
685        {
686          if (debugEnabled())
687          {
688            TRACER.debugCaught(DebugLogLevel.ERROR, e);
689          }
690    
691          mruSyntax = new MatchingRuleUseSyntax();
692          mruSyntax.initializeSyntax(null);
693        }
694    
695        AttributeType mruAttrType =
696             schema.getAttributeType(ATTR_MATCHING_RULE_USE_LC);
697        if (mruAttrType == null)
698        {
699          mruAttrType =
700               DirectoryServer.getDefaultAttributeType(ATTR_MATCHING_RULE_USE,
701                                                       mruSyntax);
702        }
703    
704        List<Attribute> mruList = entry.getAttribute(mruAttrType);
705        if ((mruList != null) && (! mruList.isEmpty()))
706        {
707          for (Attribute a : mruList)
708          {
709            mods.add(new Modification(ModificationType.ADD, a.duplicate()));
710          }
711        }
712    
713        // Loop on all the attribute of the schema entry to
714        // find the extra attribute that shoule be loaded in the Schema.
715        for (Attribute attribute : entry.getAttributes())
716        {
717          if (!isSchemaAttribute(attribute))
718          {
719            schema.addExtraAttribute(attribute.getName(), attribute);
720          }
721        }
722    
723        // Parse the attribute type definitions if there are any.
724        if (attrList != null)
725        {
726          for (Attribute a : attrList)
727          {
728            for (AttributeValue v : a.getValues())
729            {
730              // Parse the attribute type.
731              AttributeType attrType;
732              try
733              {
734                attrType = AttributeTypeSyntax.decodeAttributeType(v.getValue(),
735                                                              schema, false);
736                attrType.setExtraProperty(SCHEMA_PROPERTY_FILENAME, (String) null);
737                attrType.setSchemaFile(schemaFile);
738              }
739              catch (DirectoryException de)
740              {
741                if (debugEnabled())
742                {
743                  TRACER.debugCaught(DebugLogLevel.ERROR, de);
744                }
745    
746                Message message = WARN_CONFIG_SCHEMA_CANNOT_PARSE_ATTR_TYPE.get(
747                        schemaFile, de.getMessageObject());
748    
749                if (failOnError)
750                {
751                  throw new ConfigException(message, de);
752                }
753                else
754                {
755                  logError(message);
756                  continue;
757                }
758              }
759              catch (Exception e)
760              {
761                if (debugEnabled())
762                {
763                  TRACER.debugCaught(DebugLogLevel.ERROR, e);
764                }
765    
766                Message message = WARN_CONFIG_SCHEMA_CANNOT_PARSE_ATTR_TYPE.get(
767                        schemaFile, v.getStringValue() + ":  " +
768                        getExceptionMessage(e));
769                if (failOnError)
770                {
771                  throw new ConfigException(message, e);
772                }
773                else
774                {
775                  logError(message);
776                  continue;
777                }
778              }
779    
780              // Register it with the schema.  We will allow duplicates, with the
781              // later definition overriding any earlier definition, but we want
782              // to trap them and log a warning.
783              try
784              {
785                schema.registerAttributeType(attrType, failOnError);
786              }
787              catch (DirectoryException de)
788              {
789                if (debugEnabled())
790                {
791                  TRACER.debugCaught(DebugLogLevel.ERROR, de);
792                }
793    
794                Message message = WARN_CONFIG_SCHEMA_CONFLICTING_ATTR_TYPE.get(
795                    schemaFile, de.getMessageObject());
796                logError(message);
797    
798                try
799                {
800                  schema.registerAttributeType(attrType, true);
801                }
802                catch (Exception e)
803                {
804                  // This should never happen.
805                  if (debugEnabled())
806                  {
807                    TRACER.debugCaught(DebugLogLevel.ERROR, e);
808                  }
809                }
810              }
811            }
812          }
813        }
814    
815    
816        // Parse the objectclass definitions if there are any.
817        if (ocList != null)
818        {
819          for (Attribute a : ocList)
820          {
821            for (AttributeValue v : a.getValues())
822            {
823              // Parse the objectclass.
824              ObjectClass oc;
825              try
826              {
827                oc =
828                  ObjectClassSyntax.decodeObjectClass(v.getValue(), schema, false);
829                oc.setExtraProperty(SCHEMA_PROPERTY_FILENAME, (String) null);
830                oc.setSchemaFile(schemaFile);
831              }
832              catch (DirectoryException de)
833              {
834                if (debugEnabled())
835                {
836                  TRACER.debugCaught(DebugLogLevel.ERROR, de);
837                }
838    
839                Message message = WARN_CONFIG_SCHEMA_CANNOT_PARSE_OC.get(
840                        schemaFile,
841                        de.getMessageObject());
842    
843                if (failOnError)
844                {
845                  throw new ConfigException(message, de);
846                }
847                else
848                {
849                  logError(message);
850                  continue;
851                }
852              }
853              catch (Exception e)
854              {
855                if (debugEnabled())
856                {
857                  TRACER.debugCaught(DebugLogLevel.ERROR, e);
858                }
859    
860                Message message = WARN_CONFIG_SCHEMA_CANNOT_PARSE_OC.get(
861                        schemaFile,
862                        v.getStringValue() + ":  " + getExceptionMessage(e));
863    
864                if (failOnError)
865                {
866                  throw new ConfigException(message, e);
867                }
868                else
869                {
870                  logError(message);
871                  continue;
872                }
873              }
874    
875              // Register it with the schema.  We will allow duplicates, with the
876              // later definition overriding any earlier definition, but we want
877              // to trap them and log a warning.
878              try
879              {
880                schema.registerObjectClass(oc, failOnError);
881              }
882              catch (DirectoryException de)
883              {
884                if (debugEnabled())
885                {
886                  TRACER.debugCaught(DebugLogLevel.ERROR, de);
887                }
888    
889                Message message = WARN_CONFIG_SCHEMA_CONFLICTING_OC.get(
890                    schemaFile, de.getMessageObject());
891                logError(message);
892    
893                try
894                {
895                  schema.registerObjectClass(oc, true);
896                }
897                catch (Exception e)
898                {
899                  // This should never happen.
900                  if (debugEnabled())
901                  {
902                    TRACER.debugCaught(DebugLogLevel.ERROR, e);
903                  }
904                }
905              }
906            }
907          }
908        }
909    
910    
911        // Parse the name form definitions if there are any.
912        if (nfList != null)
913        {
914          for (Attribute a : nfList)
915          {
916            for (AttributeValue v : a.getValues())
917            {
918              // Parse the name form.
919              NameForm nf;
920              try
921              {
922                nf = NameFormSyntax.decodeNameForm(v.getValue(), schema, false);
923                nf.getExtraProperties().remove(SCHEMA_PROPERTY_FILENAME);
924                nf.setSchemaFile(schemaFile);
925              }
926              catch (DirectoryException de)
927              {
928                if (debugEnabled())
929                {
930                  TRACER.debugCaught(DebugLogLevel.ERROR, de);
931                }
932    
933                Message message = WARN_CONFIG_SCHEMA_CANNOT_PARSE_NAME_FORM.get(
934                        schemaFile, de.getMessageObject());
935                if (failOnError)
936                {
937                  throw new ConfigException(message, de);
938                }
939                else
940                {
941                  logError(message);
942                  continue;
943                }
944              }
945              catch (Exception e)
946              {
947                if (debugEnabled())
948                {
949                  TRACER.debugCaught(DebugLogLevel.ERROR, e);
950                }
951    
952                Message message = WARN_CONFIG_SCHEMA_CANNOT_PARSE_NAME_FORM.get(
953                        schemaFile,  v.getStringValue() + ":  " +
954                        getExceptionMessage(e));
955    
956                if (failOnError)
957                {
958                  throw new ConfigException(message, e);
959                }
960                else
961                {
962                  logError(message);
963                  continue;
964                }
965              }
966    
967              // Register it with the schema.  We will allow duplicates, with the
968              // later definition overriding any earlier definition, but we want
969              // to trap them and log a warning.
970              try
971              {
972                schema.registerNameForm(nf, failOnError);
973              }
974              catch (DirectoryException de)
975              {
976                if (debugEnabled())
977                {
978                  TRACER.debugCaught(DebugLogLevel.ERROR, de);
979                }
980    
981                Message message = WARN_CONFIG_SCHEMA_CONFLICTING_NAME_FORM.get(
982                    schemaFile, de.getMessageObject());
983                logError(message);
984    
985                try
986                {
987                  schema.registerNameForm(nf, true);
988                }
989                catch (Exception e)
990                {
991                  // This should never happen.
992                  if (debugEnabled())
993                  {
994                    TRACER.debugCaught(DebugLogLevel.ERROR, e);
995                  }
996                }
997              }
998            }
999          }
1000        }
1001    
1002    
1003        // Parse the DIT content rule definitions if there are any.
1004        if (dcrList != null)
1005        {
1006          for (Attribute a : dcrList)
1007          {
1008            for (AttributeValue v : a.getValues())
1009            {
1010              // Parse the DIT content rule.
1011              DITContentRule dcr;
1012              try
1013              {
1014                dcr = DITContentRuleSyntax.decodeDITContentRule(
1015                    v.getValue(), schema, false);
1016                dcr.getExtraProperties().remove(SCHEMA_PROPERTY_FILENAME);
1017                dcr.setSchemaFile(schemaFile);
1018              }
1019              catch (DirectoryException de)
1020              {
1021                if (debugEnabled())
1022                {
1023                  TRACER.debugCaught(DebugLogLevel.ERROR, de);
1024                }
1025    
1026                Message message = WARN_CONFIG_SCHEMA_CANNOT_PARSE_DCR.get(
1027                        schemaFile, de.getMessageObject());
1028    
1029                if (failOnError)
1030                {
1031                  throw new ConfigException(message, de);
1032                }
1033                else
1034                {
1035                  logError(message);
1036                  continue;
1037                }
1038              }
1039              catch (Exception e)
1040              {
1041                if (debugEnabled())
1042                {
1043                  TRACER.debugCaught(DebugLogLevel.ERROR, e);
1044                }
1045    
1046                Message message = WARN_CONFIG_SCHEMA_CANNOT_PARSE_DCR.get(
1047                        schemaFile,v.getStringValue() + ":  " +
1048                        getExceptionMessage(e));
1049    
1050                if (failOnError)
1051                {
1052                  throw new ConfigException(message, e);
1053                }
1054                else
1055                {
1056                  logError(message);
1057                  continue;
1058                }
1059              }
1060    
1061              // Register it with the schema.  We will allow duplicates, with the
1062              // later definition overriding any earlier definition, but we want
1063              // to trap them and log a warning.
1064              try
1065              {
1066                schema.registerDITContentRule(dcr, failOnError);
1067              }
1068              catch (DirectoryException de)
1069              {
1070                if (debugEnabled())
1071                {
1072                  TRACER.debugCaught(DebugLogLevel.ERROR, de);
1073                }
1074    
1075                Message message = WARN_CONFIG_SCHEMA_CONFLICTING_DCR.get(
1076                    schemaFile, de.getMessageObject());
1077                logError(message);
1078    
1079                try
1080                {
1081                  schema.registerDITContentRule(dcr, true);
1082                }
1083                catch (Exception e)
1084                {
1085                  // This should never happen.
1086                  if (debugEnabled())
1087                  {
1088                    TRACER.debugCaught(DebugLogLevel.ERROR, e);
1089                  }
1090                }
1091              }
1092            }
1093          }
1094        }
1095    
1096    
1097        // Parse the DIT structure rule definitions if there are any.
1098        if (dsrList != null)
1099        {
1100          for (Attribute a : dsrList)
1101          {
1102            for (AttributeValue v : a.getValues())
1103            {
1104              // Parse the DIT content rule.
1105              DITStructureRule dsr;
1106              try
1107              {
1108                dsr = DITStructureRuleSyntax.decodeDITStructureRule(
1109                    v.getValue(), schema, false);
1110                dsr.getExtraProperties().remove(SCHEMA_PROPERTY_FILENAME);
1111                dsr.setSchemaFile(schemaFile);
1112              }
1113              catch (DirectoryException de)
1114              {
1115                if (debugEnabled())
1116                {
1117                  TRACER.debugCaught(DebugLogLevel.ERROR, de);
1118                }
1119    
1120                Message message = WARN_CONFIG_SCHEMA_CANNOT_PARSE_DSR.get(
1121                        schemaFile, de.getMessageObject());
1122    
1123                if (failOnError)
1124                {
1125                  throw new ConfigException(message, de);
1126                }
1127                else
1128                {
1129                  logError(message);
1130                  continue;
1131                }
1132              }
1133              catch (Exception e)
1134              {
1135                if (debugEnabled())
1136                {
1137                  TRACER.debugCaught(DebugLogLevel.ERROR, e);
1138                }
1139    
1140                Message message = WARN_CONFIG_SCHEMA_CANNOT_PARSE_DSR.get(
1141                        schemaFile, v.getStringValue() + ":  " +
1142                                            getExceptionMessage(e));
1143    
1144                if (failOnError)
1145                {
1146                  throw new ConfigException(message, e);
1147                }
1148                else
1149                {
1150                  logError(message);
1151                  continue;
1152                }
1153              }
1154    
1155              // Register it with the schema.  We will allow duplicates, with the
1156              // later definition overriding any earlier definition, but we want
1157              // to trap them and log a warning.
1158              try
1159              {
1160                schema.registerDITStructureRule(dsr, failOnError);
1161              }
1162              catch (DirectoryException de)
1163              {
1164                if (debugEnabled())
1165                {
1166                  TRACER.debugCaught(DebugLogLevel.ERROR, de);
1167                }
1168    
1169                Message message = WARN_CONFIG_SCHEMA_CONFLICTING_DSR.get(
1170                    schemaFile, de.getMessageObject());
1171                logError(message);
1172    
1173                try
1174                {
1175                  schema.registerDITStructureRule(dsr, true);
1176                }
1177                catch (Exception e)
1178                {
1179                  // This should never happen.
1180                  if (debugEnabled())
1181                  {
1182                    TRACER.debugCaught(DebugLogLevel.ERROR, e);
1183                  }
1184                }
1185              }
1186            }
1187          }
1188        }
1189    
1190    
1191        // Parse the matching rule use definitions if there are any.
1192        if (mruList != null)
1193        {
1194          for (Attribute a : mruList)
1195          {
1196            for (AttributeValue v : a.getValues())
1197            {
1198              // Parse the matching rule use definition.
1199              MatchingRuleUse mru;
1200              try
1201              {
1202                mru = MatchingRuleUseSyntax.decodeMatchingRuleUse(
1203                                v.getValue(), schema, false);
1204                mru.getExtraProperties().remove(SCHEMA_PROPERTY_FILENAME);
1205                mru.setSchemaFile(schemaFile);
1206              }
1207              catch (DirectoryException de)
1208              {
1209                if (debugEnabled())
1210                {
1211                  TRACER.debugCaught(DebugLogLevel.ERROR, de);
1212                }
1213    
1214                Message message = WARN_CONFIG_SCHEMA_CANNOT_PARSE_MRU.get(
1215                        schemaFile, de.getMessageObject());
1216    
1217                if (failOnError)
1218                {
1219                  throw new ConfigException(message, de);
1220                }
1221                else
1222                {
1223                  logError(message);
1224                  continue;
1225                }
1226              }
1227              catch (Exception e)
1228              {
1229                if (debugEnabled())
1230                {
1231                  TRACER.debugCaught(DebugLogLevel.ERROR, e);
1232                }
1233    
1234                Message message = WARN_CONFIG_SCHEMA_CANNOT_PARSE_MRU.get(
1235                        schemaFile,
1236                        v.getStringValue() + ":  " +
1237                        getExceptionMessage(e));
1238    
1239                if (failOnError)
1240                {
1241                  throw new ConfigException(message, e);
1242                }
1243                else
1244                {
1245                  logError(message);
1246                  continue;
1247                }
1248              }
1249    
1250              // Register it with the schema.  We will allow duplicates, with the
1251              // later definition overriding any earlier definition, but we want
1252              // to trap them and log a warning.
1253              try
1254              {
1255                schema.registerMatchingRuleUse(mru, failOnError);
1256              }
1257              catch (DirectoryException de)
1258              {
1259                if (debugEnabled())
1260                {
1261                  TRACER.debugCaught(DebugLogLevel.ERROR, de);
1262                }
1263    
1264                Message message = WARN_CONFIG_SCHEMA_CONFLICTING_MRU.get(
1265                    schemaFile, de.getMessageObject());
1266                logError(message);
1267    
1268                try
1269                {
1270                  schema.registerMatchingRuleUse(mru, true);
1271                }
1272                catch (Exception e)
1273                {
1274                  // This should never happen.
1275                  if (debugEnabled())
1276                  {
1277                    TRACER.debugCaught(DebugLogLevel.ERROR, e);
1278                  }
1279                }
1280              }
1281            }
1282          }
1283        }
1284    
1285    
1286        return mods;
1287      }
1288    
1289    
1290    
1291      /**
1292       * This method checks if a given attribute is an attribute that
1293       * is used by the definition of the schema.
1294       *
1295       * @param attribute   The attribute to be checked.
1296       * @return            true if the attribute is part of the schema definition,
1297       *                    false if the attribute is not part of the schema
1298       *                    definition.
1299       */
1300      private static boolean isSchemaAttribute(Attribute attribute)
1301      {
1302        String attributeOid = attribute.getAttributeType().getOID();
1303        if (attributeOid.equals("2.5.21.1") ||
1304            attributeOid.equals("2.5.21.2") ||
1305            attributeOid.equals("2.5.21.4") ||
1306            attributeOid.equals("2.5.21.5") ||
1307            attributeOid.equals("2.5.21.6") ||
1308            attributeOid.equals("2.5.21.7") ||
1309            attributeOid.equals("2.5.21.8") ||
1310            attributeOid.equals("2.5.4.3")  ||
1311            attributeOid.equals("attributetypes-oid")      ||
1312            attributeOid.equals("objectclasses-oid")       ||
1313            attributeOid.equals("matchingRules-oid")       ||
1314            attributeOid.equals("matchingRuleUse-oid")     ||
1315            attributeOid.equals("NameFormDescription-oid") ||
1316            attributeOid.equals("dITContentRules-oid")     ||
1317            attributeOid.equals("dITStructureRules")
1318            )
1319        {
1320          return true;
1321        }
1322        else
1323        {
1324          return false;
1325        }
1326      }
1327    }
1328