From 9d44e6062ba56524e5d7738808044f00349d6738 Mon Sep 17 00:00:00 2001
From: Nicolas Capponi <nicolas.capponi@forgerock.com>
Date: Fri, 09 Sep 2016 09:45:23 +0000
Subject: [PATCH] OPENDJ-3089 OPENDJ-1237 Move code from Schema and SchemaBackend to SchemaUtils and new class SchemaWriter
---
opendj-server-legacy/src/main/java/org/opends/server/core/SchemaHandler.java | 239 ---------
opendj-server-legacy/src/main/java/org/opends/server/util/SchemaUtils.java | 250 +++++++++
opendj-server-legacy/src/main/java/org/opends/server/backends/SchemaBackend.java | 158 +----
opendj-server-legacy/src/main/java/org/opends/server/tools/upgrade/UpgradeTasks.java | 5
opendj-server-legacy/src/main/java/org/opends/server/types/SchemaWriter.java | 486 ++++++++++++++++++
opendj-server-legacy/src/main/java/org/opends/server/tasks/AddSchemaFileTask.java | 6
opendj-server-legacy/src/main/java/org/opends/server/types/Schema.java | 374 --------------
7 files changed, 772 insertions(+), 746 deletions(-)
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/backends/SchemaBackend.java b/opendj-server-legacy/src/main/java/org/opends/server/backends/SchemaBackend.java
index 67039d5..3507117 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/backends/SchemaBackend.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/backends/SchemaBackend.java
@@ -42,7 +42,6 @@
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
-import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
@@ -104,13 +103,13 @@
import org.opends.server.types.Modification;
import org.opends.server.types.Privilege;
import org.opends.server.types.RestoreConfig;
-import org.opends.server.types.Schema;
+import org.opends.server.types.SchemaWriter;
import org.opends.server.types.SearchFilter;
import org.opends.server.util.BackupManager;
-import org.opends.server.util.BuildVersion;
import org.opends.server.util.LDIFException;
import org.opends.server.util.LDIFReader;
import org.opends.server.util.LDIFWriter;
+import org.opends.server.util.SchemaUtils;
import org.opends.server.util.StaticUtils;
/**
@@ -241,109 +240,12 @@
}
}
- updateConcatenatedSchema();
+ SchemaWriter.updateConcatenatedSchema();
// Register with the Directory Server as a configurable component.
currentConfig.addSchemaChangeListener(this);
}
- /**
- * Updates the concatenated schema if changes are detected in the current schema files.
- * <p>
- * Identify any differences that may exist between the concatenated schema file from the last
- * online modification and the current schema files. If there are any differences, then they
- * should be from making changes to the schema files with the server offline.
- */
- private void updateConcatenatedSchema() throws InitializationException
- {
- try
- {
- // First, generate lists of elements from the current schema.
- Set<String> newATs = new LinkedHashSet<>();
- Set<String> newOCs = new LinkedHashSet<>();
- Set<String> newNFs = new LinkedHashSet<>();
- Set<String> newDCRs = new LinkedHashSet<>();
- Set<String> newDSRs = new LinkedHashSet<>();
- Set<String> newMRUs = new LinkedHashSet<>();
- Set<String> newLSs = new LinkedHashSet<>();
- Schema.genConcatenatedSchema(newATs, newOCs, newNFs, newDCRs, newDSRs, newMRUs, newLSs);
-
- // Next, generate lists of elements from the previous concatenated schema.
- // If there isn't a previous concatenated schema, then use the base
- // schema for the current revision.
- File concatFile = getConcatFile();
-
- Set<String> oldATs = new LinkedHashSet<>();
- Set<String> oldOCs = new LinkedHashSet<>();
- Set<String> oldNFs = new LinkedHashSet<>();
- Set<String> oldDCRs = new LinkedHashSet<>();
- Set<String> oldDSRs = new LinkedHashSet<>();
- Set<String> oldMRUs = new LinkedHashSet<>();
- Set<String> oldLSs = new LinkedHashSet<>();
- Schema.readConcatenatedSchema(concatFile, oldATs, oldOCs, oldNFs,
- oldDCRs, oldDSRs, oldMRUs,oldLSs);
-
- // Create a list of modifications and add any differences between the old
- // and new schema into them.
- List<Modification> mods = new LinkedList<>();
- Schema.compareConcatenatedSchema(oldATs, newATs, attributeTypesType, mods);
- Schema.compareConcatenatedSchema(oldOCs, newOCs, objectClassesType, mods);
- Schema.compareConcatenatedSchema(oldNFs, newNFs, nameFormsType, mods);
- Schema.compareConcatenatedSchema(oldDCRs, newDCRs, ditContentRulesType, mods);
- Schema.compareConcatenatedSchema(oldDSRs, newDSRs, ditStructureRulesType, mods);
- Schema.compareConcatenatedSchema(oldMRUs, newMRUs, matchingRuleUsesType, mods);
- Schema.compareConcatenatedSchema(oldLSs, newLSs, ldapSyntaxesType, mods);
- if (! mods.isEmpty())
- {
- // TODO : Raise an alert notification.
-
- DirectoryServer.setOfflineSchemaChanges(mods);
-
- // Write a new concatenated schema file with the most recent information
- // so we don't re-find these same changes on the next startup.
- Schema.writeConcatenatedSchema();
- }
- }
- catch (InitializationException ie)
- {
- throw ie;
- }
- catch (Exception e)
- {
- logger.traceException(e);
-
- logger.error(ERR_SCHEMA_ERROR_DETERMINING_SCHEMA_CHANGES, getExceptionMessage(e));
- }
- }
-
- private File getConcatFile() throws InitializationException
- {
- File configDirectory = new File(DirectoryServer.getConfigFile()).getParentFile();
- File upgradeDirectory = new File(configDirectory, "upgrade");
- File concatFile = new File(upgradeDirectory, SCHEMA_CONCAT_FILE_NAME);
- if (concatFile.exists())
- {
- return concatFile.getAbsoluteFile();
- }
-
- String fileName = SCHEMA_BASE_FILE_NAME_WITHOUT_REVISION + BuildVersion.instanceVersion().getRevision();
- concatFile = new File(upgradeDirectory, fileName);
- if (concatFile.exists())
- {
- return concatFile.getAbsoluteFile();
- }
-
- String runningUnitTestsStr = System.getProperty(PROPERTY_RUNNING_UNIT_TESTS);
- if ("true".equalsIgnoreCase(runningUnitTestsStr))
- {
- Schema.writeConcatenatedSchema();
- concatFile = new File(upgradeDirectory, SCHEMA_CONCAT_FILE_NAME);
- return concatFile.getAbsoluteFile();
- }
- throw new InitializationException(ERR_SCHEMA_CANNOT_FIND_CONCAT_FILE.get(
- upgradeDirectory.getAbsolutePath(), SCHEMA_CONCAT_FILE_NAME, concatFile.getName()));
- }
-
@Override
public void closeBackend()
{
@@ -949,7 +851,7 @@
// Create a single file with all of the concatenated schema information
// that we can use on startup to detect whether the schema files have been
// edited with the server offline.
- Schema.writeConcatenatedSchema();
+ SchemaWriter.writeConcatenatedSchema();
}
/**
@@ -973,7 +875,7 @@
throws DirectoryException
{
org.forgerock.opendj.ldap.schema.Schema currentSchema = schemaHandler.getSchema();
- String oid = SchemaHandler.parseAttributeTypeOID(definition);
+ String oid = SchemaUtils.parseAttributeTypeOID(definition);
final String finalDefinition;
if (!currentSchema.hasAttributeType(oid))
{
@@ -994,10 +896,10 @@
private String completeDefinitionWhenAddingSchemaElement(String definition, Set<String> modifiedSchemaFiles)
throws DirectoryException
{
- String givenSchemaFile = SchemaHandler.parseSchemaFileFromElementDefinition(definition);
+ String givenSchemaFile = SchemaUtils.parseSchemaFileFromElementDefinition(definition);
String finalSchemaFile = givenSchemaFile == null ? FILE_USER_SCHEMA_ELEMENTS : givenSchemaFile;
modifiedSchemaFiles.add(finalSchemaFile);
- return SchemaHandler.addSchemaFileToElementDefinitionIfAbsent(definition, finalSchemaFile);
+ return SchemaUtils.addSchemaFileToElementDefinitionIfAbsent(definition, finalSchemaFile);
}
/**
@@ -1009,7 +911,7 @@
private String completeDefinitionWhenReplacingSchemaElement(String definition, SchemaElement existingElement,
Set<String> modifiedSchemaFiles) throws DirectoryException
{
- String givenSchemaFile = SchemaHandler.parseSchemaFileFromElementDefinition(definition);
+ String givenSchemaFile = SchemaUtils.parseSchemaFileFromElementDefinition(definition);
String oldSchemaFile = getElementSchemaFile(existingElement);
if (givenSchemaFile == null)
@@ -1019,7 +921,7 @@
oldSchemaFile = FILE_USER_SCHEMA_ELEMENTS;
}
modifiedSchemaFiles.add(oldSchemaFile);
- return SchemaHandler.addSchemaFileToElementDefinitionIfAbsent(definition, oldSchemaFile);
+ return SchemaUtils.addSchemaFileToElementDefinitionIfAbsent(definition, oldSchemaFile);
}
else if (oldSchemaFile == null || oldSchemaFile.equals(givenSchemaFile))
{
@@ -1064,7 +966,7 @@
int currentPosition, Set<String> modifiedSchemaFiles) throws DirectoryException
{
org.forgerock.opendj.ldap.schema.Schema currentSchema = newSchemaBuilder.toSchema();
- String atOID = SchemaHandler.parseAttributeTypeOID(definition);
+ String atOID = SchemaUtils.parseAttributeTypeOID(definition);
if (!currentSchema.hasAttributeType(atOID))
{
@@ -1090,7 +992,7 @@
{
try
{
- String oid = SchemaHandler.parseAttributeTypeOID(v.toString());
+ String oid = SchemaUtils.parseAttributeTypeOID(v.toString());
if (atOID.equals(oid))
{
// We found a match where the attribute type is added back later,
@@ -1131,7 +1033,7 @@
throws DirectoryException
{
org.forgerock.opendj.ldap.schema.Schema currentSchema = schemaHandler.getSchema();
- String oid = SchemaHandler.parseObjectClassOID(definition);
+ String oid = SchemaUtils.parseObjectClassOID(definition);
final String finalDefinition;
if (!currentSchema.hasObjectClass(oid))
{
@@ -1178,7 +1080,7 @@
throws DirectoryException
{
org.forgerock.opendj.ldap.schema.Schema currentSchema = newSchemaBuilder.toSchema();
- String ocOID = SchemaHandler.parseObjectClassOID(definition);
+ String ocOID = SchemaUtils.parseObjectClassOID(definition);
if (!currentSchema.hasObjectClass(ocOID))
{
@@ -1205,7 +1107,7 @@
String oid;
try
{
- oid = SchemaHandler.parseObjectClassOID(v.toString());
+ oid = SchemaUtils.parseObjectClassOID(v.toString());
}
catch (DirectoryException de)
{
@@ -1247,7 +1149,7 @@
throws DirectoryException
{
org.forgerock.opendj.ldap.schema.Schema currentSchema = schemaHandler.getSchema();
- String oid = SchemaHandler.parseNameFormOID(definition);
+ String oid = SchemaUtils.parseNameFormOID(definition);
final String finalDefinition;
if (!currentSchema.hasNameForm(oid))
{
@@ -1293,7 +1195,7 @@
throws DirectoryException
{
org.forgerock.opendj.ldap.schema.Schema currentSchema = newSchemaBuilder.toSchema();
- String nfOID = SchemaHandler.parseNameFormOID(definition);
+ String nfOID = SchemaUtils.parseNameFormOID(definition);
if (!currentSchema.hasNameForm(nfOID))
{
@@ -1319,7 +1221,7 @@
{
try
{
- String oid = SchemaHandler.parseNameFormOID(v.toString());
+ String oid = SchemaUtils.parseNameFormOID(v.toString());
if (nfOID.equals(oid))
{
// We found a match where the name form is added back later, so we
@@ -1361,7 +1263,7 @@
Set<String> modifiedSchemaFiles) throws DirectoryException
{
org.forgerock.opendj.ldap.schema.Schema currentSchema = schemaHandler.getSchema();
- String oid = SchemaHandler.parseDITContentRuleOID(definition);
+ String oid = SchemaUtils.parseDITContentRuleOID(definition);
final String finalDefinition;
if (!currentSchema.hasDITContentRule(oid))
{
@@ -1401,7 +1303,7 @@
SchemaBuilder newSchemaBuilder, Set<String> modifiedSchemaFiles) throws DirectoryException
{
org.forgerock.opendj.ldap.schema.Schema currentSchema = newSchemaBuilder.toSchema();
- String ruleOid = SchemaHandler.parseDITContentRuleOID(definition);
+ String ruleOid = SchemaUtils.parseDITContentRuleOID(definition);
if (! currentSchema.hasDITContentRule(ruleOid))
{
@@ -1439,7 +1341,7 @@
throws DirectoryException
{
org.forgerock.opendj.ldap.schema.Schema currentSchema = schemaHandler.getSchema();
- int ruleId = SchemaHandler.parseRuleID(definition);
+ int ruleId = SchemaUtils.parseRuleID(definition);
final String finalDefinition;
if (!currentSchema.hasDITStructureRule(ruleId))
{
@@ -1487,7 +1389,7 @@
throws DirectoryException
{
org.forgerock.opendj.ldap.schema.Schema currentSchema = newSchemaBuilder.toSchema();
- int ruleID = SchemaHandler.parseRuleID(definition);
+ int ruleID = SchemaUtils.parseRuleID(definition);
if (!currentSchema.hasDITStructureRule(ruleID))
{
@@ -1511,7 +1413,7 @@
for (ByteString v : a)
{
- int id = SchemaHandler.parseRuleID(v.toString());
+ int id = SchemaUtils.parseRuleID(v.toString());
if (ruleID == id)
{
// We found a match where the DIT structure rule is added back later,
@@ -1547,7 +1449,7 @@
throws DirectoryException
{
org.forgerock.opendj.ldap.schema.Schema currentSchema = schemaHandler.getSchema();
- String oid = SchemaHandler.parseMatchingRuleUseOID(definition);
+ String oid = SchemaUtils.parseMatchingRuleUseOID(definition);
final String finalDefinition;
if (!currentSchema.hasMatchingRuleUse(oid))
{
@@ -1589,7 +1491,7 @@
throws DirectoryException
{
org.forgerock.opendj.ldap.schema.Schema currentSchema = newSchemaBuilder.toSchema();
- String mruOid = SchemaHandler.parseMatchingRuleUseOID(definition);
+ String mruOid = SchemaUtils.parseMatchingRuleUseOID(definition);
if (!currentSchema.hasMatchingRuleUse(mruOid))
{
@@ -1628,7 +1530,7 @@
// reject a change if a syntax with oid already exists, but I don't understand why.
// I kept an implementation that behave like other schema elements.
org.forgerock.opendj.ldap.schema.Schema currentSchema = schemaHandler.getSchema();
- String oid = SchemaHandler.parseSyntaxOID(definition);
+ String oid = SchemaUtils.parseSyntaxOID(definition);
final String finalDefinition;
if (!currentSchema.hasSyntax(oid))
{
@@ -1652,7 +1554,7 @@
* hence never deleted.
*/
org.forgerock.opendj.ldap.schema.Schema currentSchema = newSchemaBuilder.toSchema();
- String oid = SchemaHandler.parseSyntaxOID(definition);
+ String oid = SchemaUtils.parseSyntaxOID(definition);
if (!currentSchema.hasSyntax(oid))
{
@@ -2440,13 +2342,13 @@
for (ByteString v : a)
{
String definition = v.toString();
- String schemaFile = SchemaHandler.parseSchemaFileFromElementDefinition(definition);
+ String schemaFile = SchemaUtils.parseSchemaFileFromElementDefinition(definition);
if (is02ConfigLdif(schemaFile))
{
continue;
}
- String oid = SchemaHandler.parseAttributeTypeOID(definition);
+ String oid = SchemaUtils.parseAttributeTypeOID(definition);
oidList.add(oid);
try
{
@@ -2492,12 +2394,12 @@
// It IS important here to allow the unknown elements that could
// appear in the new config schema.
String definition = v.toString();
- String schemaFile = SchemaHandler.parseSchemaFileFromElementDefinition(definition);
+ String schemaFile = SchemaUtils.parseSchemaFileFromElementDefinition(definition);
if (is02ConfigLdif(schemaFile))
{
continue;
}
- String oid = SchemaHandler.parseObjectClassOID(definition);
+ String oid = SchemaUtils.parseObjectClassOID(definition);
oidList.add(oid);
try
{
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/core/SchemaHandler.java b/opendj-server-legacy/src/main/java/org/opends/server/core/SchemaHandler.java
index e0d13f3..61eec45 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/core/SchemaHandler.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/core/SchemaHandler.java
@@ -15,14 +15,6 @@
*/
package org.opends.server.core;
-import static org.opends.messages.SchemaMessages.ERR_PARSING_LDAP_SYNTAX_OID;
-
-import static org.opends.messages.SchemaMessages.ERR_PARSING_MATCHING_RULE_USE_OID;
-import static org.opends.messages.SchemaMessages.ERR_PARSING_DIT_STRUCTURE_RULE_RULEID;
-import static org.opends.messages.SchemaMessages.ERR_PARSING_DIT_CONTENT_RULE_OID;
-import static org.opends.messages.SchemaMessages.ERR_PARSING_NAME_FORM_OID;
-import static org.opends.messages.SchemaMessages.ERR_PARSING_OBJECTCLASS_OID;
-import static org.opends.messages.SchemaMessages.ERR_PARSING_ATTRIBUTE_TYPE_OID;
import static com.forgerock.opendj.ldap.CoreMessages.ERR_ATTR_SYNTAX_TRUNCATED_VALUE1;
import static org.opends.messages.ConfigMessages.WARN_CONFIG_SCHEMA_CANNOT_OPEN_FILE;
import static org.opends.server.util.ServerConstants.SCHEMA_PROPERTY_FILENAME;
@@ -49,7 +41,6 @@
import org.opends.server.schema.AciSyntax;
import org.opends.server.schema.SubtreeSpecificationSyntax;
import org.forgerock.i18n.LocalizableMessage;
-import org.forgerock.i18n.LocalizableMessageDescriptor.Arg1;
import org.forgerock.i18n.slf4j.LocalizedLogger;
import org.forgerock.opendj.config.ClassPropertyDefinition;
import org.forgerock.opendj.config.server.ConfigException;
@@ -83,8 +74,6 @@
import org.opends.server.util.ActivateOnceSDKSchemaIsUsed;
import org.opends.server.util.StaticUtils;
-import com.forgerock.opendj.util.SubstringReader;
-
/**
* Responsible for loading the server schema.
* <p>
@@ -294,88 +283,6 @@
return extraAttributes.values();
}
- /**
- * Adds the provided schema file to the provided schema element definition.
- *
- * @param definition
- * The schema element definition
- * @param schemaFile
- * The name of the schema file to include in the definition
- * @return The definition string of the element
- * including the X-SCHEMA-FILE extension.
- */
- public static String addSchemaFileToElementDefinitionIfAbsent(String definition, String schemaFile)
- {
- if (schemaFile != null && !definition.contains(SCHEMA_PROPERTY_FILENAME))
- {
- int pos = definition.lastIndexOf(')');
- return definition.substring(0, pos).trim() + " " + SCHEMA_PROPERTY_FILENAME + " '" + schemaFile + "' )";
- }
- return definition;
- }
-
- /**
- * Parses the schema file (value of X-SCHEMA-FILE extension) from the provided schema element
- * definition.
- * <p>
- * It expects a single value for the X-SCHEMA-FILE extension, e.g.:
- * "X-SCHEMA-FILE '99-user.ldif'", as there is no sensible meaning for multiple values.
- *
- * @param definition
- * The definition of a schema element
- * @return the value of the schema file or {@code null} if the X-SCHEMA-FILE extension is not
- * present in the definition
- * @throws DirectoryException
- * If an error occurs while parsing the schema element definition
- */
- public static String parseSchemaFileFromElementDefinition(String definition) throws DirectoryException
- {
- int pos = definition.lastIndexOf(SCHEMA_PROPERTY_FILENAME);
- if (pos == -1)
- {
- return null;
- }
-
- SubstringReader reader = new SubstringReader(definition);
- reader.read(pos + SCHEMA_PROPERTY_FILENAME.length());
-
- int length = 0;
- reader.skipWhitespaces();
- reader.mark();
- try
- {
- // Accept both a quoted value or an unquoted value
- char c = reader.read();
- if (c == '\'')
- {
- reader.mark();
- // Parse until the closing quote.
- while (reader.read() != '\'')
- {
- length++;
- }
- }
- else
- {
- // Parse until the next space.
- do
- {
- length++;
- }
- while (reader.read() != ' ');
- }
- reader.reset();
- return reader.read(length);
- }
- catch (final StringIndexOutOfBoundsException e)
- {
- // TODO : write the correct message = Error when trying to parse the schema file from a schema
- // element definition
- throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, LocalizableMessage.raw(""));
- }
- }
-
-
/** Takes an exclusive lock on the schema. */
public void exclusiveLock()
{
@@ -765,150 +672,4 @@
*/
Schema update(SchemaBuilder builder) throws DirectoryException;
}
-
- /**
- * Returns the OID from the provided attribute type definition, assuming the definition is valid.
- * <p>
- * This method does not perform any check.
- *
- * @param definition
- * The definition of an attribute type, assumed to be valid
- * @return the OID, which is never {@code null}
- * @throws DirectoryException
- * If a problem occurs while parsing the definition
- */
- public static String parseAttributeTypeOID(String definition) throws DirectoryException
- {
- return parseOID(definition, ERR_PARSING_ATTRIBUTE_TYPE_OID);
- }
-
- /**
- * Returns the OID from the provided object class definition, assuming the definition is valid.
- * <p>
- * This method does not perform any check.
- *
- * @param definition
- * The definition of a object class, assumed to be valid
- * @return the OID, which is never {@code null}
- * @throws DirectoryException
- * If a problem occurs while parsing the definition
- */
- public static String parseObjectClassOID(String definition) throws DirectoryException
- {
- return parseOID(definition, ERR_PARSING_OBJECTCLASS_OID);
- }
-
- /**
- * Returns the OID from the provided name form definition, assuming the definition is valid.
- * <p>
- * This method does not perform any check.
- *
- * @param definition
- * The definition of a name form, assumed to be valid
- * @return the OID, which is never {@code null}
- * @throws DirectoryException
- * If a problem occurs while parsing the definition
- */
- public static String parseNameFormOID(String definition) throws DirectoryException
- {
- return parseOID(definition, ERR_PARSING_NAME_FORM_OID);
- }
-
- /**
- * Returns the OID from the provided DIT content rule definition, assuming the definition is valid.
- * <p>
- * This method does not perform any check.
- *
- * @param definition
- * The definition of a DIT content rule, assumed to be valid
- * @return the OID, which is never {@code null}
- * @throws DirectoryException
- * If a problem occurs while parsing the definition
- */
- public static String parseDITContentRuleOID(String definition) throws DirectoryException
- {
- return parseOID(definition, ERR_PARSING_DIT_CONTENT_RULE_OID);
- }
-
- /**
- * Returns the ruleID from the provided DIT structure rule definition, assuming the definition is
- * valid.
- * <p>
- * This method does not perform any check.
- *
- * @param definition
- * The definition of a DIT structure rule, assumed to be valid
- * @return the OID, which is never {@code null}
- * @throws DirectoryException
- * If a problem occurs while parsing the definition
- */
- public static int parseRuleID(String definition) throws DirectoryException
- {
- // Reuse code of parseOID, even though this is not an OID
- return Integer.parseInt(parseOID(definition, ERR_PARSING_DIT_STRUCTURE_RULE_RULEID));
- }
-
- /**
- * Returns the OID from the provided matching rule use definition, assuming the definition is valid.
- * <p>
- * This method does not perform any check.
- *
- * @param definition
- * The definition of a matching rule use, assumed to be valid
- * @return the OID, which is never {@code null}
- * @throws DirectoryException
- * If a problem occurs while parsing the definition
- */
- public static String parseMatchingRuleUseOID(String definition) throws DirectoryException
- {
- return parseOID(definition, ERR_PARSING_MATCHING_RULE_USE_OID);
- }
-
- /**
- * Returns the OID from the provided syntax definition, assuming the definition is valid.
- * <p>
- * This method does not perform any check.
- *
- * @param definition
- * The definition of a syntax, assumed to be valid
- * @return the OID, which is never {@code null}
- * @throws DirectoryException
- * If a problem occurs while parsing the definition
- */
- public static String parseSyntaxOID(String definition) throws DirectoryException
- {
- return parseOID(definition, ERR_PARSING_LDAP_SYNTAX_OID);
- }
-
- private static String parseOID(String definition, Arg1<Object> parsingErrorMsg) throws DirectoryException
- {
- try
- {
- int pos = 0;
- int length = definition.length();
- // Skip over any leading whitespace.
- while (pos < length && (definition.charAt(pos) == ' '))
- {
- pos++;
- }
- // Skip the open parenthesis.
- pos++;
- // Skip over any spaces immediately following the opening parenthesis.
- while (pos < length && definition.charAt(pos) == ' ')
- {
- pos++;
- }
- // The next set of characters must be the OID.
- int oidStartPos = pos;
- while (pos < length && definition.charAt(pos) != ' ' && definition.charAt(pos) != ')')
- {
- pos++;
- }
- return definition.substring(oidStartPos, pos);
- }
- catch (IndexOutOfBoundsException e)
- {
- throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX, parsingErrorMsg.get(definition), e);
- }
- }
}
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/tasks/AddSchemaFileTask.java b/opendj-server-legacy/src/main/java/org/opends/server/tasks/AddSchemaFileTask.java
index 2fef56a..1548902 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/tasks/AddSchemaFileTask.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/tasks/AddSchemaFileTask.java
@@ -44,6 +44,8 @@
import org.opends.server.types.Operation;
import org.opends.server.types.Privilege;
import org.opends.server.types.Schema;
+import org.opends.server.types.SchemaWriter;
+import org.opends.server.util.SchemaUtils;
import static org.opends.messages.TaskMessages.*;
import static org.opends.server.config.ConfigConstants.*;
@@ -181,7 +183,7 @@
AttributeBuilder builder = new AttributeBuilder(a.getAttributeDescription());
for (ByteString v : a)
{
- builder.add(Schema.addSchemaFileToElementDefinitionIfAbsent(v.toString(), schemaFile));
+ builder.add(SchemaUtils.addSchemaFileToElementDefinitionIfAbsent(v.toString(), schemaFile));
}
mods.add(new Modification(m.getModificationType(), builder.toAttribute()));
@@ -213,7 +215,7 @@
}
}
- Schema.writeConcatenatedSchema();
+ SchemaWriter.writeConcatenatedSchema();
}
schema.setYoungestModificationTime(System.currentTimeMillis());
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/tools/upgrade/UpgradeTasks.java b/opendj-server-legacy/src/main/java/org/opends/server/tools/upgrade/UpgradeTasks.java
index 2059687..90f8866 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/tools/upgrade/UpgradeTasks.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/tools/upgrade/UpgradeTasks.java
@@ -15,17 +15,17 @@
*/
package org.opends.server.tools.upgrade;
+import static org.opends.server.util.SchemaUtils.addSchemaFileToElementDefinitionIfAbsent;
+
import static java.nio.charset.StandardCharsets.*;
import static java.nio.file.StandardOpenOption.*;
import static javax.security.auth.callback.ConfirmationCallback.NO;
import static javax.security.auth.callback.ConfirmationCallback.YES;
import static javax.security.auth.callback.TextOutputCallback.*;
-
import static org.forgerock.util.Utils.joinAsString;
import static org.opends.messages.ToolMessages.*;
import static org.opends.server.tools.upgrade.FileManager.copyRecursively;
import static org.opends.server.tools.upgrade.UpgradeUtils.*;
-import static org.opends.server.types.Schema.*;
import static org.opends.server.util.StaticUtils.*;
import java.io.BufferedWriter;
@@ -67,6 +67,7 @@
import org.opends.server.tools.RebuildIndex;
import org.opends.server.util.BuildVersion;
import org.opends.server.util.ChangeOperationType;
+import org.opends.server.util.SchemaUtils;
import org.opends.server.util.StaticUtils;
import com.forgerock.opendj.cli.ClientException;
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/types/Schema.java b/opendj-server-legacy/src/main/java/org/opends/server/types/Schema.java
index 95b87d2..13e6d60 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/types/Schema.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/types/Schema.java
@@ -16,32 +16,14 @@
*/
package org.opends.server.types;
-import static org.forgerock.opendj.ldap.ModificationType.*;
import static org.forgerock.opendj.ldap.schema.CoreSchema.*;
import static org.forgerock.opendj.ldap.schema.SchemaOptions.*;
-import static org.opends.messages.BackendMessages.*;
import static org.opends.messages.SchemaMessages.*;
-import static org.opends.server.config.ConfigConstants.*;
import static org.opends.server.util.ServerConstants.*;
-import static org.opends.server.util.StaticUtils.*;
-import java.io.BufferedReader;
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileReader;
-import java.io.FileWriter;
-import java.io.FilenameFilter;
-import java.io.IOException;
-import java.text.ParseException;
import java.util.Collection;
import java.util.HashMap;
-import java.util.LinkedHashSet;
-import java.util.LinkedList;
-import java.util.List;
import java.util.Map;
-import java.util.Set;
-import java.util.TreeSet;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
@@ -49,9 +31,6 @@
import org.forgerock.i18n.LocalizableMessageDescriptor.Arg1;
import org.forgerock.i18n.LocalizedIllegalArgumentException;
import org.forgerock.i18n.slf4j.LocalizedLogger;
-import org.forgerock.opendj.ldap.AttributeDescription;
-import org.forgerock.opendj.ldap.ByteString;
-import org.forgerock.opendj.ldap.ModificationType;
import org.forgerock.opendj.ldap.ResultCode;
import org.forgerock.opendj.ldap.schema.AttributeType;
import org.forgerock.opendj.ldap.schema.ConflictingSchemaElementException;
@@ -68,8 +47,6 @@
import org.forgerock.util.Option;
import org.forgerock.util.Utils;
import org.opends.server.core.DirectoryServer;
-import org.opends.server.core.SchemaConfigManager;
-import org.opends.server.util.Base64;
/**
* This class defines a data structure that holds information about the components of the Directory
@@ -1551,357 +1528,6 @@
extraAttributes.put(name, attr);
}
-
- /**
- * Writes a single file containing all schema element definitions,
- * which can be used on startup to determine whether the schema
- * files were edited with the server offline.
- */
- public static void writeConcatenatedSchema()
- {
- String concatFilePath = null;
- try
- {
- Set<String> attributeTypes = new LinkedHashSet<>();
- Set<String> objectClasses = new LinkedHashSet<>();
- Set<String> nameForms = new LinkedHashSet<>();
- Set<String> ditContentRules = new LinkedHashSet<>();
- Set<String> ditStructureRules = new LinkedHashSet<>();
- Set<String> matchingRuleUses = new LinkedHashSet<>();
- Set<String> ldapSyntaxes = new LinkedHashSet<>();
- genConcatenatedSchema(attributeTypes, objectClasses, nameForms,
- ditContentRules, ditStructureRules,
- matchingRuleUses,ldapSyntaxes);
-
-
- File configFile = new File(DirectoryServer.getConfigFile());
- File configDirectory = configFile.getParentFile();
- File upgradeDirectory = new File(configDirectory, "upgrade");
- upgradeDirectory.mkdir();
- File concatFile = new File(upgradeDirectory, SCHEMA_CONCAT_FILE_NAME);
- concatFilePath = concatFile.getAbsolutePath();
-
- File tempFile = new File(concatFilePath + ".tmp");
- try (BufferedWriter writer = new BufferedWriter(new FileWriter(tempFile, false)))
- {
- writeLines(writer,
- "dn: " + DirectoryServer.getSchemaDN(),
- "objectClass: top",
- "objectClass: ldapSubentry",
- "objectClass: subschema");
-
- writeLines(writer, ATTR_ATTRIBUTE_TYPES, attributeTypes);
- writeLines(writer, ATTR_OBJECTCLASSES, objectClasses);
- writeLines(writer, ATTR_NAME_FORMS, nameForms);
- writeLines(writer, ATTR_DIT_CONTENT_RULES, ditContentRules);
- writeLines(writer, ATTR_DIT_STRUCTURE_RULES, ditStructureRules);
- writeLines(writer, ATTR_MATCHING_RULE_USE, matchingRuleUses);
- writeLines(writer, ATTR_LDAP_SYNTAXES, ldapSyntaxes);
- }
-
- if (concatFile.exists())
- {
- concatFile.delete();
- }
- tempFile.renameTo(concatFile);
- }
- catch (Exception e)
- {
- logger.traceException(e);
-
- // This is definitely not ideal, but it's not the end of the
- // world. The worst that should happen is that the schema
- // changes could potentially be sent to the other servers again
- // when this server is restarted, which shouldn't hurt anything.
- // Still, we should log a warning message.
- logger.error(ERR_SCHEMA_CANNOT_WRITE_CONCAT_SCHEMA_FILE, concatFilePath, getExceptionMessage(e));
- }
- }
-
- private static void writeLines(BufferedWriter writer, String... lines) throws IOException
- {
- for (String line : lines)
- {
- writer.write(line);
- writer.newLine();
- }
- }
-
- private static void writeLines(BufferedWriter writer, String beforeColumn, Set<String> lines) throws IOException
- {
- for (String line : lines)
- {
- writer.write(beforeColumn);
- writer.write(": ");
- writer.write(line);
- writer.newLine();
- }
- }
-
- /**
- * Reads the files contained in the schema directory and generates a
- * concatenated view of their contents in the provided sets.
- *
- * @param attributeTypes The set into which to place the
- * attribute types read from the schema
- * files.
- * @param objectClasses The set into which to place the object
- * classes read from the schema files.
- * @param nameForms The set into which to place the name
- * forms read from the schema files.
- * @param ditContentRules The set into which to place the DIT
- * content rules read from the schema
- * files.
- * @param ditStructureRules The set into which to place the DIT
- * structure rules read from the schema
- * files.
- * @param matchingRuleUses The set into which to place the
- * matching rule uses read from the
- * schema files.
- * @param ldapSyntaxes The set into which to place the
- * ldap syntaxes read from the
- * schema files.
- *
- * @throws IOException If a problem occurs while reading the
- * schema file elements.
- */
- public static void genConcatenatedSchema(
- Set<String> attributeTypes,
- Set<String> objectClasses,
- Set<String> nameForms,
- Set<String> ditContentRules,
- Set<String> ditStructureRules,
- Set<String> matchingRuleUses,
- Set<String> ldapSyntaxes)
- throws IOException
- {
- // Get a sorted list of the files in the schema directory.
- TreeSet<File> schemaFiles = new TreeSet<>();
- String schemaDirectory = SchemaConfigManager.getSchemaDirectoryPath();
-
- final FilenameFilter filter = new SchemaConfigManager.SchemaFileFilter();
- for (File f : new File(schemaDirectory).listFiles(filter))
- {
- if (f.isFile())
- {
- schemaFiles.add(f);
- }
- }
-
-
- // Open each of the files in order and read the elements that they
- // contain, appending them to the appropriate lists.
- for (File f : schemaFiles)
- {
- List<StringBuilder> lines = readSchemaElementsFromLdif(f);
-
- // Iterate through each line in the list. Find the colon and
- // get the attribute name at the beginning. If it's something
- // that we don't recognize, then skip it. Otherwise, add the
- // X-SCHEMA-FILE extension and add it to the appropriate schema
- // element list.
- for (StringBuilder buffer : lines)
- {
- String line = buffer.toString().trim();
- parseSchemaLine(line, f.getName(), attributeTypes, objectClasses,
- nameForms, ditContentRules, ditStructureRules, matchingRuleUses,
- ldapSyntaxes);
- }
- }
- }
-
- private static List<StringBuilder> readSchemaElementsFromLdif(File f) throws IOException, FileNotFoundException
- {
- final LinkedList<StringBuilder> lines = new LinkedList<>();
-
- try (BufferedReader reader = new BufferedReader(new FileReader(f)))
- {
- String line;
- while ((line = reader.readLine()) != null)
- {
- if (line.startsWith("#") || line.length() == 0)
- {
- continue;
- }
- else if (line.startsWith(" "))
- {
- lines.getLast().append(line.substring(1));
- }
- else
- {
- lines.add(new StringBuilder(line));
- }
- }
- }
- return lines;
- }
-
-
-
- /**
- * Reads data from the specified concatenated schema file into the
- * provided sets.
- *
- * @param concatSchemaFile The concatenated schema file to be read.
- * @param attributeTypes The set into which to place the attribute types
- * read from the concatenated schema file.
- * @param objectClasses The set into which to place the object classes
- * read from the concatenated schema file.
- * @param nameForms The set into which to place the name forms
- * read from the concatenated schema file.
- * @param ditContentRules The set into which to place the DIT content rules
- * read from the concatenated schema file.
- * @param ditStructureRules The set into which to place the DIT structure rules
- * read from the concatenated schema file.
- * @param matchingRuleUses The set into which to place the matching rule
- * uses read from the concatenated schema file.
- * @param ldapSyntaxes The set into which to place the ldap syntaxes
- * read from the concatenated schema file.
- *
- * @throws IOException If a problem occurs while reading the
- * schema file elements.
- */
- public static void readConcatenatedSchema(File concatSchemaFile,
- Set<String> attributeTypes,
- Set<String> objectClasses,
- Set<String> nameForms,
- Set<String> ditContentRules,
- Set<String> ditStructureRules,
- Set<String> matchingRuleUses,
- Set<String> ldapSyntaxes)
- throws IOException
- {
- try (BufferedReader reader = new BufferedReader(new FileReader(concatSchemaFile)))
- {
- String line;
- while ((line = reader.readLine()) != null)
- {
- parseSchemaLine(line, null, attributeTypes, objectClasses,
- nameForms, ditContentRules, ditStructureRules, matchingRuleUses,
- ldapSyntaxes);
- }
- }
- }
-
- private static void parseSchemaLine(String definition, String fileName,
- Set<String> attributeTypes,
- Set<String> objectClasses,
- Set<String> nameForms,
- Set<String> ditContentRules,
- Set<String> ditStructureRules,
- Set<String> matchingRuleUses,
- Set<String> ldapSyntaxes)
- {
- String lowerLine = toLowerCase(definition);
-
- try
- {
- if (lowerLine.startsWith(ATTR_ATTRIBUTE_TYPES_LC))
- {
- addSchemaDefinition(attributeTypes, definition, ATTR_ATTRIBUTE_TYPES_LC, fileName);
- }
- else if (lowerLine.startsWith(ATTR_OBJECTCLASSES_LC))
- {
- addSchemaDefinition(objectClasses, definition, ATTR_OBJECTCLASSES_LC, fileName);
- }
- else if (lowerLine.startsWith(ATTR_NAME_FORMS_LC))
- {
- addSchemaDefinition(nameForms, definition, ATTR_NAME_FORMS_LC, fileName);
- }
- else if (lowerLine.startsWith(ATTR_DIT_CONTENT_RULES_LC))
- {
- addSchemaDefinition(ditContentRules, definition, ATTR_DIT_CONTENT_RULES_LC, fileName);
- }
- else if (lowerLine.startsWith(ATTR_DIT_STRUCTURE_RULES_LC))
- {
- addSchemaDefinition(ditStructureRules, definition, ATTR_DIT_STRUCTURE_RULES_LC, fileName);
- }
- else if (lowerLine.startsWith(ATTR_MATCHING_RULE_USE_LC))
- {
- addSchemaDefinition(matchingRuleUses, definition, ATTR_MATCHING_RULE_USE_LC, fileName);
- }
- else if (lowerLine.startsWith(ATTR_LDAP_SYNTAXES_LC))
- {
- addSchemaDefinition(ldapSyntaxes, definition, ATTR_LDAP_SYNTAXES_LC, fileName);
- }
- } catch (ParseException pe)
- {
- logger.error(ERR_SCHEMA_PARSE_LINE.get(definition, pe.getLocalizedMessage()));
- }
- }
-
- private static void addSchemaDefinition(Set<String> definitions, String line, String attrName, String fileName)
- throws ParseException
- {
- definitions.add(getSchemaDefinition(line.substring(attrName.length()), fileName));
- }
-
- private static String getSchemaDefinition(String definition, String schemaFile) throws ParseException
- {
- if (definition.startsWith("::"))
- {
- // See OPENDJ-2792: the definition of the ds-cfg-csv-delimiter-char attribute type
- // had a space accidentally added after the closing parenthesis.
- // This was unfortunately interpreted as base64
- definition = ByteString.wrap(Base64.decode(definition.substring(2).trim())).toString();
- }
- else if (definition.startsWith(":"))
- {
- definition = definition.substring(1).trim();
- }
- else
- {
- throw new ParseException(ERR_SCHEMA_COULD_NOT_PARSE_DEFINITION.get().toString(), 0);
- }
-
- return addSchemaFileToElementDefinitionIfAbsent(definition, schemaFile);
- }
-
- /**
- * Compares the provided sets of schema element definitions and
- * writes any differences found into the given list of
- * modifications.
- *
- * @param oldElements The set of elements of the specified type
- * read from the previous concatenated schema
- * files.
- * @param newElements The set of elements of the specified type
- * read from the server's current schema.
- * @param elementType The attribute type associated with the
- * schema element being compared.
- * @param mods The list of modifications into which any
- * identified differences should be written.
- */
- public static void compareConcatenatedSchema(
- Set<String> oldElements,
- Set<String> newElements,
- AttributeType elementType,
- List<Modification> mods)
- {
- AttributeBuilder builder = new AttributeBuilder(elementType);
- addModification(mods, DELETE, oldElements, newElements, builder);
-
- builder.setAttributeDescription(AttributeDescription.create(elementType));
- addModification(mods, ADD, newElements, oldElements, builder);
- }
-
- private static void addModification(List<Modification> mods, ModificationType modType, Set<String> included,
- Set<String> excluded, AttributeBuilder builder)
- {
- for (String val : included)
- {
- if (!excluded.contains(val))
- {
- builder.add(val);
- }
- }
-
- if (!builder.isEmpty())
- {
- mods.add(new Modification(modType, builder.toAttribute()));
- }
- }
-
/**
* Destroys the structures maintained by the schema so that they are
* no longer usable. This should only be called at the end of the
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/types/SchemaWriter.java b/opendj-server-legacy/src/main/java/org/opends/server/types/SchemaWriter.java
new file mode 100644
index 0000000..efeafd4
--- /dev/null
+++ b/opendj-server-legacy/src/main/java/org/opends/server/types/SchemaWriter.java
@@ -0,0 +1,486 @@
+/*
+ * The contents of this file are subject to the terms of the Common Development and
+ * Distribution License (the License). You may not use this file except in compliance with the
+ * License.
+ *
+ * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
+ * specific language governing permission and limitations under the License.
+ *
+ * When distributing Covered Software, include this CDDL Header Notice in each file and include
+ * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
+ * Header, with the fields enclosed by brackets [] replaced by your own identifying
+ * information: "Portions Copyright [year] [name of copyright owner]".
+ *
+ * Copyright 2016 ForgeRock AS.
+ */
+package org.opends.server.types;
+
+import static org.opends.messages.BackendMessages.ERR_SCHEMA_CANNOT_FIND_CONCAT_FILE;
+import static org.opends.server.util.ServerConstants.*;
+
+import static org.opends.messages.BackendMessages.ERR_SCHEMA_COULD_NOT_PARSE_DEFINITION;
+import static org.opends.messages.BackendMessages.ERR_SCHEMA_PARSE_LINE;
+import static org.opends.server.config.ConfigConstants.*;
+import static org.opends.messages.BackendMessages.ERR_SCHEMA_ERROR_DETERMINING_SCHEMA_CHANGES;
+import static org.forgerock.opendj.ldap.schema.CoreSchema.*;
+import static org.forgerock.opendj.ldap.ModificationType.ADD;
+import static org.forgerock.opendj.ldap.ModificationType.DELETE;
+import static org.opends.messages.BackendMessages.*;
+import static org.opends.server.config.ConfigConstants.*;
+import static org.opends.server.util.ServerConstants.*;
+import static org.opends.server.util.StaticUtils.getExceptionMessage;
+import static org.opends.server.util.StaticUtils.toLowerCase;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.text.ParseException;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.forgerock.i18n.slf4j.LocalizedLogger;
+import org.forgerock.opendj.ldap.AttributeDescription;
+import org.forgerock.opendj.ldap.ByteString;
+import org.forgerock.opendj.ldap.ModificationType;
+import org.forgerock.opendj.ldap.schema.AttributeType;
+import org.opends.server.core.DirectoryServer;
+import org.opends.server.core.SchemaConfigManager;
+import org.opends.server.util.Base64;
+import org.opends.server.util.BuildVersion;
+import org.opends.server.util.SchemaUtils;
+
+/**
+ * Provides support to write schema files.
+ */
+public class SchemaWriter
+{
+ private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
+
+ private static final AttributeType attributeTypesType = getAttributeTypesAttributeType();
+ private static final AttributeType ditStructureRulesType = getDITStructureRulesAttributeType();
+ private static final AttributeType ditContentRulesType = getDITContentRulesAttributeType();
+ private static final AttributeType ldapSyntaxesType = getLDAPSyntaxesAttributeType();
+ private static final AttributeType matchingRuleUsesType = getMatchingRuleUseAttributeType();
+ private static final AttributeType nameFormsType = getNameFormsAttributeType();
+ private static final AttributeType objectClassesType = getObjectClassesAttributeType();
+
+ /**
+ * Compares the provided sets of schema element definitions and writes any differences found into
+ * the given list of modifications.
+ *
+ * @param oldElements
+ * The set of elements of the specified type read from the previous concatenated schema
+ * files.
+ * @param newElements
+ * The set of elements of the specified type read from the server's current schema.
+ * @param elementType
+ * The attribute type associated with the schema element being compared.
+ * @param mods
+ * The list of modifications into which any identified differences should be written.
+ */
+ public static void compareConcatenatedSchema(Set<String> oldElements, Set<String> newElements,
+ AttributeType elementType, List<Modification> mods)
+ {
+ AttributeBuilder builder = new AttributeBuilder(elementType);
+ addModification(mods, DELETE, oldElements, newElements, builder);
+
+ builder.setAttributeDescription(AttributeDescription.create(elementType));
+ addModification(mods, ADD, newElements, oldElements, builder);
+ }
+
+ /**
+ * Reads the files contained in the schema directory and generates a concatenated view of their
+ * contents in the provided sets.
+ *
+ * @param attributeTypes
+ * The set into which to place the attribute types read from the schema files.
+ * @param objectClasses
+ * The set into which to place the object classes read from the schema files.
+ * @param nameForms
+ * The set into which to place the name forms read from the schema files.
+ * @param ditContentRules
+ * The set into which to place the DIT content rules read from the schema files.
+ * @param ditStructureRules
+ * The set into which to place the DIT structure rules read from the schema files.
+ * @param matchingRuleUses
+ * The set into which to place the matching rule uses read from the schema files.
+ * @param ldapSyntaxes
+ * The set into which to place the ldap syntaxes read from the schema files.
+ * @throws IOException
+ * If a problem occurs while reading the schema file elements.
+ */
+ public static void generateConcatenatedSchema(Set<String> attributeTypes, Set<String> objectClasses,
+ Set<String> nameForms, Set<String> ditContentRules, Set<String> ditStructureRules, Set<String> matchingRuleUses,
+ Set<String> ldapSyntaxes) throws IOException
+ {
+ // Get a sorted list of the files in the schema directory.
+ TreeSet<File> schemaFiles = new TreeSet<>();
+ String schemaDirectory = SchemaConfigManager.getSchemaDirectoryPath();
+
+ final FilenameFilter filter = new SchemaConfigManager.SchemaFileFilter();
+ for (File f : new File(schemaDirectory).listFiles(filter))
+ {
+ if (f.isFile())
+ {
+ schemaFiles.add(f);
+ }
+ }
+
+ // Open each of the files in order and read the elements that they
+ // contain, appending them to the appropriate lists.
+ for (File f : schemaFiles)
+ {
+ List<StringBuilder> lines = readSchemaElementsFromLdif(f);
+
+ // Iterate through each line in the list. Find the colon and
+ // get the attribute name at the beginning. If it's something
+ // that we don't recognize, then skip it. Otherwise, add the
+ // X-SCHEMA-FILE extension and add it to the appropriate schema
+ // element list.
+ for (StringBuilder buffer : lines)
+ {
+ String line = buffer.toString().trim();
+ parseSchemaLine(line, f.getName(), attributeTypes, objectClasses, nameForms, ditContentRules,
+ ditStructureRules, matchingRuleUses, ldapSyntaxes);
+ }
+ }
+ }
+
+ /**
+ * Reads data from the specified concatenated schema file into the provided sets.
+ *
+ * @param concatSchemaFile
+ * The concatenated schema file to be read.
+ * @param attributeTypes
+ * The set into which to place the attribute types read from the concatenated schema
+ * file.
+ * @param objectClasses
+ * The set into which to place the object classes read from the concatenated schema file.
+ * @param nameForms
+ * The set into which to place the name forms read from the concatenated schema file.
+ * @param ditContentRules
+ * The set into which to place the DIT content rules read from the concatenated schema
+ * file.
+ * @param ditStructureRules
+ * The set into which to place the DIT structure rules read from the concatenated schema
+ * file.
+ * @param matchingRuleUses
+ * The set into which to place the matching rule uses read from the concatenated schema
+ * file.
+ * @param ldapSyntaxes
+ * The set into which to place the ldap syntaxes read from the concatenated schema file.
+ * @throws IOException
+ * If a problem occurs while reading the schema file elements.
+ */
+ public static void readConcatenatedSchema(File concatSchemaFile, Set<String> attributeTypes,
+ Set<String> objectClasses, Set<String> nameForms, Set<String> ditContentRules, Set<String> ditStructureRules,
+ Set<String> matchingRuleUses, Set<String> ldapSyntaxes) throws IOException
+ {
+ try (BufferedReader reader = new BufferedReader(new FileReader(concatSchemaFile)))
+ {
+ String line;
+ while ((line = reader.readLine()) != null)
+ {
+ parseSchemaLine(line, null, attributeTypes, objectClasses, nameForms, ditContentRules, ditStructureRules,
+ matchingRuleUses, ldapSyntaxes);
+ }
+ }
+ }
+
+ /**
+ * Updates the concatenated schema if changes are detected in the current schema files.
+ * <p>
+ * Identify any differences that may exist between the concatenated schema file from the last
+ * online modification and the current schema files. If there are any differences, then they
+ * should be from making changes to the schema files with the server offline.
+ */
+ public static void updateConcatenatedSchema() throws InitializationException
+ {
+ try
+ {
+ // First, generate lists of elements from the current schema.
+ Set<String> newATs = new LinkedHashSet<>();
+ Set<String> newOCs = new LinkedHashSet<>();
+ Set<String> newNFs = new LinkedHashSet<>();
+ Set<String> newDCRs = new LinkedHashSet<>();
+ Set<String> newDSRs = new LinkedHashSet<>();
+ Set<String> newMRUs = new LinkedHashSet<>();
+ Set<String> newLSs = new LinkedHashSet<>();
+ generateConcatenatedSchema(newATs, newOCs, newNFs, newDCRs, newDSRs, newMRUs, newLSs);
+
+ // Next, generate lists of elements from the previous concatenated schema.
+ // If there isn't a previous concatenated schema, then use the base
+ // schema for the current revision.
+ File concatFile = getConcatenatedSchemaFile();
+
+ Set<String> oldATs = new LinkedHashSet<>();
+ Set<String> oldOCs = new LinkedHashSet<>();
+ Set<String> oldNFs = new LinkedHashSet<>();
+ Set<String> oldDCRs = new LinkedHashSet<>();
+ Set<String> oldDSRs = new LinkedHashSet<>();
+ Set<String> oldMRUs = new LinkedHashSet<>();
+ Set<String> oldLSs = new LinkedHashSet<>();
+ readConcatenatedSchema(concatFile, oldATs, oldOCs, oldNFs, oldDCRs, oldDSRs, oldMRUs, oldLSs);
+
+ // Create a list of modifications and add any differences between the old
+ // and new schema into them.
+ List<Modification> mods = new LinkedList<>();
+ compareConcatenatedSchema(oldATs, newATs, attributeTypesType, mods);
+ compareConcatenatedSchema(oldOCs, newOCs, objectClassesType, mods);
+ compareConcatenatedSchema(oldNFs, newNFs, nameFormsType, mods);
+ compareConcatenatedSchema(oldDCRs, newDCRs, ditContentRulesType, mods);
+ compareConcatenatedSchema(oldDSRs, newDSRs, ditStructureRulesType, mods);
+ compareConcatenatedSchema(oldMRUs, newMRUs, matchingRuleUsesType, mods);
+ compareConcatenatedSchema(oldLSs, newLSs, ldapSyntaxesType, mods);
+ if (!mods.isEmpty())
+ {
+ // TODO : Raise an alert notification.
+
+ DirectoryServer.setOfflineSchemaChanges(mods);
+
+ // Write a new concatenated schema file with the most recent information
+ // so we don't re-find these same changes on the next startup.
+ writeConcatenatedSchema();
+ }
+ }
+ catch (InitializationException ie)
+ {
+ throw ie;
+ }
+ catch (Exception e)
+ {
+ logger.traceException(e);
+
+ logger.error(ERR_SCHEMA_ERROR_DETERMINING_SCHEMA_CHANGES, getExceptionMessage(e));
+ }
+ }
+
+ /**
+ * Writes a single file containing all schema element definitions, which can be used on startup to
+ * determine whether the schema files were edited with the server offline.
+ */
+ public static void writeConcatenatedSchema()
+ {
+ String concatFilePath = null;
+ try
+ {
+ Set<String> attributeTypes = new LinkedHashSet<>();
+ Set<String> objectClasses = new LinkedHashSet<>();
+ Set<String> nameForms = new LinkedHashSet<>();
+ Set<String> ditContentRules = new LinkedHashSet<>();
+ Set<String> ditStructureRules = new LinkedHashSet<>();
+ Set<String> matchingRuleUses = new LinkedHashSet<>();
+ Set<String> ldapSyntaxes = new LinkedHashSet<>();
+ generateConcatenatedSchema(attributeTypes, objectClasses, nameForms, ditContentRules, ditStructureRules,
+ matchingRuleUses, ldapSyntaxes);
+
+ File configFile = new File(DirectoryServer.getConfigFile());
+ File configDirectory = configFile.getParentFile();
+ File upgradeDirectory = new File(configDirectory, "upgrade");
+ upgradeDirectory.mkdir();
+ File concatFile = new File(upgradeDirectory, SCHEMA_CONCAT_FILE_NAME);
+ concatFilePath = concatFile.getAbsolutePath();
+
+ File tempFile = new File(concatFilePath + ".tmp");
+ try (BufferedWriter writer = new BufferedWriter(new FileWriter(tempFile, false)))
+ {
+ writeLines(writer, "dn: " + DirectoryServer.getSchemaDN(), "objectClass: top", "objectClass: ldapSubentry",
+ "objectClass: subschema");
+
+ writeLines(writer, ATTR_ATTRIBUTE_TYPES, attributeTypes);
+ writeLines(writer, ATTR_OBJECTCLASSES, objectClasses);
+ writeLines(writer, ATTR_NAME_FORMS, nameForms);
+ writeLines(writer, ATTR_DIT_CONTENT_RULES, ditContentRules);
+ writeLines(writer, ATTR_DIT_STRUCTURE_RULES, ditStructureRules);
+ writeLines(writer, ATTR_MATCHING_RULE_USE, matchingRuleUses);
+ writeLines(writer, ATTR_LDAP_SYNTAXES, ldapSyntaxes);
+ }
+
+ if (concatFile.exists())
+ {
+ concatFile.delete();
+ }
+ tempFile.renameTo(concatFile);
+ }
+ catch (Exception e)
+ {
+ logger.traceException(e);
+
+ // This is definitely not ideal, but it's not the end of the
+ // world. The worst that should happen is that the schema
+ // changes could potentially be sent to the other servers again
+ // when this server is restarted, which shouldn't hurt anything.
+ // Still, we should log a warning message.
+ logger.error(ERR_SCHEMA_CANNOT_WRITE_CONCAT_SCHEMA_FILE, concatFilePath, getExceptionMessage(e));
+ }
+ }
+
+ private static void addModification(List<Modification> mods, ModificationType modType, Set<String> included,
+ Set<String> excluded, AttributeBuilder builder)
+ {
+ for (String val : included)
+ {
+ if (!excluded.contains(val))
+ {
+ builder.add(val);
+ }
+ }
+
+ if (!builder.isEmpty())
+ {
+ mods.add(new Modification(modType, builder.toAttribute()));
+ }
+ }
+
+ private static void addSchemaDefinition(Set<String> definitions, String line, String attrName, String fileName)
+ throws ParseException
+ {
+ definitions.add(getSchemaDefinition(line.substring(attrName.length()), fileName));
+ }
+
+ private static File getConcatenatedSchemaFile() throws InitializationException
+ {
+ File configDirectory = new File(DirectoryServer.getConfigFile()).getParentFile();
+ File upgradeDirectory = new File(configDirectory, "upgrade");
+ File concatFile = new File(upgradeDirectory, SCHEMA_CONCAT_FILE_NAME);
+ if (concatFile.exists())
+ {
+ return concatFile.getAbsoluteFile();
+ }
+
+ String fileName = SCHEMA_BASE_FILE_NAME_WITHOUT_REVISION + BuildVersion.instanceVersion().getRevision();
+ concatFile = new File(upgradeDirectory, fileName);
+ if (concatFile.exists())
+ {
+ return concatFile.getAbsoluteFile();
+ }
+
+ String runningUnitTestsStr = System.getProperty(PROPERTY_RUNNING_UNIT_TESTS);
+ if ("true".equalsIgnoreCase(runningUnitTestsStr))
+ {
+ writeConcatenatedSchema();
+ concatFile = new File(upgradeDirectory, SCHEMA_CONCAT_FILE_NAME);
+ return concatFile.getAbsoluteFile();
+ }
+ throw new InitializationException(ERR_SCHEMA_CANNOT_FIND_CONCAT_FILE.get(upgradeDirectory.getAbsolutePath(),
+ SCHEMA_CONCAT_FILE_NAME, concatFile.getName()));
+ }
+
+ private static String getSchemaDefinition(String definition, String schemaFile) throws ParseException
+ {
+ if (definition.startsWith("::"))
+ {
+ // See OPENDJ-2792: the definition of the ds-cfg-csv-delimiter-char attribute type
+ // had a space accidentally added after the closing parenthesis.
+ // This was unfortunately interpreted as base64
+ definition = ByteString.wrap(Base64.decode(definition.substring(2).trim())).toString();
+ }
+ else if (definition.startsWith(":"))
+ {
+ definition = definition.substring(1).trim();
+ }
+ else
+ {
+ throw new ParseException(ERR_SCHEMA_COULD_NOT_PARSE_DEFINITION.get().toString(), 0);
+ }
+
+ return SchemaUtils.addSchemaFileToElementDefinitionIfAbsent(definition, schemaFile);
+ }
+
+ private static void parseSchemaLine(String definition, String fileName, Set<String> attributeTypes,
+ Set<String> objectClasses, Set<String> nameForms, Set<String> ditContentRules, Set<String> ditStructureRules,
+ Set<String> matchingRuleUses, Set<String> ldapSyntaxes)
+ {
+ String lowerLine = toLowerCase(definition);
+
+ try
+ {
+ if (lowerLine.startsWith(ATTR_ATTRIBUTE_TYPES_LC))
+ {
+ addSchemaDefinition(attributeTypes, definition, ATTR_ATTRIBUTE_TYPES_LC, fileName);
+ }
+ else if (lowerLine.startsWith(ATTR_OBJECTCLASSES_LC))
+ {
+ addSchemaDefinition(objectClasses, definition, ATTR_OBJECTCLASSES_LC, fileName);
+ }
+ else if (lowerLine.startsWith(ATTR_NAME_FORMS_LC))
+ {
+ addSchemaDefinition(nameForms, definition, ATTR_NAME_FORMS_LC, fileName);
+ }
+ else if (lowerLine.startsWith(ATTR_DIT_CONTENT_RULES_LC))
+ {
+ addSchemaDefinition(ditContentRules, definition, ATTR_DIT_CONTENT_RULES_LC, fileName);
+ }
+ else if (lowerLine.startsWith(ATTR_DIT_STRUCTURE_RULES_LC))
+ {
+ addSchemaDefinition(ditStructureRules, definition, ATTR_DIT_STRUCTURE_RULES_LC, fileName);
+ }
+ else if (lowerLine.startsWith(ATTR_MATCHING_RULE_USE_LC))
+ {
+ addSchemaDefinition(matchingRuleUses, definition, ATTR_MATCHING_RULE_USE_LC, fileName);
+ }
+ else if (lowerLine.startsWith(ATTR_LDAP_SYNTAXES_LC))
+ {
+ addSchemaDefinition(ldapSyntaxes, definition, ATTR_LDAP_SYNTAXES_LC, fileName);
+ }
+ }
+ catch (ParseException pe)
+ {
+ logger.error(ERR_SCHEMA_PARSE_LINE.get(definition, pe.getLocalizedMessage()));
+ }
+ }
+
+ private static List<StringBuilder> readSchemaElementsFromLdif(File f) throws IOException, FileNotFoundException
+ {
+ final LinkedList<StringBuilder> lines = new LinkedList<>();
+
+ try (BufferedReader reader = new BufferedReader(new FileReader(f)))
+ {
+ String line;
+ while ((line = reader.readLine()) != null)
+ {
+ if (line.startsWith("#") || line.length() == 0)
+ {
+ continue;
+ }
+ else if (line.startsWith(" "))
+ {
+ lines.getLast().append(line.substring(1));
+ }
+ else
+ {
+ lines.add(new StringBuilder(line));
+ }
+ }
+ }
+ return lines;
+ }
+
+ private static void writeLines(BufferedWriter writer, String... lines) throws IOException
+ {
+ for (String line : lines)
+ {
+ writer.write(line);
+ writer.newLine();
+ }
+ }
+
+ private static void writeLines(BufferedWriter writer, String beforeColumn, Set<String> lines) throws IOException
+ {
+ for (String line : lines)
+ {
+ writer.write(beforeColumn);
+ writer.write(": ");
+ writer.write(line);
+ writer.newLine();
+ }
+ }
+}
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/util/SchemaUtils.java b/opendj-server-legacy/src/main/java/org/opends/server/util/SchemaUtils.java
index 166b2d0..6f9740e 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/util/SchemaUtils.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/util/SchemaUtils.java
@@ -15,7 +15,9 @@
*/
package org.opends.server.util;
-import static org.opends.server.types.Schema.addSchemaFileToElementDefinitionIfAbsent;
+import static org.opends.messages.SchemaMessages.*;
+
+import static org.opends.server.util.ServerConstants.SCHEMA_PROPERTY_FILENAME;
import static org.opends.server.schema.SchemaConstants.SYNTAX_AUTH_PASSWORD_OID;
import static org.opends.server.schema.SchemaConstants.SYNTAX_USER_PASSWORD_OID;
@@ -24,12 +26,18 @@
import java.util.List;
import java.util.Set;
+import org.forgerock.i18n.LocalizableMessage;
+import org.forgerock.i18n.LocalizableMessageDescriptor.Arg1;
+import org.forgerock.opendj.ldap.ResultCode;
import org.forgerock.opendj.ldap.schema.AttributeType;
import org.forgerock.opendj.ldap.schema.ObjectClass;
import org.forgerock.opendj.ldap.schema.Schema;
import org.forgerock.opendj.ldap.schema.SchemaBuilder;
import org.forgerock.opendj.ldap.schema.SchemaElement;
import org.opends.server.core.ServerContext;
+import org.opends.server.types.DirectoryException;
+
+import com.forgerock.opendj.util.SubstringReader;
/** Utility methods related to schema. */
public class SchemaUtils
@@ -189,4 +197,244 @@
}
return attributeType;
}
+
+ /**
+ * Adds the provided schema file to the provided schema element definition.
+ *
+ * @param definition
+ * The schema element definition
+ * @param schemaFile
+ * The name of the schema file to include in the definition
+ * @return The definition string of the element
+ * including the X-SCHEMA-FILE extension.
+ */
+ public static String addSchemaFileToElementDefinitionIfAbsent(String definition, String schemaFile)
+ {
+ if (schemaFile != null && !definition.contains(SCHEMA_PROPERTY_FILENAME))
+ {
+ int pos = definition.lastIndexOf(')');
+ return definition.substring(0, pos).trim() + " " + SCHEMA_PROPERTY_FILENAME + " '" + schemaFile + "' )";
+ }
+ return definition;
+ }
+
+ /**
+ * Parses the schema file (value of X-SCHEMA-FILE extension) from the provided schema element
+ * definition.
+ * <p>
+ * It expects a single value for the X-SCHEMA-FILE extension, e.g.:
+ * "X-SCHEMA-FILE '99-user.ldif'", as there is no sensible meaning for multiple values.
+ *
+ * @param definition
+ * The definition of a schema element
+ * @return the value of the schema file or {@code null} if the X-SCHEMA-FILE extension is not
+ * present in the definition
+ * @throws DirectoryException
+ * If an error occurs while parsing the schema element definition
+ */
+ public static String parseSchemaFileFromElementDefinition(String definition) throws DirectoryException
+ {
+ int pos = definition.lastIndexOf(SCHEMA_PROPERTY_FILENAME);
+ if (pos == -1)
+ {
+ return null;
+ }
+
+ SubstringReader reader = new SubstringReader(definition);
+ reader.read(pos + SCHEMA_PROPERTY_FILENAME.length());
+
+ int length = 0;
+ reader.skipWhitespaces();
+ reader.mark();
+ try
+ {
+ // Accept both a quoted value or an unquoted value
+ char c = reader.read();
+ if (c == '\'')
+ {
+ reader.mark();
+ // Parse until the closing quote.
+ while (reader.read() != '\'')
+ {
+ length++;
+ }
+ }
+ else
+ {
+ // Parse until the next space.
+ do
+ {
+ length++;
+ }
+ while (reader.read() != ' ');
+ }
+ reader.reset();
+ return reader.read(length);
+ }
+ catch (final StringIndexOutOfBoundsException e)
+ {
+ // TODO : write the correct message = Error when trying to parse the schema file from a schema
+ // element definition
+ throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, LocalizableMessage.raw(""));
+ }
+ }
+
+ /**
+ * Returns the OID from the provided attribute type definition, assuming the definition is valid.
+ * <p>
+ * This method does not perform any check.
+ *
+ * @param definition
+ * The definition of an attribute type, assumed to be valid
+ * @return the OID, which is never {@code null}
+ * @throws DirectoryException
+ * If a problem occurs while parsing the definition
+ */
+ public static String parseAttributeTypeOID(String definition) throws DirectoryException
+ {
+ return parseOID(definition, ERR_PARSING_ATTRIBUTE_TYPE_OID);
+ }
+
+ /**
+ * Returns the OID from the provided object class definition, assuming the definition is valid.
+ * <p>
+ * This method does not perform any check.
+ *
+ * @param definition
+ * The definition of a object class, assumed to be valid
+ * @return the OID, which is never {@code null}
+ * @throws DirectoryException
+ * If a problem occurs while parsing the definition
+ */
+ public static String parseObjectClassOID(String definition) throws DirectoryException
+ {
+ return parseOID(definition, ERR_PARSING_OBJECTCLASS_OID);
+ }
+
+ /**
+ * Returns the OID from the provided name form definition, assuming the definition is valid.
+ * <p>
+ * This method does not perform any check.
+ *
+ * @param definition
+ * The definition of a name form, assumed to be valid
+ * @return the OID, which is never {@code null}
+ * @throws DirectoryException
+ * If a problem occurs while parsing the definition
+ */
+ public static String parseNameFormOID(String definition) throws DirectoryException
+ {
+ return parseOID(definition, ERR_PARSING_NAME_FORM_OID);
+ }
+
+ /**
+ * Returns the OID from the provided DIT content rule definition, assuming the definition is valid.
+ * <p>
+ * This method does not perform any check.
+ *
+ * @param definition
+ * The definition of a DIT content rule, assumed to be valid
+ * @return the OID, which is never {@code null}
+ * @throws DirectoryException
+ * If a problem occurs while parsing the definition
+ */
+ public static String parseDITContentRuleOID(String definition) throws DirectoryException
+ {
+ return parseOID(definition, ERR_PARSING_DIT_CONTENT_RULE_OID);
+ }
+
+ /**
+ * Returns the ruleID from the provided DIT structure rule definition, assuming the definition is
+ * valid.
+ * <p>
+ * This method does not perform any check.
+ *
+ * @param definition
+ * The definition of a DIT structure rule, assumed to be valid
+ * @return the OID, which is never {@code null}
+ * @throws DirectoryException
+ * If a problem occurs while parsing the definition
+ */
+ public static int parseRuleID(String definition) throws DirectoryException
+ {
+ // Reuse code of parseOID, even though this is not an OID
+ return Integer.parseInt(parseOID(definition, ERR_PARSING_DIT_STRUCTURE_RULE_RULEID));
+ }
+
+ /**
+ * Returns the OID from the provided matching rule use definition, assuming the definition is valid.
+ * <p>
+ * This method does not perform any check.
+ *
+ * @param definition
+ * The definition of a matching rule use, assumed to be valid
+ * @return the OID, which is never {@code null}
+ * @throws DirectoryException
+ * If a problem occurs while parsing the definition
+ */
+ public static String parseMatchingRuleUseOID(String definition) throws DirectoryException
+ {
+ return parseOID(definition, ERR_PARSING_MATCHING_RULE_USE_OID);
+ }
+
+ /**
+ * Returns the OID from the provided syntax definition, assuming the definition is valid.
+ * <p>
+ * This method does not perform any check.
+ *
+ * @param definition
+ * The definition of a syntax, assumed to be valid
+ * @return the OID, which is never {@code null}
+ * @throws DirectoryException
+ * If a problem occurs while parsing the definition
+ */
+ public static String parseSyntaxOID(String definition) throws DirectoryException
+ {
+ return parseOID(definition, ERR_PARSING_LDAP_SYNTAX_OID);
+ }
+
+ /**
+ * Returns the OID from the provided definition, using the provided message if an error occurs.
+ *
+ * @param definition
+ * The definition of a schema element
+ * @param parsingErrorMsg
+ * Error message to use in case of failure (should be related to
+ * the specific schema element parsed)
+ * @return the OID corresponding to the definition
+ * @throws DirectoryException
+ * If the parsing of the definition fails
+ *
+ * */
+ public static String parseOID(String definition, Arg1<Object> parsingErrorMsg) throws DirectoryException
+ {
+ try
+ {
+ int pos = 0;
+ int length = definition.length();
+ // Skip over any leading whitespace.
+ while (pos < length && (definition.charAt(pos) == ' '))
+ {
+ pos++;
+ }
+ // Skip the open parenthesis.
+ pos++;
+ // Skip over any spaces immediately following the opening parenthesis.
+ while (pos < length && definition.charAt(pos) == ' ')
+ {
+ pos++;
+ }
+ // The next set of characters must be the OID.
+ int oidStartPos = pos;
+ while (pos < length && definition.charAt(pos) != ' ' && definition.charAt(pos) != ')')
+ {
+ pos++;
+ }
+ return definition.substring(oidStartPos, pos);
+ }
+ catch (IndexOutOfBoundsException e)
+ {
+ throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX, parsingErrorMsg.get(definition), e);
+ }
+ }
}
--
Gitblit v1.10.0