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 legal-notices/CDDLv1_0.txt
010 * or http://forgerock.org/license/CDDLv1.0.html.
011 * See the License for the specific language governing permissions
012 * and limitations under the License.
013 *
014 * When distributing Covered Code, include this CDDL HEADER in each
015 * file and include the License file at legal-notices/CDDLv1_0.txt.
016 * If applicable, add the following below this CDDL HEADER, with the
017 * fields enclosed by brackets "[]" replaced with your own identifying
018 * information:
019 *      Portions Copyright [yyyy] [name of copyright owner]
020 *
021 * CDDL HEADER END
022 *
023 *
024 *      Copyright 2014 ForgeRock AS.
025 *      Portions Copyright 2014-2015 ForgeRock AS
026 */
027package org.opends.server.schema;
028
029import static org.forgerock.opendj.ldap.schema.SchemaOptions.*;
030
031import java.util.List;
032
033import org.forgerock.i18n.LocalizableMessage;
034import org.forgerock.opendj.config.server.ConfigChangeResult;
035import org.forgerock.opendj.config.server.ConfigException;
036import org.forgerock.opendj.config.server.ConfigurationChangeListener;
037import org.forgerock.opendj.ldap.ResultCode;
038import org.forgerock.opendj.ldap.schema.SchemaBuilder;
039import org.forgerock.opendj.server.config.server.CoreSchemaCfg;
040import org.opends.server.types.InitializationException;
041
042/**
043 * Provides the core schema, which includes core matching rules and syntaxes.
044 */
045public class CoreSchemaProvider implements SchemaProvider<CoreSchemaCfg>,
046  ConfigurationChangeListener<CoreSchemaCfg>
047{
048  private static final String NONE_ELEMENT = "NONE";
049
050  /** The current configuration of core schema. */
051  private CoreSchemaCfg currentConfig;
052
053  /** The current schema builder. */
054  private SchemaBuilder currentSchemaBuilder;
055
056  /** Updater to notify schema update when configuration changes. */
057  private SchemaUpdater schemaUpdater;
058
059  /** {@inheritDoc} */
060  @Override
061  public void initialize(final CoreSchemaCfg configuration, final SchemaBuilder initialSchemaBuilder,
062      final SchemaUpdater schemaUpdater) throws ConfigException, InitializationException
063  {
064    this.currentConfig = configuration;
065    this.currentSchemaBuilder = initialSchemaBuilder;
066    this.schemaUpdater = schemaUpdater;
067
068    updateSchemaFromConfiguration(initialSchemaBuilder, configuration);
069
070    currentConfig.addCoreSchemaChangeListener(this);
071  }
072
073  /**
074   * Update the provided schema builder with the provided configuration.
075   *
076   * @param schemaBuilder
077   *          The schema builder to update.
078   * @param configuration
079   *          The configuration to use for update.
080   */
081  private void updateSchemaFromConfiguration(final SchemaBuilder schemaBuilder, final CoreSchemaCfg configuration)
082  {
083    schemaBuilder
084      .setOption(ALLOW_ZERO_LENGTH_DIRECTORY_STRINGS, configuration.isAllowZeroLengthValuesDirectoryString())
085      .setOption(STRICT_FORMAT_FOR_COUNTRY_STRINGS, configuration.isStrictFormatCountryString())
086      .setOption(STRIP_UPPER_BOUND_FOR_ATTRIBUTE_TYPE,
087          configuration.isStripSyntaxMinUpperBoundAttributeTypeDescription());
088    // TODO : add the missing methods in schema builder for those properties
089    // schemaBuilder.allowMalformedJPEGPhotos(configuration.)
090    // schemaBuilder.allowMalformedNamesAndOptions(configuration.)
091    // ...
092
093    for (final String oid : configuration.getDisabledMatchingRule())
094    {
095      if (!oid.equals(NONE_ELEMENT))
096      {
097        schemaBuilder.removeMatchingRule(oid);
098      }
099    }
100
101    for (final String oid : configuration.getDisabledSyntax())
102    {
103      if (!oid.equals(NONE_ELEMENT))
104      {
105        schemaBuilder.removeSyntax(oid);
106      }
107    }
108  }
109
110  /** {@inheritDoc} */
111  @Override
112  public void finalizeProvider()
113  {
114    currentConfig.removeCoreSchemaChangeListener(this);
115  }
116
117  /** {@inheritDoc} */
118  @Override
119  public boolean isConfigurationAcceptable(final CoreSchemaCfg configuration,
120      final List<LocalizableMessage> unacceptableReasons)
121  {
122    // TODO : check that elements to disable are present in the schema ?
123    return true;
124  }
125
126  /** {@inheritDoc} */
127  @Override
128  public SchemaBuilder getSchema()
129  {
130    return currentSchemaBuilder;
131  }
132
133  /** {@inheritDoc} */
134  @Override
135  public boolean isConfigurationChangeAcceptable(final CoreSchemaCfg configuration,
136      final List<LocalizableMessage> unacceptableReasons)
137  {
138    if (!configuration.isEnabled())
139    {
140      // TODO : fix message
141      unacceptableReasons.add(LocalizableMessage.raw("The core schema must always be enabled"));
142      return false;
143    }
144    // TODO : check that elements to disable are present in the schema ?
145    return true;
146  }
147
148  /** {@inheritDoc} */
149  @Override
150  public ConfigChangeResult applyConfigurationChange(final CoreSchemaCfg configuration)
151  {
152    currentSchemaBuilder = schemaUpdater.getSchemaBuilder();
153
154    updateSchemaFromConfiguration(currentSchemaBuilder, configuration);
155
156    final boolean isUpdated = schemaUpdater.updateSchema(currentSchemaBuilder.toSchema());
157
158    // TODO : fix result code + log an error in case of failure
159    final ConfigChangeResult result = new ConfigChangeResult();
160    result.setResultCode(isUpdated ? ResultCode.SUCCESS : ResultCode.OTHER);
161    return result;
162  }
163
164}