001/*
002 * The contents of this file are subject to the terms of the Common Development and
003 * Distribution License (the License). You may not use this file except in compliance with the
004 * License.
005 *
006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
007 * specific language governing permission and limitations under the License.
008 *
009 * When distributing Covered Software, include this CDDL Header Notice in each file and include
010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
011 * Header, with the fields enclosed by brackets [] replaced by your own identifying
012 * information: "Portions Copyright [year] [name of copyright owner]".
013 *
014 * Copyright 2008-2010 Sun Microsystems, Inc.
015 * Portions Copyright 2013-2016 ForgeRock AS.
016 */
017package org.opends.guitools.controlpanel.util;
018
019import static org.opends.messages.ConfigMessages.*;
020
021import java.io.File;
022import java.io.FileFilter;
023import java.util.ArrayList;
024import java.util.Arrays;
025import java.util.List;
026
027import org.forgerock.i18n.LocalizableMessage;
028import org.forgerock.i18n.LocalizedIllegalArgumentException;
029import org.forgerock.opendj.config.server.ConfigException;
030import org.forgerock.opendj.ldap.ResultCode;
031import org.forgerock.opendj.ldap.schema.AttributeType;
032import org.forgerock.opendj.ldap.schema.MatchingRule;
033import org.forgerock.opendj.ldap.schema.SchemaBuilder;
034import org.forgerock.opendj.ldap.schema.Syntax;
035import org.opends.server.config.ConfigConstants;
036import org.opends.server.core.DirectoryServer;
037import org.opends.server.core.SchemaConfigManager;
038import org.opends.server.schema.SchemaConstants;
039import org.opends.server.types.DirectoryException;
040import org.opends.server.types.InitializationException;
041import org.opends.server.types.ObjectClass;
042import org.opends.server.types.Schema;
043
044import com.forgerock.opendj.util.OperatingSystem;
045
046/** Class used to retrieve the schema from the schema files. */
047public class SchemaLoader
048{
049  private Schema schema;
050  private static final String[] ATTRIBUTES_TO_KEEP = {
051    ConfigConstants.ATTR_ATTRIBUTE_TYPES_LC,
052    ConfigConstants.ATTR_OBJECTCLASSES_LC,
053    ConfigConstants.ATTR_NAME_FORMS_LC,
054    ConfigConstants.ATTR_DIT_CONTENT_RULES_LC,
055    ConfigConstants.ATTR_DIT_STRUCTURE_RULES_LC,
056    ConfigConstants.ATTR_MATCHING_RULE_USE_LC };
057  private static final String[] OBJECTCLASS_TO_KEEP = { SchemaConstants.TOP_OBJECTCLASS_NAME };
058
059  private final List<ObjectClass> objectclassesToKeep = new ArrayList<>();
060  private final List<AttributeType> attributesToKeep = new ArrayList<>();
061  /** List of matching rules to keep in the schema. */
062  protected final List<MatchingRule> matchingRulesToKeep = new ArrayList<>();
063  /** List of attribute syntaxes to keep in the schema. */
064  protected final List<Syntax> syntaxesToKeep = new ArrayList<>();
065
066  /** Constructor. */
067  public SchemaLoader()
068  {
069    Schema sc = DirectoryServer.getSchema();
070    for (String name : OBJECTCLASS_TO_KEEP)
071    {
072      ObjectClass oc = sc.getObjectClass(name.toLowerCase());
073      if (oc != null)
074      {
075        objectclassesToKeep.add(oc);
076      }
077    }
078    for (String name : ATTRIBUTES_TO_KEEP)
079    {
080      if (sc.hasAttributeType(name))
081      {
082        attributesToKeep.add(sc.getAttributeType(name));
083      }
084    }
085    matchingRulesToKeep.addAll(sc.getMatchingRules());
086    syntaxesToKeep.addAll(sc.getSyntaxes());
087  }
088
089  private static String getSchemaDirectoryPath()
090  {
091    File schemaDir = DirectoryServer.getEnvironmentConfig().getSchemaDirectory();
092    return schemaDir != null ? schemaDir.getAbsolutePath() : null;
093  }
094
095  /**
096   * Reads the schema.
097   *
098   * @throws ConfigException
099   *           if an error occurs reading the schema.
100   * @throws InitializationException
101   *           if an error occurs trying to find out the schema files.
102   * @throws DirectoryException
103   *           if there is an error registering the minimal objectclasses.
104   */
105  public void readSchema() throws DirectoryException, ConfigException, InitializationException
106  {
107    schema = getBaseSchema();
108
109    String[] fileNames;
110    String schemaDirPath = getSchemaDirectoryPath();
111    try
112    {
113      // Load install directory schema
114      File schemaDir = new File(schemaDirPath);
115      if (schemaDirPath == null || !schemaDir.exists())
116      {
117        LocalizableMessage message = ERR_CONFIG_SCHEMA_NO_SCHEMA_DIR.get(schemaDirPath);
118        throw new InitializationException(message);
119      }
120      else if (!schemaDir.isDirectory())
121      {
122        LocalizableMessage message = ERR_CONFIG_SCHEMA_DIR_NOT_DIRECTORY.get(schemaDirPath);
123        throw new InitializationException(message);
124      }
125      FileFilter ldifFilesFilter = new FileFilter()
126      {
127        @Override
128        public boolean accept(File f)
129        {
130          if (f != null)
131          {
132            if (f.isDirectory())
133            {
134              return true;
135            }
136            return OperatingSystem.isWindows() ? f.getName().toLowerCase().endsWith(".ldif")
137                                               : f.getName().endsWith(".ldif");
138          }
139          return false;
140        }
141      };
142      File[] schemaFiles = schemaDir.listFiles(ldifFilesFilter);
143      List<String> fileList = new ArrayList<>(schemaFiles.length);
144      for (File f : schemaFiles)
145      {
146        if (f.isFile())
147        {
148          fileList.add(f.getName());
149        }
150      }
151
152      fileNames = new String[fileList.size()];
153      fileList.toArray(fileNames);
154      Arrays.sort(fileNames);
155    }
156    catch (InitializationException ie)
157    {
158      throw ie;
159    }
160    catch (Exception e)
161    {
162      throw new InitializationException(ERR_CONFIG_SCHEMA_CANNOT_LIST_FILES.get(schemaDirPath, e.getMessage()), e);
163    }
164
165    //  Iterate through the schema files and read them as an LDIF file
166    //  containing a single entry.  Then get the attributeTypes and
167    //  objectClasses attributes from that entry and parse them to
168    //  initialize the server schema.
169    for (String schemaFile : fileNames)
170    {
171      SchemaConfigManager.loadSchemaFile(schema, schemaFile);
172    }
173  }
174
175  /**
176   * Returns a basic version of the schema. The schema is created and contains
177   * enough definitions for the schema to be loaded.
178   *
179   * @return a basic version of the schema.
180   * @throws DirectoryException
181   *           if there is an error registering the minimal objectclasses.
182   */
183  protected Schema getBaseSchema() throws DirectoryException
184  {
185    try
186    {
187      SchemaBuilder builder = new SchemaBuilder(org.forgerock.opendj.ldap.schema.Schema.getDefaultSchema());
188      for (Syntax syntax : syntaxesToKeep)
189      {
190        builder.buildSyntax(syntax).addToSchemaOverwrite();
191      }
192      for (MatchingRule mr : matchingRulesToKeep)
193      {
194        builder.buildMatchingRule(mr).addToSchemaOverwrite();
195      }
196      for (AttributeType attr : attributesToKeep)
197      {
198        builder.buildAttributeType(attr).addToSchemaOverwrite();
199      }
200      Schema schema = new Schema(builder.toSchema());
201      for (ObjectClass oc : objectclassesToKeep)
202      {
203        schema.registerObjectClass(oc, true);
204      }
205      return schema;
206    }
207    catch (LocalizedIllegalArgumentException e)
208    {
209      throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, e.getMessageObject(), e);
210    }
211  }
212
213  /**
214   * Returns the schema that was read.
215   *
216   * @return the schema that was read.
217   */
218  public Schema getSchema()
219  {
220    return schema;
221  }
222}