From 90ff70d4c2a798957d2d6eabe367d0a271b794ca Mon Sep 17 00:00:00 2001
From: Matthew Swift <matthew.swift@forgerock.com>
Date: Fri, 06 Jan 2012 11:38:31 +0000
Subject: [PATCH] Fix OPENDJ-382: Implement ldifdiff, ldifsearch, and ldifmodify tools for the SDK toolkit

---
 opendj3/opendj-ldap-toolkit/src/main/assembly/bat/ldifdiff.bat                                    |   32 +
 opendj3/opendj-ldap-toolkit/src/main/assembly/bin/ldifdiff                                        |   37 +
 opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/ToolConstants.java      |   12 
 opendj3/opendj-ldap-toolkit/src/main/assembly/bat/ldifsearch.bat                                  |   32 +
 opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/ConsoleApplication.java |   27 +
 opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/LDIFDiff.java           |  251 +++++++++++
 opendj3/opendj-ldap-toolkit/src/main/assembly/bat/ldifmodify.bat                                  |   32 +
 opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/LDIFModify.java         |  378 +++++++++++++++++
 opendj3/opendj-ldap-toolkit/src/main/assembly/bin/ldifsearch                                      |   37 +
 opendj3/opendj-ldap-toolkit/src/site/xdoc/index.xml.vm                                            |    3 
 opendj3/opendj-ldap-toolkit/src/main/assembly/bin/ldifmodify                                      |   38 +
 opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/LDIFSearch.java         |  363 ++++++++++++++++
 opendj3/opendj-ldap-toolkit/src/main/resources/com/forgerock/opendj/ldap/tools/tools.properties   |   35 +
 13 files changed, 1,266 insertions(+), 11 deletions(-)

diff --git a/opendj3/opendj-ldap-toolkit/src/main/assembly/bat/ldifdiff.bat b/opendj3/opendj-ldap-toolkit/src/main/assembly/bat/ldifdiff.bat
new file mode 100755
index 0000000..e477693
--- /dev/null
+++ b/opendj3/opendj-ldap-toolkit/src/main/assembly/bat/ldifdiff.bat
@@ -0,0 +1,32 @@
+
+@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/opendj3/legal-notices/CDDLv1_0.txt
+rem or http://forgerock.org/license/CDDLv1.0.html.
+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/opendj3/legal-notices/CDDLv1_0.txt.  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      Copyright 2012 ForgeRock AS.
+
+setlocal
+
+set OPENDJ_INVOKE_CLASS="com.forgerock.opendj.ldap.tools.LDIFDiff"
+set SCRIPT_NAME=ldifdiff
+for %%i in (%~sf0) do call "%%~dPsi\..\lib\_client-script.bat" %*
diff --git a/opendj3/opendj-ldap-toolkit/src/main/assembly/bat/ldifmodify.bat b/opendj3/opendj-ldap-toolkit/src/main/assembly/bat/ldifmodify.bat
new file mode 100755
index 0000000..6966992
--- /dev/null
+++ b/opendj3/opendj-ldap-toolkit/src/main/assembly/bat/ldifmodify.bat
@@ -0,0 +1,32 @@
+
+@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/opendj3/legal-notices/CDDLv1_0.txt
+rem or http://forgerock.org/license/CDDLv1.0.html.
+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/opendj3/legal-notices/CDDLv1_0.txt.  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      Copyright 2012 ForgeRock AS.
+
+setlocal
+
+set OPENDJ_INVOKE_CLASS="com.forgerock.opendj.ldap.tools.LDIFModify"
+set SCRIPT_NAME=ldifmodify
+for %%i in (%~sf0) do call "%%~dPsi\..\lib\_client-script.bat" %*
diff --git a/opendj3/opendj-ldap-toolkit/src/main/assembly/bat/ldifsearch.bat b/opendj3/opendj-ldap-toolkit/src/main/assembly/bat/ldifsearch.bat
new file mode 100755
index 0000000..df8271f
--- /dev/null
+++ b/opendj3/opendj-ldap-toolkit/src/main/assembly/bat/ldifsearch.bat
@@ -0,0 +1,32 @@
+
+@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/opendj3/legal-notices/CDDLv1_0.txt
+rem or http://forgerock.org/license/CDDLv1.0.html.
+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/opendj3/legal-notices/CDDLv1_0.txt.  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      Copyright 2012 ForgeRock AS.
+
+setlocal
+
+set OPENDJ_INVOKE_CLASS="com.forgerock.opendj.ldap.tools.LDIFSearch"
+set SCRIPT_NAME=ldifsearch
+for %%i in (%~sf0) do call "%%~dPsi\..\lib\_client-script.bat" %*
diff --git a/opendj3/opendj-ldap-toolkit/src/main/assembly/bin/ldifdiff b/opendj3/opendj-ldap-toolkit/src/main/assembly/bin/ldifdiff
new file mode 100644
index 0000000..de82167
--- /dev/null
+++ b/opendj3/opendj-ldap-toolkit/src/main/assembly/bin/ldifdiff
@@ -0,0 +1,37 @@
+#!/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/opendj3/legal-notices/CDDLv1_0.txt
+# or http://forgerock.org/license/CDDLv1.0.html.
+# 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/opendj3/legal-notices/CDDLv1_0.txt.  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
+#
+#
+#      Copyright 2012 ForgeRock AS.
+
+
+# This script may be used to compare LDIF files.
+OPENDJ_INVOKE_CLASS="com.forgerock.opendj.ldap.tools.LDIFDiff"
+export OPENDJ_INVOKE_CLASS
+
+SCRIPT_NAME="ldifdiff"
+export SCRIPT_NAME
+
+SCRIPT_DIR=`dirname "${0}"`
+"${SCRIPT_DIR}/../lib/_client-script.sh" "${@}"
diff --git a/opendj3/opendj-ldap-toolkit/src/main/assembly/bin/ldifmodify b/opendj3/opendj-ldap-toolkit/src/main/assembly/bin/ldifmodify
new file mode 100644
index 0000000..b761446
--- /dev/null
+++ b/opendj3/opendj-ldap-toolkit/src/main/assembly/bin/ldifmodify
@@ -0,0 +1,38 @@
+#!/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/opendj3/legal-notices/CDDLv1_0.txt
+# or http://forgerock.org/license/CDDLv1.0.html.
+# 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/opendj3/legal-notices/CDDLv1_0.txt.  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
+#
+#
+#      Copyright 2012 ForgeRock AS.
+
+
+# This script may be used to perform LDAP add, delete, modify, and modify DN
+# operations against an LDIF file.
+OPENDJ_INVOKE_CLASS="com.forgerock.opendj.ldap.tools.LDIFModify"
+export OPENDJ_INVOKE_CLASS
+
+SCRIPT_NAME="ldifmodify"
+export SCRIPT_NAME
+
+SCRIPT_DIR=`dirname "${0}"`
+"${SCRIPT_DIR}/../lib/_client-script.sh" "${@}"
diff --git a/opendj3/opendj-ldap-toolkit/src/main/assembly/bin/ldifsearch b/opendj3/opendj-ldap-toolkit/src/main/assembly/bin/ldifsearch
new file mode 100644
index 0000000..4c9d2c0
--- /dev/null
+++ b/opendj3/opendj-ldap-toolkit/src/main/assembly/bin/ldifsearch
@@ -0,0 +1,37 @@
+#!/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/opendj3/legal-notices/CDDLv1_0.txt
+# or http://forgerock.org/license/CDDLv1.0.html.
+# 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/opendj3/legal-notices/CDDLv1_0.txt.  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
+#
+#
+#      Copyright 2012 ForgeRock AS.
+
+
+# This script may be used to perform search operations against an LDIF file.
+OPENDJ_INVOKE_CLASS="com.forgerock.opendj.ldap.tools.LDIFSearch"
+export OPENDJ_INVOKE_CLASS
+
+SCRIPT_NAME="ldifsearch"
+export SCRIPT_NAME
+
+SCRIPT_DIR=`dirname "${0}"`
+"${SCRIPT_DIR}/../lib/_client-script.sh" "${@}"
diff --git a/opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/ConsoleApplication.java b/opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/ConsoleApplication.java
index 4308804..d68aa09 100755
--- a/opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/ConsoleApplication.java
+++ b/opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/ConsoleApplication.java
@@ -23,7 +23,7 @@
  *
  *
  *      Copyright 2008-2009 Sun Microsystems, Inc.
- *      Portions copyright 2011 ForgeRock AS
+ *      Portions copyright 2011-2012 ForgeRock AS
  *      Portions copyright 2011 Nemanja Lukić
  */
 package com.forgerock.opendj.ldap.tools;
@@ -46,7 +46,7 @@
  */
 abstract class ConsoleApplication
 {
-  private final PrintStream err = new PrintStream(System.out);
+  private final PrintStream err = new PrintStream(System.err);
 
   private final BufferedReader reader = new BufferedReader(
       new InputStreamReader(System.in));
@@ -70,6 +70,29 @@
 
 
   /**
+   * Closes the provided {@code Closeable} if it is not {@code null}.
+   *
+   * @param closeable
+   *          The closeable to be closed.
+   */
+  final void closeIfNotNull(Closeable closeable)
+  {
+    if (closeable != null)
+    {
+      try
+      {
+        closeable.close();
+      }
+      catch (Exception ignored)
+      {
+        // Do nothing.
+      }
+    }
+  }
+
+
+
+  /**
    * Returns the application error stream.
    *
    * @return The application error stream.
diff --git a/opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/LDIFDiff.java b/opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/LDIFDiff.java
new file mode 100644
index 0000000..a3e5380
--- /dev/null
+++ b/opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/LDIFDiff.java
@@ -0,0 +1,251 @@
+/*
+ * 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/opendj3/legal-notices/CDDLv1_0.txt
+ * or http://forgerock.org/license/CDDLv1.0.html.
+ * 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/opendj3/legal-notices/CDDLv1_0.txt.  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
+ *
+ *
+ *      Copyright 2012 ForgeRock AS
+ */
+
+package com.forgerock.opendj.ldap.tools;
+
+
+
+import static com.forgerock.opendj.ldap.tools.ToolConstants.*;
+import static com.forgerock.opendj.ldap.tools.ToolsMessages.*;
+import static com.forgerock.opendj.ldap.tools.Utils.filterExitCode;
+
+import java.io.*;
+import java.util.List;
+
+import org.forgerock.i18n.LocalizableException;
+import org.forgerock.i18n.LocalizableMessage;
+import org.forgerock.opendj.ldap.ResultCode;
+import org.forgerock.opendj.ldif.LDIF;
+import org.forgerock.opendj.ldif.LDIFChangeRecordWriter;
+import org.forgerock.opendj.ldif.LDIFEntryReader;
+
+
+
+/**
+ * This utility can be used to compare two LDIF files and report the differences
+ * in LDIF format.
+ */
+public final class LDIFDiff extends ConsoleApplication
+{
+
+  /**
+   * The main method for LDIFDiff tool.
+   *
+   * @param args
+   *          The command-line arguments provided to this program.
+   */
+
+  public static void main(final String[] args)
+  {
+    final int retCode = new LDIFDiff().run(args);
+    System.exit(filterExitCode(retCode));
+  }
+
+
+
+  private LDIFDiff()
+  {
+    // Nothing to do.
+  }
+
+
+
+  private int run(final String[] args)
+  {
+    // Create the command-line argument parser for use with this
+    // program.
+
+    final LocalizableMessage toolDescription = INFO_LDIFDIFF_TOOL_DESCRIPTION
+        .get();
+    final ArgumentParser argParser = new ArgumentParser(
+        LDIFDiff.class.getName(), toolDescription, false, true, 2, 2,
+        "source target");
+
+    final BooleanArgument showUsage;
+    final StringArgument outputFilename;
+
+    try
+    {
+      outputFilename = new StringArgument("outputFilename",
+          OPTION_SHORT_OUTPUT_LDIF_FILENAME, OPTION_LONG_OUTPUT_LDIF_FILENAME,
+          false, false, true, INFO_OUTPUT_LDIF_FILE_PLACEHOLDER.get(),
+          "stdout", null,
+          INFO_LDIFDIFF_DESCRIPTION_OUTPUT_FILENAME
+              .get(INFO_OUTPUT_LDIF_FILE_PLACEHOLDER.get()));
+      argParser.addArgument(outputFilename);
+
+      showUsage = new BooleanArgument("showUsage", OPTION_SHORT_HELP,
+          OPTION_LONG_HELP, INFO_DESCRIPTION_SHOWUSAGE.get());
+      argParser.addArgument(showUsage);
+      argParser.setUsageArgument(showUsage, getOutputStream());
+    }
+    catch (final ArgumentException ae)
+    {
+      final LocalizableMessage message = ERR_CANNOT_INITIALIZE_ARGS.get(ae
+          .getMessage());
+      println(message);
+      return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+    }
+
+    // Parse the command-line arguments provided to this program.
+    try
+    {
+      argParser.parseArguments(args);
+
+      // If we should just display usage or version information,
+      // then print it and exit.
+      if (argParser.usageOrVersionDisplayed())
+      {
+        return 0;
+      }
+    }
+    catch (final ArgumentException ae)
+    {
+      final LocalizableMessage message = ERR_ERROR_PARSING_ARGS.get(ae
+          .getMessage());
+      println(message);
+      return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+    }
+
+    InputStream sourceInputStream = null;
+    InputStream targetInputStream = null;
+    OutputStream outputStream = null;
+    LDIFEntryReader sourceReader = null;
+    LDIFEntryReader targetReader = null;
+    LDIFChangeRecordWriter outputWriter = null;
+
+    try
+    {
+      // First source file.
+      final List<String> trailingArguments = argParser.getTrailingArguments();
+      if (!trailingArguments.get(0).equals("-"))
+      {
+        try
+        {
+          sourceInputStream = new FileInputStream(trailingArguments.get(0));
+        }
+        catch (final FileNotFoundException e)
+        {
+          final LocalizableMessage message = ERR_LDIF_FILE_CANNOT_OPEN_FOR_READ
+              .get(trailingArguments.get(0), e.getLocalizedMessage());
+          println(message);
+          return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+        }
+      }
+
+      // Patch file.
+      if (!trailingArguments.get(1).equals("-"))
+      {
+        try
+        {
+          targetInputStream = new FileInputStream(trailingArguments.get(1));
+        }
+        catch (final FileNotFoundException e)
+        {
+          final LocalizableMessage message = ERR_LDIF_FILE_CANNOT_OPEN_FOR_READ
+              .get(trailingArguments.get(1), e.getLocalizedMessage());
+          println(message);
+          return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+        }
+      }
+
+      // Output file.
+      if (outputFilename.isPresent() && !outputFilename.getValue().equals("-"))
+      {
+        try
+        {
+          outputStream = new FileOutputStream(outputFilename.getValue());
+        }
+        catch (final FileNotFoundException e)
+        {
+          final LocalizableMessage message = ERR_LDIF_FILE_CANNOT_OPEN_FOR_WRITE
+              .get(outputFilename.getValue(), e.getLocalizedMessage());
+          println(message);
+          return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+        }
+      }
+
+      // Default to stdin/stdout for all streams if not specified.
+      if (sourceInputStream == null)
+      {
+        // Command line parameter was "-".
+        sourceInputStream = System.in;
+      }
+
+      if (targetInputStream == null)
+      {
+        targetInputStream = System.in;
+      }
+
+      if (outputStream == null)
+      {
+        outputStream = System.out;
+      }
+
+      // Check that we are not attempting to read both the source and target
+      // from stdin.
+      if (sourceInputStream == targetInputStream)
+      {
+        final LocalizableMessage message = ERR_LDIFDIFF_MULTIPLE_USES_OF_STDIN
+            .get();
+        println(message);
+        return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+      }
+
+      // Perform the diff.
+      sourceReader = new LDIFEntryReader(sourceInputStream);
+      targetReader = new LDIFEntryReader(targetInputStream);
+      outputWriter = new LDIFChangeRecordWriter(outputStream);
+      LDIF.copyTo(LDIF.diff(sourceReader, targetReader), outputWriter);
+    }
+    catch (final IOException e)
+    {
+      if (e instanceof LocalizableException)
+      {
+        println(ERR_LDIFDIFF_DIFF_FAILED.get(((LocalizableException) e)
+            .getMessageObject()));
+      }
+      else
+      {
+        println(ERR_LDIFDIFF_DIFF_FAILED.get(e.getLocalizedMessage()));
+      }
+      return ResultCode.CLIENT_SIDE_LOCAL_ERROR.intValue();
+    }
+    finally
+    {
+      closeIfNotNull(sourceReader);
+      closeIfNotNull(targetReader);
+      closeIfNotNull(outputWriter);
+
+      closeIfNotNull(sourceInputStream);
+      closeIfNotNull(targetInputStream);
+      closeIfNotNull(outputStream);
+    }
+
+    return ResultCode.SUCCESS.intValue();
+  }
+}
diff --git a/opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/LDIFModify.java b/opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/LDIFModify.java
new file mode 100644
index 0000000..561fca9
--- /dev/null
+++ b/opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/LDIFModify.java
@@ -0,0 +1,378 @@
+/*
+ * 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/opendj3/legal-notices/CDDLv1_0.txt
+ * or http://forgerock.org/license/CDDLv1.0.html.
+ * 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/opendj3/legal-notices/CDDLv1_0.txt.  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
+ *
+ *
+ *      Copyright 2012 ForgeRock AS
+ */
+
+package com.forgerock.opendj.ldap.tools;
+
+
+
+import static com.forgerock.opendj.ldap.tools.ToolConstants.*;
+import static com.forgerock.opendj.ldap.tools.ToolsMessages.*;
+import static com.forgerock.opendj.ldap.tools.Utils.filterExitCode;
+
+import java.io.*;
+import java.util.List;
+
+import org.forgerock.i18n.LocalizableException;
+import org.forgerock.i18n.LocalizableMessage;
+import org.forgerock.opendj.ldap.DecodeException;
+import org.forgerock.opendj.ldap.Entry;
+import org.forgerock.opendj.ldap.ResultCode;
+import org.forgerock.opendj.ldap.requests.AddRequest;
+import org.forgerock.opendj.ldap.requests.DeleteRequest;
+import org.forgerock.opendj.ldap.requests.ModifyDNRequest;
+import org.forgerock.opendj.ldap.requests.ModifyRequest;
+import org.forgerock.opendj.ldif.*;
+
+
+
+/**
+ * A tool that can be used to issue update (Add/Delete/Modify/ModifyDN) requests
+ * to a set of entries contained in an LDIF file.
+ */
+public final class LDIFModify extends ConsoleApplication
+{
+
+  /**
+   * The main method for LDIFModify tool.
+   *
+   * @param args
+   *          The command-line arguments provided to this program.
+   */
+
+  public static void main(final String[] args)
+  {
+    final int retCode = new LDIFModify().run(args);
+    System.exit(filterExitCode(retCode));
+  }
+
+
+
+  private LDIFModify()
+  {
+    // Nothing to do.
+  }
+
+
+
+  private int run(final String[] args)
+  {
+    // Create the command-line argument parser for use with this
+    // program.
+
+    final LocalizableMessage toolDescription = INFO_LDIFMODIFY_TOOL_DESCRIPTION
+        .get();
+    final ArgumentParser argParser = new ArgumentParser(
+        LDIFModify.class.getName(), toolDescription, false, true, 1, 2,
+        "source [changes]");
+
+    final BooleanArgument continueOnError;
+    final BooleanArgument showUsage;
+    final StringArgument outputFilename;
+
+    try
+    {
+      outputFilename = new StringArgument("outputFilename",
+          OPTION_SHORT_OUTPUT_LDIF_FILENAME, OPTION_LONG_OUTPUT_LDIF_FILENAME,
+          false, false, true, INFO_OUTPUT_LDIF_FILE_PLACEHOLDER.get(),
+          "stdout", null,
+          INFO_LDIFMODIFY_DESCRIPTION_OUTPUT_FILENAME
+              .get(INFO_OUTPUT_LDIF_FILE_PLACEHOLDER.get()));
+      argParser.addArgument(outputFilename);
+
+      continueOnError = new BooleanArgument("continueOnError", 'c',
+          "continueOnError", INFO_DESCRIPTION_CONTINUE_ON_ERROR.get());
+      continueOnError.setPropertyName("continueOnError");
+      argParser.addArgument(continueOnError);
+
+      showUsage = new BooleanArgument("showUsage", OPTION_SHORT_HELP,
+          OPTION_LONG_HELP, INFO_DESCRIPTION_SHOWUSAGE.get());
+      argParser.addArgument(showUsage);
+      argParser.setUsageArgument(showUsage, getOutputStream());
+    }
+    catch (final ArgumentException ae)
+    {
+      final LocalizableMessage message = ERR_CANNOT_INITIALIZE_ARGS.get(ae
+          .getMessage());
+      println(message);
+      return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+    }
+
+    // Parse the command-line arguments provided to this program.
+    try
+    {
+      argParser.parseArguments(args);
+
+      // If we should just display usage or version information,
+      // then print it and exit.
+      if (argParser.usageOrVersionDisplayed())
+      {
+        return 0;
+      }
+    }
+    catch (final ArgumentException ae)
+    {
+      final LocalizableMessage message = ERR_ERROR_PARSING_ARGS.get(ae
+          .getMessage());
+      println(message);
+      return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+    }
+
+    InputStream sourceInputStream = null;
+    InputStream changesInputStream = null;
+    OutputStream outputStream = null;
+    LDIFEntryReader sourceReader = null;
+    LDIFChangeRecordReader changesReader = null;
+    LDIFEntryWriter outputWriter = null;
+
+    try
+    {
+      // First source file.
+      final List<String> trailingArguments = argParser.getTrailingArguments();
+      if (!trailingArguments.get(0).equals("-"))
+      {
+        try
+        {
+          sourceInputStream = new FileInputStream(trailingArguments.get(0));
+        }
+        catch (final FileNotFoundException e)
+        {
+          final LocalizableMessage message = ERR_LDIF_FILE_CANNOT_OPEN_FOR_READ
+              .get(trailingArguments.get(0), e.getLocalizedMessage());
+          println(message);
+          return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+        }
+      }
+
+      // Patch file.
+      if (trailingArguments.size() > 1 && !trailingArguments.get(1).equals("-"))
+      {
+        try
+        {
+          changesInputStream = new FileInputStream(trailingArguments.get(1));
+        }
+        catch (final FileNotFoundException e)
+        {
+          final LocalizableMessage message = ERR_LDIF_FILE_CANNOT_OPEN_FOR_READ
+              .get(trailingArguments.get(1), e.getLocalizedMessage());
+          println(message);
+          return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+        }
+      }
+
+      // Output file.
+      if (outputFilename.isPresent() && !outputFilename.getValue().equals("-"))
+      {
+        try
+        {
+          outputStream = new FileOutputStream(outputFilename.getValue());
+        }
+        catch (final FileNotFoundException e)
+        {
+          final LocalizableMessage message = ERR_LDIF_FILE_CANNOT_OPEN_FOR_WRITE
+              .get(outputFilename.getValue(), e.getLocalizedMessage());
+          println(message);
+          return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+        }
+      }
+
+      // Default to stdin/stdout for all streams if not specified.
+      if (sourceInputStream == null)
+      {
+        // Command line parameter was "-".
+        sourceInputStream = System.in;
+      }
+
+      if (changesInputStream == null)
+      {
+        changesInputStream = System.in;
+      }
+
+      if (outputStream == null)
+      {
+        outputStream = System.out;
+      }
+
+      // Check that we are not attempting to read both the source and changes
+      // from stdin.
+      if (sourceInputStream == changesInputStream)
+      {
+        final LocalizableMessage message = ERR_LDIFMODIFY_MULTIPLE_USES_OF_STDIN
+            .get();
+        println(message);
+        return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+      }
+
+      // Apply the changes.
+      sourceReader = new LDIFEntryReader(sourceInputStream);
+      changesReader = new LDIFChangeRecordReader(changesInputStream);
+      outputWriter = new LDIFEntryWriter(outputStream);
+
+      final RejectedChangeRecordListener listener = new RejectedChangeRecordListener()
+      {
+        public Entry handleDuplicateEntry(final AddRequest change,
+            final Entry existingEntry) throws DecodeException
+        {
+          try
+          {
+            RejectedChangeRecordListener.FAIL_FAST.handleDuplicateEntry(change,
+                existingEntry);
+          }
+          catch (final DecodeException e)
+          {
+            logErrorOrFail(e);
+          }
+          return change;
+        }
+
+
+
+        public Entry handleDuplicateEntry(final ModifyDNRequest change,
+            final Entry existingEntry, final Entry renamedEntry)
+            throws DecodeException
+        {
+          try
+          {
+            RejectedChangeRecordListener.FAIL_FAST.handleDuplicateEntry(change,
+                existingEntry, renamedEntry);
+          }
+          catch (final DecodeException e)
+          {
+            logErrorOrFail(e);
+          }
+          return renamedEntry;
+        }
+
+
+
+        public void handleRejectedChangeRecord(final AddRequest change,
+            final LocalizableMessage reason) throws DecodeException
+        {
+          try
+          {
+            RejectedChangeRecordListener.FAIL_FAST.handleRejectedChangeRecord(
+                change, reason);
+          }
+          catch (final DecodeException e)
+          {
+            logErrorOrFail(e);
+          }
+        }
+
+
+
+        public void handleRejectedChangeRecord(final DeleteRequest change,
+            final LocalizableMessage reason) throws DecodeException
+        {
+          try
+          {
+            RejectedChangeRecordListener.FAIL_FAST.handleRejectedChangeRecord(
+                change, reason);
+          }
+          catch (final DecodeException e)
+          {
+            logErrorOrFail(e);
+          }
+        }
+
+
+
+        public void handleRejectedChangeRecord(final ModifyDNRequest change,
+            final LocalizableMessage reason) throws DecodeException
+        {
+          try
+          {
+            RejectedChangeRecordListener.FAIL_FAST.handleRejectedChangeRecord(
+                change, reason);
+          }
+          catch (final DecodeException e)
+          {
+            logErrorOrFail(e);
+          }
+        }
+
+
+
+        public void handleRejectedChangeRecord(final ModifyRequest change,
+            final LocalizableMessage reason) throws DecodeException
+        {
+          try
+          {
+            RejectedChangeRecordListener.FAIL_FAST.handleRejectedChangeRecord(
+                change, reason);
+          }
+          catch (final DecodeException e)
+          {
+            logErrorOrFail(e);
+          }
+        }
+
+
+
+        private void logErrorOrFail(final DecodeException e)
+            throws DecodeException
+        {
+          if (continueOnError.isPresent())
+          {
+            println(e.getMessageObject());
+          }
+          else
+          {
+            throw e;
+          }
+        }
+      };
+
+      LDIF.copyTo(LDIF.patch(sourceReader, changesReader, listener),
+          outputWriter);
+    }
+    catch (final IOException e)
+    {
+      if (e instanceof LocalizableException)
+      {
+        println(ERR_LDIFMODIFY_PATCH_FAILED.get(((LocalizableException) e)
+            .getMessageObject()));
+      }
+      else
+      {
+        println(ERR_LDIFMODIFY_PATCH_FAILED.get(e.getLocalizedMessage()));
+      }
+      return ResultCode.CLIENT_SIDE_LOCAL_ERROR.intValue();
+    }
+    finally
+    {
+      closeIfNotNull(sourceReader);
+      closeIfNotNull(changesReader);
+      closeIfNotNull(outputWriter);
+
+      closeIfNotNull(sourceInputStream);
+      closeIfNotNull(changesInputStream);
+      closeIfNotNull(outputStream);
+    }
+
+    return ResultCode.SUCCESS.intValue();
+  }
+}
diff --git a/opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/LDIFSearch.java b/opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/LDIFSearch.java
new file mode 100644
index 0000000..f157417
--- /dev/null
+++ b/opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/LDIFSearch.java
@@ -0,0 +1,363 @@
+/*
+ * 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/opendj3/legal-notices/CDDLv1_0.txt
+ * or http://forgerock.org/license/CDDLv1.0.html.
+ * 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/opendj3/legal-notices/CDDLv1_0.txt.  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
+ *
+ *
+ *      Copyright 2012 ForgeRock AS
+ */
+
+package com.forgerock.opendj.ldap.tools;
+
+
+
+import static com.forgerock.opendj.ldap.tools.ToolConstants.*;
+import static com.forgerock.opendj.ldap.tools.ToolsMessages.*;
+import static com.forgerock.opendj.ldap.tools.Utils.filterExitCode;
+
+import java.io.*;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.forgerock.i18n.LocalizableException;
+import org.forgerock.i18n.LocalizableMessage;
+import org.forgerock.i18n.LocalizedIllegalArgumentException;
+import org.forgerock.opendj.ldap.DN;
+import org.forgerock.opendj.ldap.Filter;
+import org.forgerock.opendj.ldap.ResultCode;
+import org.forgerock.opendj.ldap.SearchScope;
+import org.forgerock.opendj.ldap.requests.Requests;
+import org.forgerock.opendj.ldap.requests.SearchRequest;
+import org.forgerock.opendj.ldif.LDIF;
+import org.forgerock.opendj.ldif.LDIFEntryReader;
+import org.forgerock.opendj.ldif.LDIFEntryWriter;
+
+
+
+/**
+ * This utility can be used to perform search operations against data in an LDIF
+ * file.
+ */
+public final class LDIFSearch extends ConsoleApplication
+{
+
+  /**
+   * The main method for LDIFSearch tool.
+   *
+   * @param args
+   *          The command-line arguments provided to this program.
+   */
+
+  public static void main(final String[] args)
+  {
+    final int retCode = new LDIFSearch().run(args);
+    System.exit(filterExitCode(retCode));
+  }
+
+
+
+  private LDIFSearch()
+  {
+    // Nothing to do.
+  }
+
+
+
+  private int run(final String[] args)
+  {
+    // Create the command-line argument parser for use with this
+    // program.
+
+    final LocalizableMessage toolDescription = INFO_LDIFSEARCH_TOOL_DESCRIPTION
+        .get();
+    final ArgumentParser argParser = new ArgumentParser(
+        LDIFSearch.class.getName(), toolDescription, false, true, 1, 0,
+        "source [filter] [attributes ...]");
+
+    final BooleanArgument showUsage;
+    final StringArgument outputFilename;
+    final BooleanArgument typesOnly;
+    final IntegerArgument timeLimit;
+    final StringArgument filename;
+    final StringArgument baseDN;
+    final MultiChoiceArgument<SearchScope> searchScope;
+    final IntegerArgument sizeLimit;
+
+    try
+    {
+      outputFilename = new StringArgument("outputFilename",
+          OPTION_SHORT_OUTPUT_LDIF_FILENAME, OPTION_LONG_OUTPUT_LDIF_FILENAME,
+          false, false, true, INFO_OUTPUT_LDIF_FILE_PLACEHOLDER.get(),
+          "stdout", null,
+          INFO_LDIFSEARCH_DESCRIPTION_OUTPUT_FILENAME
+              .get(INFO_OUTPUT_LDIF_FILE_PLACEHOLDER.get()));
+      argParser.addArgument(outputFilename);
+
+      baseDN = new StringArgument("baseDN", OPTION_SHORT_BASEDN,
+          OPTION_LONG_BASEDN, true, false, true, INFO_BASEDN_PLACEHOLDER.get(),
+          null, null, INFO_SEARCH_DESCRIPTION_BASEDN.get());
+      baseDN.setPropertyName(OPTION_LONG_BASEDN);
+      argParser.addArgument(baseDN);
+
+      searchScope = new MultiChoiceArgument<SearchScope>("searchScope", 's',
+          "searchScope", false, true, INFO_SEARCH_SCOPE_PLACEHOLDER.get(),
+          SearchScope.values(), false,
+          INFO_SEARCH_DESCRIPTION_SEARCH_SCOPE.get());
+      searchScope.setPropertyName("searchScope");
+      searchScope.setDefaultValue(SearchScope.WHOLE_SUBTREE);
+      argParser.addArgument(searchScope);
+
+      filename = new StringArgument("filename", OPTION_SHORT_FILENAME,
+          OPTION_LONG_FILENAME, false, false, true,
+          INFO_FILE_PLACEHOLDER.get(), null, null,
+          INFO_SEARCH_DESCRIPTION_FILENAME.get());
+      searchScope.setPropertyName(OPTION_LONG_FILENAME);
+      argParser.addArgument(filename);
+
+      typesOnly = new BooleanArgument("typesOnly", 'A', "typesOnly",
+          INFO_DESCRIPTION_TYPES_ONLY.get());
+      typesOnly.setPropertyName("typesOnly");
+      argParser.addArgument(typesOnly);
+
+      sizeLimit = new IntegerArgument("sizeLimit", 'z', "sizeLimit", false,
+          false, true, INFO_SIZE_LIMIT_PLACEHOLDER.get(), 0, null,
+          INFO_SEARCH_DESCRIPTION_SIZE_LIMIT.get());
+      sizeLimit.setPropertyName("sizeLimit");
+      argParser.addArgument(sizeLimit);
+
+      timeLimit = new IntegerArgument("timeLimit", 'l', "timeLimit", false,
+          false, true, INFO_TIME_LIMIT_PLACEHOLDER.get(), 0, null,
+          INFO_SEARCH_DESCRIPTION_TIME_LIMIT.get());
+      timeLimit.setPropertyName("timeLimit");
+      argParser.addArgument(timeLimit);
+
+      showUsage = new BooleanArgument("showUsage", OPTION_SHORT_HELP,
+          OPTION_LONG_HELP, INFO_DESCRIPTION_SHOWUSAGE.get());
+      argParser.addArgument(showUsage);
+      argParser.setUsageArgument(showUsage, getOutputStream());
+    }
+    catch (final ArgumentException ae)
+    {
+      final LocalizableMessage message = ERR_CANNOT_INITIALIZE_ARGS.get(ae
+          .getMessage());
+      println(message);
+      return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+    }
+
+    // Parse the command-line arguments provided to this program.
+    try
+    {
+      argParser.parseArguments(args);
+
+      // If we should just display usage or version information,
+      // then print it and exit.
+      if (argParser.usageOrVersionDisplayed())
+      {
+        return 0;
+      }
+    }
+    catch (final ArgumentException ae)
+    {
+      final LocalizableMessage message = ERR_ERROR_PARSING_ARGS.get(ae
+          .getMessage());
+      println(message);
+      return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+    }
+
+    final List<Filter> filters = new LinkedList<Filter>();
+    final List<String> attributes = new LinkedList<String>();
+    final List<String> trailingArguments = argParser.getTrailingArguments();
+    if (trailingArguments.size() > 1)
+    {
+      final List<String> filterAndAttributeStrings = trailingArguments.subList(
+          1, trailingArguments.size());
+
+      // the list of trailing arguments should be structured as follow:
+      // - If a filter file is present, trailing arguments are
+      // considered as attributes
+      // - If filter file is not present, the first trailing argument is
+      // considered the filter, the other as attributes.
+      if (!filename.isPresent())
+      {
+        final String filterString = filterAndAttributeStrings.remove(0);
+        try
+        {
+          filters.add(Filter.valueOf(filterString));
+        }
+        catch (final LocalizedIllegalArgumentException e)
+        {
+          println(e.getMessageObject());
+          return ResultCode.CLIENT_SIDE_FILTER_ERROR.intValue();
+        }
+      }
+      // The rest are attributes
+      for (final String s : filterAndAttributeStrings)
+      {
+        attributes.add(s);
+      }
+    }
+
+    if (filename.isPresent())
+    {
+      // Read the filter strings.
+      BufferedReader in = null;
+      try
+      {
+        in = new BufferedReader(new FileReader(filename.getValue()));
+        String line = null;
+
+        while ((line = in.readLine()) != null)
+        {
+          if (line.trim().equals(""))
+          {
+            // ignore empty lines.
+            continue;
+          }
+          final Filter ldapFilter = Filter.valueOf(line);
+          filters.add(ldapFilter);
+        }
+      }
+      catch (final LocalizedIllegalArgumentException e)
+      {
+        println(e.getMessageObject());
+        return ResultCode.CLIENT_SIDE_FILTER_ERROR.intValue();
+      }
+      catch (final IOException e)
+      {
+        println(LocalizableMessage.raw(e.toString()));
+        return ResultCode.CLIENT_SIDE_FILTER_ERROR.intValue();
+      }
+      finally
+      {
+        closeIfNotNull(in);
+      }
+    }
+
+    if (filters.isEmpty())
+    {
+      println(ERR_SEARCH_NO_FILTERS.get());
+      println(argParser.getUsageMessage());
+      return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+    }
+
+    final SearchRequest search;
+    try
+    {
+      final SearchScope scope = searchScope.getTypedValue();
+      search = Requests
+          .newSearchRequest(DN.valueOf(baseDN.getValue()), scope,
+              filters.get(0), attributes.toArray(new String[attributes.size()]))
+          .setTypesOnly(typesOnly.isPresent())
+          .setTimeLimit(timeLimit.getIntValue())
+          .setSizeLimit(sizeLimit.getIntValue());
+    }
+    catch (final ArgumentException e)
+    {
+      println(e.getMessageObject());
+      return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+    }
+    catch (final LocalizedIllegalArgumentException e)
+    {
+      println(e.getMessageObject());
+      return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+    }
+
+    InputStream sourceInputStream = null;
+    OutputStream outputStream = null;
+    LDIFEntryReader sourceReader = null;
+    LDIFEntryWriter outputWriter = null;
+
+    try
+    {
+      // First source file.
+      if (!trailingArguments.get(0).equals("-"))
+      {
+        try
+        {
+          sourceInputStream = new FileInputStream(trailingArguments.get(0));
+        }
+        catch (final FileNotFoundException e)
+        {
+          final LocalizableMessage message = ERR_LDIF_FILE_CANNOT_OPEN_FOR_READ
+              .get(trailingArguments.get(0), e.getLocalizedMessage());
+          println(message);
+          return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+        }
+      }
+
+      // Output file.
+      if (outputFilename.isPresent() && !outputFilename.getValue().equals("-"))
+      {
+        try
+        {
+          outputStream = new FileOutputStream(outputFilename.getValue());
+        }
+        catch (final FileNotFoundException e)
+        {
+          final LocalizableMessage message = ERR_LDIF_FILE_CANNOT_OPEN_FOR_WRITE
+              .get(outputFilename.getValue(), e.getLocalizedMessage());
+          println(message);
+          return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+        }
+      }
+
+      // Default to stdin/stdout for all streams if not specified.
+      if (sourceInputStream == null)
+      {
+        // Command line parameter was "-".
+        sourceInputStream = System.in;
+      }
+
+      if (outputStream == null)
+      {
+        outputStream = System.out;
+      }
+
+      // Perform the search.
+      sourceReader = new LDIFEntryReader(sourceInputStream);
+      outputWriter = new LDIFEntryWriter(outputStream);
+      LDIF.copyTo(LDIF.search(sourceReader, search), outputWriter);
+    }
+    catch (final IOException e)
+    {
+      if (e instanceof LocalizableException)
+      {
+        println(ERR_LDIFSEARCH_FAILED.get(((LocalizableException) e)
+            .getMessageObject()));
+      }
+      else
+      {
+        println(ERR_LDIFSEARCH_FAILED.get(e.getLocalizedMessage()));
+      }
+      return ResultCode.CLIENT_SIDE_LOCAL_ERROR.intValue();
+    }
+    finally
+    {
+      closeIfNotNull(sourceReader);
+      closeIfNotNull(outputWriter);
+
+      closeIfNotNull(sourceInputStream);
+      closeIfNotNull(outputStream);
+    }
+
+    return ResultCode.SUCCESS.intValue();
+  }
+}
diff --git a/opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/ToolConstants.java b/opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/ToolConstants.java
index 3298b18..ce3688e 100755
--- a/opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/ToolConstants.java
+++ b/opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/ToolConstants.java
@@ -23,6 +23,7 @@
  *
  *
  *      Copyright 2006-2010 Sun Microsystems, Inc.
+ *      Portions copyright 2012 ForgeRock AS.
  */
 package com.forgerock.opendj.ldap.tools;
 
@@ -608,6 +609,17 @@
    */
   static final String LIST_TABLE_SEPARATOR = ":";
 
+  /**
+   *
+   * The value for the short option output LDIF filename.
+   */
+  static final char OPTION_SHORT_OUTPUT_LDIF_FILENAME= 'o';
+
+  /**
+   * The value for the long option output LDIF filename.
+   */
+  static final String OPTION_LONG_OUTPUT_LDIF_FILENAME = "outputLDIF";
+
 
 
   // Prevent instantiation.
diff --git a/opendj3/opendj-ldap-toolkit/src/main/resources/com/forgerock/opendj/ldap/tools/tools.properties b/opendj3/opendj-ldap-toolkit/src/main/resources/com/forgerock/opendj/ldap/tools/tools.properties
index 95cfa74..bb49818 100755
--- a/opendj3/opendj-ldap-toolkit/src/main/resources/com/forgerock/opendj/ldap/tools/tools.properties
+++ b/opendj3/opendj-ldap-toolkit/src/main/resources/com/forgerock/opendj/ldap/tools/tools.properties
@@ -23,12 +23,7 @@
 #
 #
 #      Copyright 2010 Sun Microsystems, Inc.
-#
-#
-# Core messages
-#
-#
-# Protocol messages
+#      Portions copyright 2012 ForgeRock AS.
 #
 #
 # Utility messages
@@ -246,6 +241,8 @@
  filter was invalid:  %s
 ERR_LDIF_FILE_CANNOT_OPEN_FOR_READ=An error occurred while \
  attempting to open the LDIF file %s for reading:  %s
+ERR_LDIF_FILE_CANNOT_OPEN_FOR_WRITE=An error occurred while \
+ attempting to open the LDIF file %s for writing:  %s
 ERR_LDIF_FILE_READ_ERROR=An error occurred while attempting to read \
  the contents of LDIF file %s:  %s
 INFO_BIND_PASSWORD_EXPIRED=# Your password has expired
@@ -444,6 +441,26 @@
   options. A search operation may be used to retrieve the bind DN by \
   specifying the base DN and a filter. The retrieved entry DN will be appended \
   as the last argument in the argument list when evaluating format strings.
-
-
-
+INFO_OUTPUT_LDIF_FILE_PLACEHOLDER={file}
+INFO_LDIFMODIFY_DESCRIPTION_OUTPUT_FILENAME=Write updated entries to %s \
+ instead of stdout
+INFO_LDIFDIFF_DESCRIPTION_OUTPUT_FILENAME=Write differences to %s \
+ instead of stdout
+INFO_LDIFSEARCH_DESCRIPTION_OUTPUT_FILENAME=Write search results to %s \
+ instead of stdout
+ERR_LDIFMODIFY_MULTIPLE_USES_OF_STDIN=Unable to use stdin for both the source \
+ LDIF and changes LDIF
+ERR_LDIFDIFF_MULTIPLE_USES_OF_STDIN=Unable to use stdin for both the source \
+ LDIF and target LDIF
+ERR_LDIFMODIFY_PATCH_FAILED=The changes could not be applied for the following \
+ reason: %s
+ERR_LDIFDIFF_DIFF_FAILED=The differences could not be computed for the following \
+ reason: %s
+ERR_LDIFSEARCH_FAILED=The search could not be performed for the following \
+ reason: %s
+INFO_LDIFMODIFY_TOOL_DESCRIPTION=This utility can be used to apply a set of \
+ modify, add, and delete operations to entries contained in an LDIF file
+INFO_LDIFDIFF_TOOL_DESCRIPTION=This utility can be used to compare two LDIF \
+ files and report the differences in LDIF format
+INFO_LDIFSEARCH_TOOL_DESCRIPTION=This utility can be used to perform search \
+ operations against entries contained in an LDIF file
diff --git a/opendj3/opendj-ldap-toolkit/src/site/xdoc/index.xml.vm b/opendj3/opendj-ldap-toolkit/src/site/xdoc/index.xml.vm
index ce43833..64d4a6c 100644
--- a/opendj3/opendj-ldap-toolkit/src/site/xdoc/index.xml.vm
+++ b/opendj3/opendj-ldap-toolkit/src/site/xdoc/index.xml.vm
@@ -38,6 +38,9 @@
        <dt>ldapmodify</dt><dd>perform LDAP modify, add, delete, mod DN operations</dd>
        <dt>ldappasswordmodify</dt><dd>perform LDAP password modifications</dd>
        <dt>ldapsearch</dt><dd>perform LDAP search operations</dd>
+       <dt>ldifmodify</dt><dd>perform LDAP modify, add, delete, mod DN operations against entries contained in an LDIF file</dd>
+       <dt>ldifsearch</dt><dd>perform search operations against entries contained in an LDIF file</dd>
+       <dt>ldifdiff</dt><dd>compare two LDIF files and report the differences in LDIF format</dd>
        <dt>modrate</dt><dd>measure modification throughput and response time</dd>
        <dt>searchrate</dt><dd>measure search throughput and response time</dd>
       </dl>

--
Gitblit v1.10.0