| opends/resource/bin/ldifmodify.bat | ●●●●● patch | view | raw | blame | history | |
| opends/resource/bin/ldifmodify.sh | ●●●●● patch | view | raw | blame | history | |
| opends/src/server/org/opends/server/config/ConfigConstants.java | ●●●●● patch | view | raw | blame | history | |
| opends/src/server/org/opends/server/config/ConfigFileHandler.java | ●●●●● patch | view | raw | blame | history | |
| opends/src/server/org/opends/server/messages/ConfigMessages.java | ●●●●● patch | view | raw | blame | history | |
| opends/src/server/org/opends/server/messages/CoreMessages.java | ●●●●● patch | view | raw | blame | history | |
| opends/src/server/org/opends/server/messages/ToolMessages.java | ●●●●● patch | view | raw | blame | history | |
| opends/src/server/org/opends/server/tools/LDIFModify.java | ●●●●● patch | view | raw | blame | history | |
| opends/src/server/org/opends/server/types/Entry.java | ●●●●● patch | view | raw | blame | history |
opends/resource/bin/ldifmodify.bat
New file @@ -0,0 +1,54 @@ @echo off rem CDDL HEADER START rem rem The contents of this file are subject to the terms of the rem Common Development and Distribution License, Version 1.0 only rem (the "License"). You may not use this file except in compliance rem with the License. rem rem You can obtain a copy of the license at rem trunk/opends/resource/legal-notices/OpenDS.LICENSE rem or https://OpenDS.dev.java.net/OpenDS.LICENSE. rem See the License for the specific language governing permissions rem and limitations under the License. rem rem When distributing Covered Code, include this CDDL HEADER in each rem file and include the License file at rem trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, rem add the following below this CDDL HEADER, with the fields enclosed rem by brackets "[]" replaced with your own identifying * information: rem Portions Copyright [yyyy] [name of copyright owner] rem rem CDDL HEADER END rem rem rem Portions Copyright 2006 Sun Microsystems, Inc. setlocal set DIR_HOME=%~dP0.. if "%JAVA_BIN%" == "" goto noJavaBin goto setClassPath :noJavaBin if "%JAVA_HOME%" == "" goto noJavaHome if not exist "%JAVA_HOME%\bin\java.exe" goto noJavaHome set JAVA_BIN="%JAVA_HOME%\bin\java.exe" goto setClassPath :noJavaHome echo Error: JAVA_HOME environment variable is not set. echo Please set it to a valid Java 5 installation. goto end :setClassPath FOR %%x in (%DIR_HOME%\lib\*.jar) DO call "%DIR_HOME%\bin\setcp.bat" %%x %JAVA_BIN% %JAVA_ARGS% -classpath "%CLASSPATH%" org.opends.server.tools.LDIFModify -c %DIR_HOME%\config\config.ldif %* :end opends/resource/bin/ldifmodify.sh
New file @@ -0,0 +1,74 @@ #!/bin/sh # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License, Version 1.0 only # (the "License"). You may not use this file except in compliance # with the License. # # You can obtain a copy of the license at # trunk/opends/resource/legal-notices/OpenDS.LICENSE # or https://OpenDS.dev.java.net/OpenDS.LICENSE. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at # trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, # add the following below this CDDL HEADER, with the fields enclosed # by brackets "[]" replaced with your own identifying * information: # Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Portions Copyright 2006 Sun Microsystems, Inc. # Capture the current working directory so that we can change to it later. # Then capture the location of this script and the Directory Server instance # root so that we can use them to create appropriate paths. WORKING_DIR=`pwd` cd `dirname $0` SCRIPT_DIR=`pwd` cd .. INSTANCE_ROOT=`pwd` export INSTANCE_ROOT cd ${WORKING_DIR} # See if JAVA_HOME is set. If not, then see if there is a java executable in # the path and try to figure it out. if test -z "${JAVA_BIN}" then if test -z "${JAVA_HOME}" then JAVA_BIN=`which java 2> /dev/null` if test $? -eq 0 then export JAVA_BIN else echo "Please set JAVA_HOME to the root of a Java 5.0 installation." exit 1 fi else JAVA_BIN=${JAVA_HOME}/bin/java export JAVA_BIN fi fi CLASSPATH=${INSTANCE_ROOT}/classes for JAR in ${INSTANCE_ROOT}/lib/*.jar do CLASSPATH=${CLASSPATH}:${JAR} done export CLASSPATH ${JAVA_BIN} ${JAVA_ARGS} org.opends.server.tools.LDIFModify \ -c ${INSTANCE_ROOT}/config/config.ldif "$@" opends/src/server/org/opends/server/config/ConfigConstants.java
@@ -2417,6 +2417,15 @@ /** * The base name (with no path information) of the file that may contain * changes in LDIF form to apply to the configuration before the configuration * is loaded and initialized. */ public static final String CONFIG_CHANGES_NAME = "config-changes.ldif"; /** * The name of the directory that will hold the configuration file for the * Directory Server. */ opends/src/server/org/opends/server/config/ConfigFileHandler.java
@@ -32,6 +32,7 @@ import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.io.IOException; import java.io.OutputStream; import java.security.MessageDigest; import java.util.Arrays; @@ -69,6 +70,7 @@ import org.opends.server.core.ModifyOperation; import org.opends.server.core.ModifyDNOperation; import org.opends.server.core.SearchOperation; import org.opends.server.tools.LDIFModify; import org.opends.server.types.BackupConfig; import org.opends.server.types.BackupDirectory; import org.opends.server.types.BackupInfo; @@ -180,10 +182,10 @@ // Make sure that the configuration file exists. this.configFile = configFile; File f = new File(configFile); try { File f = new File(configFile); if (! f.exists()) { int msgID = MSGID_CONFIG_FILE_DOES_NOT_EXIST; @@ -210,6 +212,27 @@ // Fixme -- Should we add a hash or signature check here? // See if there is a config changes file. If there is, then try to apply // the changes contained in it. File changesFile = new File(f.getParent(), CONFIG_CHANGES_NAME); try { if (changesFile.exists()) { applyChangesFile(f, changesFile); } } catch (Exception e) { assert debugException(CLASS_NAME, "initializeConfigHandler", e); int msgID = MSGID_CONFIG_UNABLE_TO_APPLY_STARTUP_CHANGES; String message = getMessage(msgID, changesFile.getAbsolutePath(), String.valueOf(e)); throw new InitializationException(msgID, message, e); } // We will use the LDIF reader to read the configuration file. Create an // LDIF import configuration to do this and then get the reader. LDIFReader reader; @@ -588,6 +611,109 @@ /** * Applies the updates in the provided changes file to the content in the * specified source file. The result will be written to a temporary file, the * current source file will be moved out of place, and then the updated file * will be moved into the place of the original file. The changes file will * also be renamed so it won't be applied again. * <BR><BR> * If any problems are encountered, then the config initialization process * will be aborted. * * @param sourceFile The LDIF file containing the source data. * @param changesFile The LDIF file containing the changes to apply. * * @throws IOException If a problem occurs while performing disk I/O. * * @throws LDIFException If a problem occurs while trying to interpret the * data. */ private void applyChangesFile(File sourceFile, File changesFile) throws IOException, LDIFException { assert debugEnter(CLASS_NAME, "applyChangesFile", String.valueOf(sourceFile), String.valueOf(changesFile)); // FIXME -- Do we need to do anything special for configuration archiving? // Create the appropriate LDIF readers and writer. LDIFImportConfig importConfig = new LDIFImportConfig(sourceFile.getAbsolutePath()); importConfig.setValidateSchema(false); LDIFReader sourceReader = new LDIFReader(importConfig); importConfig = new LDIFImportConfig(changesFile.getAbsolutePath()); importConfig.setValidateSchema(false); LDIFReader changesReader = new LDIFReader(importConfig); String tempFile = changesFile.getAbsolutePath() + ".tmp"; LDIFExportConfig exportConfig = new LDIFExportConfig(tempFile, ExistingFileBehavior.OVERWRITE); LDIFWriter targetWriter = new LDIFWriter(exportConfig); // Apply the changes and make sure there were no errors. LinkedList<String> errorList = new LinkedList<String>(); boolean successful = LDIFModify.modifyLDIF(sourceReader, changesReader, targetWriter, errorList); try { sourceReader.close(); } catch (Exception e) {} try { changesReader.close(); } catch (Exception e) {} try { targetWriter.close(); } catch (Exception e) {} if (! successful) { // FIXME -- Log each error message and throw an exception. for (String s : errorList) { int msgID = MSGID_CONFIG_ERROR_APPLYING_STARTUP_CHANGE; String message = getMessage(msgID, s); logError(ErrorLogCategory.CONFIGURATION, ErrorLogSeverity.SEVERE_ERROR, msgID, message); } int msgID = MSGID_CONFIG_UNABLE_TO_APPLY_CHANGES_FILE; String message = getMessage(msgID); throw new LDIFException(msgID, message); } // Move the current config file out of the way and replace it with the // updated version. File oldSource = new File(sourceFile.getAbsolutePath() + ".prechanges"); if (oldSource.exists()) { oldSource.delete(); } sourceFile.renameTo(oldSource); new File(tempFile).renameTo(sourceFile); // Move the changes file out of the way so it doesn't get applied again. File newChanges = new File(changesFile.getAbsolutePath() + ".applied"); if (newChanges.exists()) { newChanges.delete(); } changesFile.renameTo(newChanges); } /** * Finalizes this configuration handler so that it will release any resources * associated with it so that it will no longer be used. This will be called * when the Directory Server is shutting down, as well as in the startup opends/src/server/org/opends/server/messages/ConfigMessages.java
@@ -6094,6 +6094,37 @@ /** * The message ID for the message that will be used an error occurs while * attempting to apply a set of changes on server startup. This takes two * arguments, which are the path to the changes file and a message explaining * the problem that occurred. */ public static final int MSGID_CONFIG_UNABLE_TO_APPLY_STARTUP_CHANGES = CATEGORY_MASK_CONFIG | SEVERITY_MASK_FATAL_ERROR | 563; /** * The message ID for the message that will be used to report an error that * occurred while processing a startup changes file. This takes a single * argument, which is a message explaining the problem that occurred. */ public static final int MSGID_CONFIG_ERROR_APPLYING_STARTUP_CHANGE = CATEGORY_MASK_CONFIG | SEVERITY_MASK_FATAL_ERROR | 564; /** * The message ID for the message that will be used to indicate that a problem * occurred while applying the startup changes. This does not take any * arguments. */ public static final int MSGID_CONFIG_UNABLE_TO_APPLY_CHANGES_FILE = CATEGORY_MASK_CONFIG | SEVERITY_MASK_FATAL_ERROR | 565; /** * Associates a set of generic messages with the message IDs defined in this * class. */ @@ -6260,6 +6291,10 @@ registerMessage(MSGID_CONFIG_FILE_CANNOT_VERIFY_EXISTENCE, "An unexpected error occurred while attempting to " + "determine whether configuration file %s exists: %s."); registerMessage(MSGID_CONFIG_UNABLE_TO_APPLY_STARTUP_CHANGES, "An error occurred while attempting to apply the changes " + "contained in file %s to the server configuration at " + "startup: %s."); registerMessage(MSGID_CONFIG_FILE_CANNOT_OPEN_FOR_READ, "An error occurred while attempting to open the " + "configuration file %s for reading: %s."); @@ -6314,6 +6349,11 @@ "An unexpected error occurred while trying to register " + "the configuration handler base DN \"%s\" as a private " + "suffix with the Directory Server: %s."); registerMessage(MSGID_CONFIG_ERROR_APPLYING_STARTUP_CHANGE, "Unable to apply a change at server startup: %s."); registerMessage(MSGID_CONFIG_UNABLE_TO_APPLY_CHANGES_FILE, "One or more errors occurred while applying changes on " + "server startup."); registerMessage(MSGID_CONFIG_FILE_ADD_ALREADY_EXISTS, "Entry %s cannot be added to the Directory Server " + "configuration because another configuration entry " + opends/src/server/org/opends/server/messages/CoreMessages.java
@@ -5845,6 +5845,88 @@ /** * The message ID for the message that will be used if an attempt is made to * add an attribute with one or more values that conflict with existing * values. This takes a single argument, which is the name of the attribute. */ public static final int MSGID_ENTRY_DUPLICATE_VALUES = CATEGORY_MASK_CORE | SEVERITY_MASK_MILD_ERROR | 559; /** * The message ID for the message that will be used if an attempt is made to * remove an attribute value that doesn't exist in the entry. This takes a * single argument, which is the name of the attribute. */ public static final int MSGID_ENTRY_NO_SUCH_VALUE = CATEGORY_MASK_CORE | SEVERITY_MASK_MILD_ERROR | 560; /** * The message ID for the message that will be used if an attempt is made to * perform an increment on the objectClass attribute. This does not take any * arguments. */ public static final int MSGID_ENTRY_OC_INCREMENT_NOT_SUPPORTED = CATEGORY_MASK_CORE | SEVERITY_MASK_MILD_ERROR | 561; /** * The message ID for the message that will be used if an attempt is made to * perform a modify with an unknown modification type. This does not take any * arguments. */ public static final int MSGID_ENTRY_UNKNOWN_MODIFICATION_TYPE = CATEGORY_MASK_CORE | SEVERITY_MASK_MILD_ERROR | 562; /** * The message ID for the message that will be used if an attempt is made to * increment an attribute that does not exist. This takes a single argument, * which is the name of the attribute. */ public static final int MSGID_ENTRY_INCREMENT_NO_SUCH_ATTRIBUTE = CATEGORY_MASK_CORE | SEVERITY_MASK_MILD_ERROR | 562; /** * The message ID for the message that will be used if an attempt is made to * increment an attribute that has multiple values. This takes a single * argument, which is the name of the attribute. */ public static final int MSGID_ENTRY_INCREMENT_MULTIPLE_VALUES = CATEGORY_MASK_CORE | SEVERITY_MASK_MILD_ERROR | 563; /** * The message ID for the message that will be used if an attempt is made to * perform an increment but there was not exactly one value in the provided * modification. This takes a single argument, which is the name of the * attribute. */ public static final int MSGID_ENTRY_INCREMENT_INVALID_VALUE_COUNT = CATEGORY_MASK_CORE | SEVERITY_MASK_MILD_ERROR | 564; /** * The message ID for the message that will be used if an attempt is made to * perform an increment but either the current value or the increment cannot * be parsed as an integer. This takes a single argument, which is the name * of the attribute. */ public static final int MSGID_ENTRY_INCREMENT_CANNOT_PARSE_AS_INT = CATEGORY_MASK_CORE | SEVERITY_MASK_MILD_ERROR | 565; /** * Associates a set of generic messages with the message IDs defined * in this class. */ @@ -6307,6 +6389,32 @@ registerMessage(MSGID_ENTRY_ADD_DUPLICATE_OC, "Objectclass %s is already present in entry %s and " + "cannot be added a second time."); registerMessage(MSGID_ENTRY_DUPLICATE_VALUES, "Unable to add one or more values to attribute %s " + "because at least one of the values already exists."); registerMessage(MSGID_ENTRY_NO_SUCH_VALUE, "Unable to remove one or more values from attribute %s " + "because at least one of the attributes does not exist " + "in the entry."); registerMessage(MSGID_ENTRY_OC_INCREMENT_NOT_SUPPORTED, "The increment operation is not supported for the " + "objectClass attribute."); registerMessage(MSGID_ENTRY_UNKNOWN_MODIFICATION_TYPE, "Unknown modification type %s requested."); registerMessage(MSGID_ENTRY_INCREMENT_NO_SUCH_ATTRIBUTE, "Unable to increment the value of attribute %s because " + "that attribute does not exist in the entry."); registerMessage(MSGID_ENTRY_INCREMENT_MULTIPLE_VALUES, "Unable to increment the value of attribute %s because " + "there are multiple values for that attribute."); registerMessage(MSGID_ENTRY_INCREMENT_INVALID_VALUE_COUNT, "Unable to increment the value of attribute %s because " + "the provided modification did not have exactly one " + "value to use as the increment."); registerMessage(MSGID_ENTRY_INCREMENT_CANNOT_PARSE_AS_INT, "Unable to increment the value of attribute %s because " + "either the current value or the increment could not " + "be parsed as an integer."); registerMessage(MSGID_SEARCH_FILTER_NULL, opends/src/server/org/opends/server/messages/ToolMessages.java
@@ -6003,6 +6003,254 @@ /** * The message ID for the message that will be used if an attempt is made to * add an entry twice in the same set of changes. This takes a single * argument, which is the DN of the entry. */ public static final int MSGID_LDIFMODIFY_CANNOT_ADD_ENTRY_TWICE = CATEGORY_MASK_TOOLS | SEVERITY_MASK_MILD_ERROR | 610; /** * The message ID for the message that will be used if an attempt is made to * delete an entry that had just been added in the same set of changes. This * takes a single argument, which is the DN of the entry. */ public static final int MSGID_LDIFMODIFY_CANNOT_DELETE_AFTER_ADD = CATEGORY_MASK_TOOLS | SEVERITY_MASK_MILD_ERROR | 611; /** * The message ID for the message that will be used if an attempt is made to * modify an entry that had just been added or deleted in the same set of * changes. This takes a single argument, which is the DN of the entry. */ public static final int MSGID_LDIFMODIFY_CANNOT_MODIFY_ADDED_OR_DELETED = CATEGORY_MASK_TOOLS | SEVERITY_MASK_MILD_ERROR | 612; /** * The message ID for the message that will be used if an attempt is made to * perform a modify DN operation. This takes a single argument, which is the * DN of the entry. */ public static final int MSGID_LDIFMODIFY_MODDN_NOT_SUPPORTED = CATEGORY_MASK_TOOLS | SEVERITY_MASK_MILD_ERROR | 613; /** * The message ID for the message that will be used if a change record has an * unknown changetype. This takes two arguments, which are the DN of the * entry and the specified changetype. */ public static final int MSGID_LDIFMODIFY_UNKNOWN_CHANGETYPE = CATEGORY_MASK_TOOLS | SEVERITY_MASK_MILD_ERROR | 614; /** * The message ID for the message that will be used if an entry to be added * already exists in the data. This takes a single argument, which is the DN * of the entry. */ public static final int MSGID_LDIFMODIFY_ADD_ALREADY_EXISTS = CATEGORY_MASK_TOOLS | SEVERITY_MASK_MILD_ERROR | 615; /** * The message ID for the message that will be used if an entry cannot be * deleted because it does not exist in the data set. This takes a single * argument, which is the DN of the entry. */ public static final int MSGID_LDIFMODIFY_DELETE_NO_SUCH_ENTRY = CATEGORY_MASK_TOOLS | SEVERITY_MASK_MILD_ERROR | 616; /** * The message ID for the message that will be used if an entry cannot be * modified because it does not exist in the data set. This takes a single * argument, which is the DN of the entry. */ public static final int MSGID_LDIFMODIFY_MODIFY_NO_SUCH_ENTRY = CATEGORY_MASK_TOOLS | SEVERITY_MASK_MILD_ERROR | 617; /** * The message ID for the message that will be used as the description of the * configFile argument. This does not take any arguments. */ public static final int MSGID_LDIFMODIFY_DESCRIPTION_CONFIG_FILE = CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 618; /** * The message ID for the message that will be used as the description of the * configClass argument. This does not take any arguments. */ public static final int MSGID_LDIFMODIFY_DESCRIPTION_CONFIG_CLASS = CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 619; /** * The message ID for the message that will be used as the description for the * sourceLDIF argument. It does not take any arguments. */ public static final int MSGID_LDIFMODIFY_DESCRIPTION_SOURCE = CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 620; /** * The message ID for the message that will be used as the description for the * changesLDIF argument. It does not take any arguments. */ public static final int MSGID_LDIFMODIFY_DESCRIPTION_CHANGES = CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 621; /** * The message ID for the message that will be used as the description for the * targetLDIF argument. It does not take any arguments. */ public static final int MSGID_LDIFMODIFY_DESCRIPTION_TARGET = CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 622; /** * The message ID for the message that will be used as the description for the * help argument. It does not take any arguments. */ public static final int MSGID_LDIFMODIFY_DESCRIPTION_HELP = CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 623; /** * The message ID for the message that will be used if an error occurs while * attempting to initialize the command-line argument parser. This takes a * single argument, which is a message explaining the problem that occurred. */ public static final int MSGID_LDIFMODIFY_CANNOT_INITIALIZE_ARGS = CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 624; /** * The message ID for the message that will be used if an error occurs while * parsing the provided command-line arguments. This takes a single argument, * which is a message explaining the problem that occurred. */ public static final int MSGID_LDIFMODIFY_ERROR_PARSING_ARGS = CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 625; /** * The message ID for the message that will be used if an error occurs while * initializing the Directory Server JMX subsystem. This takes two arguments, * which are the path to the Directory Server configuration file and a message * explaining the problem that occurred. */ public static final int MSGID_LDIFMODIFY_CANNOT_INITIALIZE_JMX = CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 626; /** * The message ID for the message that will be used if an error occurs while * initializing the Directory Server configuration. This takes two * arguments, which are the path to the Directory Server configuration file * and a message explaining the problem that occurred. */ public static final int MSGID_LDIFMODIFY_CANNOT_INITIALIZE_CONFIG = CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 627; /** * The message ID for the message that will be used if an error occurs while * initializing the Directory Server schema. This takes two arguments, which * are the path to the Directory Server configuration file and a message * explaining the problem that occurred. */ public static final int MSGID_LDIFMODIFY_CANNOT_INITIALIZE_SCHEMA = CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 628; /** * The message ID for the message that will be used if the source LDIF file * does not exist. This takes a single argument, which is the path to the * source LDIF file. */ public static final int MSGID_LDIFMODIFY_SOURCE_DOES_NOT_EXIST = CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 629; /** * The message ID for the message that will be used if an error occurs while * trying to open the source LDIF file. This takes two arguments, which are * the path to the source LDIF file and a message explaining the problem that * occurred. */ public static final int MSGID_LDIFMODIFY_CANNOT_OPEN_SOURCE = CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 630; /** * The message ID for the message that will be used if the changes LDIF file * does not exist. This takes a single argument, which is the path to the * changes LDIF file. */ public static final int MSGID_LDIFMODIFY_CHANGES_DOES_NOT_EXIST = CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 631; /** * The message ID for the message that will be used if an error occurs while * trying to open the changes LDIF file. This takes two arguments, which are * the path to the changes LDIF file and a message explaining the problem that * occurred. */ public static final int MSGID_LDIFMODIFY_CANNOT_OPEN_CHANGES = CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 632; /** * The message ID for the message that will be used if an error occurs while * trying to open the target LDIF file. This takes two arguments, which are * the path to the target LDIF file and a message explaining the problem that * occurred. */ public static final int MSGID_LDIFMODIFY_CANNOT_OPEN_TARGET = CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 633; /** * The message ID for the message that will be used if an error occurs while * processing the changes. This takes a single argument, which is a message * explaining the problem that occurred. */ public static final int MSGID_LDIFMODIFY_ERROR_PROCESSING_LDIF = CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 634; /** * Associates a set of generic messages with the message IDs defined in this * class. */ @@ -7977,6 +8225,84 @@ "LDIF: %s."); registerMessage(MSGID_MAKELDIF_PROCESSING_COMPLETE, "LDIF processing complete. %d entries written."); registerMessage(MSGID_LDIFMODIFY_CANNOT_ADD_ENTRY_TWICE, "Entry %s is added twice in the set of changes to apply, " + "which is not supported by the LDIF modify tool."); registerMessage(MSGID_LDIFMODIFY_CANNOT_DELETE_AFTER_ADD, "Entry %s cannot be deleted because it was previously " + "added in the set of changes. This is not supported by " + "the LDIF modify tool."); registerMessage(MSGID_LDIFMODIFY_CANNOT_MODIFY_ADDED_OR_DELETED, "Cannot modify entry %s because it was previously added " + "or deleted in the set of changes. This is not " + "supported by the LDIF modify tool."); registerMessage(MSGID_LDIFMODIFY_MODDN_NOT_SUPPORTED, "The modify DN operation targeted at entry %s cannot be " + "processed because modify DN operations are not " + "supported by the LDIF modify tool."); registerMessage(MSGID_LDIFMODIFY_UNKNOWN_CHANGETYPE, "Entry %s has an unknown changetype of %s."); registerMessage(MSGID_LDIFMODIFY_ADD_ALREADY_EXISTS, "Unable to add entry %s because it already exists in " + "the data set."); registerMessage(MSGID_LDIFMODIFY_DELETE_NO_SUCH_ENTRY, "Unable to delete entry %s because it does not exist " + "in the data set."); registerMessage(MSGID_LDIFMODIFY_MODIFY_NO_SUCH_ENTRY, "Unable to modify entry %s because it does not exist " + "in the data set."); registerMessage(MSGID_LDIFMODIFY_DESCRIPTION_CONFIG_FILE, "The path to the Directory Server configuration file, " + "which will enable the use of the schema definitions " + "when processing the updates. If it is not provided, " + "then schema processing will not be available."); registerMessage(MSGID_LDIFMODIFY_DESCRIPTION_CONFIG_CLASS, "The fully-qualified name of the Java class to use as " + "the Directory Server configuration handler. If this is " + "not provided, then a default of " + ConfigFileHandler.class.getName() + " will be used."); registerMessage(MSGID_LDIFMODIFY_DESCRIPTION_SOURCE, "Specifies the LDIF file containing the data to be " + "updated."); registerMessage(MSGID_LDIFMODIFY_DESCRIPTION_CHANGES, "Specifies he LDIF file containing the changes to apply."); registerMessage(MSGID_LDIFMODIFY_DESCRIPTION_TARGET, "Specifies he file to which the updated data should be " + "written."); registerMessage(MSGID_LDIFMODIFY_DESCRIPTION_HELP, "Displays this usage information."); registerMessage(MSGID_LDIFMODIFY_CANNOT_INITIALIZE_ARGS, "An unexpected error occurred while attempting to " + "initialize the command-line arguments: %s."); registerMessage(MSGID_LDIFMODIFY_ERROR_PARSING_ARGS, "An error occurred while parsing the command-line " + "arguments: %s."); registerMessage(MSGID_LDIFMODIFY_CANNOT_INITIALIZE_JMX, "An error occurred while attempting to initialize the " + "Directory Server JMX subsystem based on the information " + "in configuration file %s: %s."); registerMessage(MSGID_LDIFMODIFY_CANNOT_INITIALIZE_CONFIG, "An error occurred while attempting to process the " + "Directory Server configuration file %s: %s."); registerMessage(MSGID_LDIFMODIFY_CANNOT_INITIALIZE_SCHEMA, "An error occurred while attempting to initialize the " + "Directory Server schema based on the information in " + "configuration file %s: %s."); registerMessage(MSGID_LDIFMODIFY_SOURCE_DOES_NOT_EXIST, "The source LDIF file %s does not exist."); registerMessage(MSGID_LDIFMODIFY_CANNOT_OPEN_SOURCE, "Unable to open the source LDIF file %s: %s."); registerMessage(MSGID_LDIFMODIFY_CHANGES_DOES_NOT_EXIST, "The changes LDIF file %s does not exist."); registerMessage(MSGID_LDIFMODIFY_CANNOT_OPEN_CHANGES, "Unable to open the changes LDIF file %s: %s."); registerMessage(MSGID_LDIFMODIFY_CANNOT_OPEN_TARGET, "Unable to open the target LDIF file %s for writing: %s."); registerMessage(MSGID_LDIFMODIFY_ERROR_PROCESSING_LDIF, "An error occurred while processing the requested " + "changes: %s."); } } opends/src/server/org/opends/server/tools/LDIFModify.java
New file @@ -0,0 +1,654 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying * information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Portions Copyright 2006 Sun Microsystems, Inc. */ package org.opends.server.tools; import java.io.File; import java.io.IOException; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import org.opends.server.config.ConfigFileHandler; import org.opends.server.core.DirectoryException; import org.opends.server.core.DirectoryServer; import org.opends.server.protocols.ldap.LDAPException; import org.opends.server.protocols.ldap.LDAPModification; import org.opends.server.protocols.ldap.LDAPResultCode; import org.opends.server.types.Attribute; import org.opends.server.types.AttributeType; import org.opends.server.types.AttributeValue; import org.opends.server.types.DN; import org.opends.server.types.Entry; import org.opends.server.types.ExistingFileBehavior; import org.opends.server.types.LDIFExportConfig; import org.opends.server.types.LDIFImportConfig; import org.opends.server.types.Modification; import org.opends.server.types.ObjectClass; import org.opends.server.util.AddChangeRecordEntry; import org.opends.server.util.ChangeRecordEntry; import org.opends.server.util.DeleteChangeRecordEntry; import org.opends.server.util.LDIFException; import org.opends.server.util.LDIFReader; import org.opends.server.util.LDIFWriter; import org.opends.server.util.ModifyChangeRecordEntry; import org.opends.server.util.args.ArgumentException; import org.opends.server.util.args.ArgumentParser; import org.opends.server.util.args.BooleanArgument; import org.opends.server.util.args.StringArgument; import static org.opends.server.messages.MessageHandler.*; import static org.opends.server.messages.ToolMessages.*; import static org.opends.server.util.StaticUtils.*; /** * This class provides a program that may be used to apply a set of changes (in * LDIF change format) to an LDIF file. It will first read all of the changes * into memory, and then will iterate through an LDIF file and apply them to the * entries contained in it. Note that because of the manner in which it * processes the changes, certain types of operations will not be allowed, * including: * <BR> * <UL> * <LI>Modify DN operations</LI> * <LI>Deleting an entry that has been added</LI> * <LI>Modifying an entry that has been added</LI> * </UL> */ public class LDIFModify { /** * The fully-qualified name of this class for debugging purposes. */ private static final String CLASS_NAME = "org.opends.server.tools.LDIFModify"; /** * Applies the specified changes to the source LDIF, writing the modified * file to the specified target. Neither the readers nor the writer will be * closed. * * @param sourceReader The LDIF reader that will be used to read the LDIF * content to be modified. * @param changeReader The LDIF reader that will be used to read the changes * to be applied. * @param targetWriter The LDIF writer that will be used to write the * modified LDIF. * @param errorList A list into which any error messages generated while * processing changes may be added. * * @return <CODE>true</CODE> if all updates were successfully applied, or * <CODE>false</CODE> if any errors were encountered. * * @throws IOException If a problem occurs while attempting to read the * source or changes, or write the target. * * @throws LDIFException If a problem occurs while attempting to decode the * source or changes, or trying to determine whether * to include the entry in the output. */ public static boolean modifyLDIF(LDIFReader sourceReader, LDIFReader changeReader, LDIFWriter targetWriter, List<String> errorList) throws IOException, LDIFException { // Read the changes into memory. HashMap<DN,AddChangeRecordEntry> adds = new HashMap<DN,AddChangeRecordEntry>(); HashMap<DN,DeleteChangeRecordEntry> deletes = new HashMap<DN,DeleteChangeRecordEntry>(); HashMap<DN,LinkedList<Modification>> modifications = new HashMap<DN,LinkedList<Modification>>(); while (true) { ChangeRecordEntry changeRecord; try { changeRecord = changeReader.readChangeRecord(false); } catch (LDIFException le) { if (le.canContinueReading()) { errorList.add(le.getMessage()); continue; } else { throw le; } } if (changeRecord == null) { break; } DN changeDN = changeRecord.getDN(); switch (changeRecord.getChangeOperationType()) { case ADD: // The entry must not exist in the add list. if (adds.containsKey(changeDN)) { int msgID = MSGID_LDIFMODIFY_CANNOT_ADD_ENTRY_TWICE; errorList.add(getMessage(msgID, String.valueOf(changeDN))); continue; } else { adds.put(changeDN, (AddChangeRecordEntry) changeRecord); } break; case DELETE: // The entry must not exist in the add list. If it exists in the // modify list, then remove the changes since we won't need to apply // them. if (adds.containsKey(changeDN)) { int msgID = MSGID_LDIFMODIFY_CANNOT_DELETE_AFTER_ADD; errorList.add(getMessage(msgID, String.valueOf(changeDN))); continue; } else { modifications.remove(changeDN); deletes.put(changeDN, (DeleteChangeRecordEntry) changeRecord); } break; case MODIFY: // The entry must not exist in the add or delete lists. if (adds.containsKey(changeDN) || deletes.containsKey(changeDN)) { int msgID = MSGID_LDIFMODIFY_CANNOT_MODIFY_ADDED_OR_DELETED; errorList.add(getMessage(msgID, String.valueOf(changeDN))); continue; } else { LinkedList<Modification> mods = modifications.get(changeDN); if (mods == null) { mods = new LinkedList<Modification>(); modifications.put(changeDN, mods); } for (LDAPModification mod : ((ModifyChangeRecordEntry) changeRecord).getModifications()) { try { mods.add(mod.toModification()); } catch (LDAPException le) { errorList.add(le.getMessage()); continue; } } } break; case MODIFY_DN: int msgID = MSGID_LDIFMODIFY_MODDN_NOT_SUPPORTED; errorList.add(getMessage(msgID, String.valueOf(changeDN))); continue; default: msgID = MSGID_LDIFMODIFY_UNKNOWN_CHANGETYPE; errorList.add(getMessage(msgID, String.valueOf(changeDN), String.valueOf(changeRecord.getChangeOperationType()))); continue; } } // Read the source an entry at a time and apply any appropriate changes // before writing to the target LDIF. while (true) { Entry entry; try { entry = sourceReader.readEntry(); } catch (LDIFException le) { if (le.canContinueReading()) { errorList.add(le.getMessage()); continue; } else { throw le; } } if (entry == null) { break; } // If the entry is to be deleted, then just skip over it without writing // it to the output. DN entryDN = entry.getDN(); if (deletes.remove(entryDN) != null) { continue; } // If the entry is to be added, then that's an error, since it already // exists. if (adds.remove(entryDN) != null) { int msgID = MSGID_LDIFMODIFY_ADD_ALREADY_EXISTS; errorList.add(getMessage(msgID, String.valueOf(entryDN))); continue; } // If the entry is to be modified, then process the changes. LinkedList<Modification> mods = modifications.remove(entryDN); if ((mods != null) && (! mods.isEmpty())) { try { entry.applyModifications(mods); } catch (DirectoryException de) { errorList.add(de.getErrorMessage()); continue; } } // If we've gotten here, then the (possibly updated) entry should be // written to the output LDIF. targetWriter.writeEntry(entry); } // Perform any adds that may be necessary. for (AddChangeRecordEntry add : adds.values()) { Map<ObjectClass,String> objectClasses = new LinkedHashMap<ObjectClass,String>(); Map<AttributeType,List<Attribute>> userAttributes = new LinkedHashMap<AttributeType,List<Attribute>>(); Map<AttributeType,List<Attribute>> operationalAttributes = new LinkedHashMap<AttributeType,List<Attribute>>(); for (Attribute a : add.getAttributes()) { AttributeType t = a.getAttributeType(); if (t.isObjectClassType()) { for (AttributeValue v : a.getValues()) { String stringValue = v.getStringValue(); String lowerValue = toLowerCase(stringValue); ObjectClass oc = DirectoryServer.getObjectClass(lowerValue, true); objectClasses.put(oc, stringValue); } } else if (t.isOperational()) { List<Attribute> attrList = operationalAttributes.get(t); if (attrList == null) { attrList = new LinkedList<Attribute>(); operationalAttributes.put(t, attrList); } attrList.add(a); } else { List<Attribute> attrList = userAttributes.get(t); if (attrList == null) { attrList = new LinkedList<Attribute>(); userAttributes.put(t, attrList); } attrList.add(a); } } Entry e = new Entry(add.getDN(), objectClasses, userAttributes, operationalAttributes); targetWriter.writeEntry(e); } // If there are any entries left in the delete or modify lists, then that's // a problem because they didn't exist. if (! deletes.isEmpty()) { for (DN dn : deletes.keySet()) { int msgID = MSGID_LDIFMODIFY_DELETE_NO_SUCH_ENTRY; errorList.add(getMessage(msgID, String.valueOf(dn))); } } if (! modifications.isEmpty()) { for (DN dn : modifications.keySet()) { int msgID = MSGID_LDIFMODIFY_MODIFY_NO_SUCH_ENTRY; errorList.add(getMessage(msgID, String.valueOf(dn))); } } return errorList.isEmpty(); } /** * Invokes <CODE>ldifModifyMain</CODE> to perform the appropriate processing. * * @param args The command-line arguments provided to the client. */ public static void main(String[] args) { int returnCode = ldifModifyMain(args); if (returnCode != 0) { System.exit(returnCode); } } /** * Processes the command-line arguments and makes the appropriate updates to * the LDIF file. * * @param args The command-line arguments provided to the client. * * @return A value of zero if everything completed properly, or nonzero if * any problem(s) occurred. */ public static int ldifModifyMain(String[] args) { // Prepare the argument parser. BooleanArgument showUsage; StringArgument changesFile; StringArgument configClass; StringArgument configFile; StringArgument sourceFile; StringArgument targetFile; ArgumentParser argParser = new ArgumentParser(CLASS_NAME, false); try { configFile = new StringArgument("configfile", 'c', "configFile", true, false, true, "{configFile}", null, null, MSGID_LDIFMODIFY_DESCRIPTION_CONFIG_FILE); argParser.addArgument(configFile); configClass = new StringArgument("configclass", 'C', "configClass", false, false, true, "{configClass}", ConfigFileHandler.class.getName(), null, MSGID_LDIFMODIFY_DESCRIPTION_CONFIG_CLASS); argParser.addArgument(configClass); sourceFile = new StringArgument("sourceldif", 's', "sourceLDIF", true, false, true, "{file}", null, null, MSGID_LDIFMODIFY_DESCRIPTION_SOURCE); argParser.addArgument(sourceFile); changesFile = new StringArgument("changesldif", 'm', "changesLDIF", true, false, true, "{file}", null, null, MSGID_LDIFMODIFY_DESCRIPTION_CHANGES); argParser.addArgument(changesFile); targetFile = new StringArgument("targetldif", 't', "targetLDIF", true, false, true, "{file}", null, null, MSGID_LDIFMODIFY_DESCRIPTION_TARGET); argParser.addArgument(targetFile); showUsage = new BooleanArgument("help", 'H', "help", MSGID_LDIFMODIFY_DESCRIPTION_HELP); argParser.addArgument(showUsage); argParser.setUsageArgument(showUsage); } catch (ArgumentException ae) { int msgID = MSGID_LDIFMODIFY_CANNOT_INITIALIZE_ARGS; String message = getMessage(msgID, ae.getMessage()); System.err.println(message); return 1; } // Parse the command-line arguments provided to the program. try { argParser.parseArguments(args); } catch (ArgumentException ae) { int msgID = MSGID_LDIFMODIFY_ERROR_PARSING_ARGS; String message = getMessage(msgID, ae.getMessage()); System.err.println(message); System.err.println(argParser.getUsage()); return LDAPResultCode.CLIENT_SIDE_PARAM_ERROR; } // If we should just display usage information, then print it and exit. if (showUsage.isPresent()) { return 0; } // Bootstrap the Directory Server configuration for use as a client. DirectoryServer directoryServer = DirectoryServer.getInstance(); directoryServer.bootstrapClient(); // If we're to use the configuration then initialize it, along with the // schema. boolean checkSchema = configFile.isPresent(); if (checkSchema) { try { directoryServer.initializeJMX(); } catch (Exception e) { int msgID = MSGID_LDIFMODIFY_CANNOT_INITIALIZE_JMX; String message = getMessage(msgID, String.valueOf(configFile.getValue()), e.getMessage()); System.err.println(message); return 1; } try { directoryServer.initializeConfiguration(configClass.getValue(), configFile.getValue()); } catch (Exception e) { int msgID = MSGID_LDIFMODIFY_CANNOT_INITIALIZE_CONFIG; String message = getMessage(msgID, String.valueOf(configFile.getValue()), e.getMessage()); System.err.println(message); return 1; } try { directoryServer.initializeSchema(); } catch (Exception e) { int msgID = MSGID_LDIFMODIFY_CANNOT_INITIALIZE_SCHEMA; String message = getMessage(msgID, String.valueOf(configFile.getValue()), e.getMessage()); System.err.println(message); return 1; } } // Create the LDIF readers and writer from the arguments. File source = new File(sourceFile.getValue()); if (! source.exists()) { int msgID = MSGID_LDIFMODIFY_SOURCE_DOES_NOT_EXIST; String message = getMessage(msgID, sourceFile.getValue()); System.err.println(message); return LDAPResultCode.CLIENT_SIDE_PARAM_ERROR; } LDIFImportConfig importConfig = new LDIFImportConfig(sourceFile.getValue()); LDIFReader sourceReader; try { sourceReader = new LDIFReader(importConfig); } catch (IOException ioe) { int msgID = MSGID_LDIFMODIFY_CANNOT_OPEN_SOURCE; String message = getMessage(msgID, sourceFile.getValue(), String.valueOf(ioe)); System.err.println(message); return LDAPResultCode.CLIENT_SIDE_LOCAL_ERROR; } File changes = new File(changesFile.getValue()); if (! changes.exists()) { int msgID = MSGID_LDIFMODIFY_CHANGES_DOES_NOT_EXIST; String message = getMessage(msgID, changesFile.getValue()); System.err.println(message); return LDAPResultCode.CLIENT_SIDE_PARAM_ERROR; } importConfig = new LDIFImportConfig(changesFile.getValue()); LDIFReader changeReader; try { changeReader = new LDIFReader(importConfig); } catch (IOException ioe) { int msgID = MSGID_LDIFMODIFY_CANNOT_OPEN_CHANGES; String message = getMessage(msgID, sourceFile.getValue()); System.err.println(message); return LDAPResultCode.CLIENT_SIDE_LOCAL_ERROR; } LDIFExportConfig exportConfig = new LDIFExportConfig(targetFile.getValue(), ExistingFileBehavior.OVERWRITE); LDIFWriter targetWriter; try { targetWriter = new LDIFWriter(exportConfig); } catch (IOException ioe) { int msgID = MSGID_LDIFMODIFY_CANNOT_OPEN_TARGET; String message = getMessage(msgID, sourceFile.getValue()); System.err.println(message); return LDAPResultCode.CLIENT_SIDE_LOCAL_ERROR; } // Actually invoke the LDIF procesing. LinkedList<String> errorList = new LinkedList<String>(); boolean successful; try { successful = modifyLDIF(sourceReader, changeReader, targetWriter, errorList); } catch (Exception e) { int msgID = MSGID_LDIFMODIFY_ERROR_PROCESSING_LDIF; String message = getMessage(msgID, String.valueOf(e)); System.err.println(message); successful = false; } try { sourceReader.close(); } catch (Exception e) {} try { changeReader.close(); } catch (Exception e) {} try { targetWriter.close(); } catch (Exception e) {} for (String s : errorList) { System.err.println(s); } return (successful ? 0 : 1); } } opends/src/server/org/opends/server/types/Entry.java
@@ -1765,6 +1765,247 @@ /** * Applies the provided modification to this entry. No schema * checking will be performed. * * @param mod The modification to apply to this entry. * * @throws DirectoryException If a problem occurs while attempting * to apply the modification. Note * that even if a problem occurs, then * the entry may have been altered in * some way. */ public void applyModification(Modification mod) throws DirectoryException { assert debugEnter(CLASS_NAME, "applyModification", String.valueOf(mod)); Attribute a = mod.getAttribute(); AttributeType t = a.getAttributeType(); // We'll need to handle changes to the objectclass attribute in a // special way. if (t.isObjectClassType()) { LinkedHashMap<ObjectClass,String> ocs = new LinkedHashMap<ObjectClass,String>(); for (AttributeValue v : a.getValues()) { String ocName = v.getStringValue(); String lowerName = toLowerCase(ocName); ObjectClass oc = DirectoryServer.getObjectClass(lowerName, true); ocs.put(oc, ocName); } switch (mod.getModificationType()) { case ADD: for (ObjectClass oc : ocs.keySet()) { if (objectClasses.containsKey(oc)) { int msgID = MSGID_ENTRY_DUPLICATE_VALUES; String message = getMessage(msgID, a.getName()); throw new DirectoryException( ResultCode.ATTRIBUTE_OR_VALUE_EXISTS, message, msgID); } else { objectClasses.put(oc, ocs.get(oc)); } } break; case DELETE: for (ObjectClass oc : ocs.keySet()) { if (objectClasses.remove(oc) == null) { int msgID = MSGID_ENTRY_NO_SUCH_VALUE; String message = getMessage(msgID, a.getName()); throw new DirectoryException( ResultCode.NO_SUCH_ATTRIBUTE, message, msgID); } } break; case REPLACE: objectClasses = ocs; break; case INCREMENT: int msgID = MSGID_ENTRY_OC_INCREMENT_NOT_SUPPORTED; String message = getMessage(msgID); throw new DirectoryException( ResultCode.UNWILLING_TO_PERFORM, message, msgID); default: msgID = MSGID_ENTRY_UNKNOWN_MODIFICATION_TYPE; message = getMessage(msgID, String.valueOf(mod.getModificationType())); throw new DirectoryException( ResultCode.UNWILLING_TO_PERFORM, message, msgID); } return; } switch (mod.getModificationType()) { case ADD: LinkedList<AttributeValue> duplicateValues = new LinkedList<AttributeValue>(); addAttribute(a, duplicateValues); if (! duplicateValues.isEmpty()) { int msgID = MSGID_ENTRY_DUPLICATE_VALUES; String message = getMessage(msgID, a.getName()); throw new DirectoryException( ResultCode.ATTRIBUTE_OR_VALUE_EXISTS, message, msgID); } break; case DELETE: LinkedList<AttributeValue> missingValues = new LinkedList<AttributeValue>(); removeAttribute(a, missingValues); if (! missingValues.isEmpty()) { int msgID = MSGID_ENTRY_NO_SUCH_VALUE; String message = getMessage(msgID, a.getName()); throw new DirectoryException(ResultCode.NO_SUCH_ATTRIBUTE, message, msgID); } break; case REPLACE: removeAttribute(t, a.getOptions()); if (a.hasValue()) { // We know that we won't have any duplicate values, so we // don't kneed to worry about checking for them. duplicateValues = new LinkedList<AttributeValue>(); addAttribute(a, duplicateValues); } break; case INCREMENT: List<Attribute> attrList = getAttribute(t); if ((attrList == null) || attrList.isEmpty()) { int msgID = MSGID_ENTRY_INCREMENT_NO_SUCH_ATTRIBUTE; String message = getMessage(msgID, a.getName()); throw new DirectoryException(ResultCode.NO_SUCH_ATTRIBUTE, message, msgID); } else if (attrList.size() != 1) { int msgID = MSGID_ENTRY_INCREMENT_MULTIPLE_VALUES; String message = getMessage(msgID, a.getName()); throw new DirectoryException( ResultCode.CONSTRAINT_VIOLATION, message, msgID); } LinkedHashSet<AttributeValue> values = attrList.get(0).getValues(); if (values.isEmpty()) { int msgID = MSGID_ENTRY_INCREMENT_NO_SUCH_ATTRIBUTE; String message = getMessage(msgID, a.getName()); throw new DirectoryException(ResultCode.NO_SUCH_ATTRIBUTE, message, msgID); } else if (values.size() > 1) { int msgID = MSGID_ENTRY_INCREMENT_MULTIPLE_VALUES; String message = getMessage(msgID, a.getName()); throw new DirectoryException( ResultCode.CONSTRAINT_VIOLATION, message, msgID); } LinkedHashSet<AttributeValue> newValues = a.getValues(); if (newValues.size() != 1) { int msgID = MSGID_ENTRY_INCREMENT_INVALID_VALUE_COUNT; String message = getMessage(msgID); throw new DirectoryException( ResultCode.CONSTRAINT_VIOLATION, message, msgID); } long newValue; try { String s = values.iterator().next().getStringValue(); long currentValue = Long.parseLong(s); s = a.getValues().iterator().next().getStringValue(); long increment = Long.parseLong(s); newValue = currentValue+increment; } catch (NumberFormatException nfe) { int msgID = MSGID_ENTRY_INCREMENT_CANNOT_PARSE_AS_INT; String message = getMessage(msgID); throw new DirectoryException( ResultCode.CONSTRAINT_VIOLATION, message, msgID); } values.clear(); values.add(new AttributeValue(t, String.valueOf(newValue))); break; default: int msgID = MSGID_ENTRY_UNKNOWN_MODIFICATION_TYPE; String message = getMessage(msgID, String.valueOf(mod.getModificationType())); throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message, msgID); } } /** * Applies all of the provided modifications to this entry. * * @param mods The modifications to apply to this entry. * * @throws DirectoryException If a problem occurs while attempting * to apply the modifications. Note * that even if a problem occurs, then * the entry may have been altered in * some way. */ public void applyModifications(List<Modification> mods) throws DirectoryException { assert debugEnter(CLASS_NAME, "applyModifications", String.valueOf(mods)); for (Modification m : mods) { applyModification(m); } } /** * Indicates whether this entry conforms to the server's schema * requirements. The checks performed by this method include: *