From e1e9596f6ae81d9aeb74177cf2792533966f45eb Mon Sep 17 00:00:00 2001
From: kenneth_suter <kenneth_suter@localhost>
Date: Mon, 23 Jul 2007 18:25:05 +0000
Subject: [PATCH] This commit does some initial work in anticipation of the reverter tool:

---
 opends/src/quicksetup/org/opends/quicksetup/resources/Resources.properties             |   44 +
 opends/src/quicksetup/org/opends/quicksetup/upgrader/VersionIssueNotifier.java         |    6 
 opends/src/quicksetup/org/opends/quicksetup/upgrader/ReversionProgressStep.java        |  103 ++
 opends/src/quicksetup/org/opends/quicksetup/CliApplication.java                        |   13 
 opends/src/quicksetup/org/opends/quicksetup/upgrader/UpgradeIssueNotifier.java         |   12 
 opends/src/quicksetup/org/opends/quicksetup/upgrader/BuildExtractor.java               |    8 
 opends/src/quicksetup/org/opends/quicksetup/installandupgrader/InstallAndUpgrader.java |    2 
 opends/src/quicksetup/org/opends/quicksetup/QuickSetupCli.java                         |   66 
 opends/src/quicksetup/org/opends/quicksetup/ui/GuiApplication.java                     |   15 
 opends/src/quicksetup/org/opends/quicksetup/CliApplicationHelper.java                  |    2 
 opends/src/quicksetup/org/opends/quicksetup/upgrader/BuildExtractorCliHelper.java      |    3 
 opends/src/quicksetup/org/opends/quicksetup/uninstaller/UninstallCliHelper.java        |    5 
 opends/src/quicksetup/org/opends/quicksetup/HistoricalRecord.java                      |   10 
 opends/src/quicksetup/org/opends/quicksetup/upgrader/UpgradeProgressStep.java          |  128 +++
 opends/src/quicksetup/org/opends/quicksetup/upgrader/UpgradeLauncher.java              |  101 +
 opends/src/quicksetup/org/opends/quicksetup/installer/InstallLauncher.java             |   96 +-
 opends/src/quicksetup/org/opends/quicksetup/Installation.java                          |   21 
 opends/src/quicksetup/org/opends/quicksetup/upgrader/ReversionLauncher.java            |  216 +++++
 opends/src/quicksetup/org/opends/quicksetup/uninstaller/Uninstaller.java               |    7 
 opends/src/quicksetup/org/opends/quicksetup/upgrader/ReverterUserData.java             |   57 +
 opends/src/quicksetup/org/opends/quicksetup/ProgressUpdateListenerDelegate.java        |  123 +++
 opends/resource/revert                                                                 |  155 +++
 opends/src/server/org/opends/server/messages/ToolMessages.java                         |   41 +
 opends/src/quicksetup/org/opends/quicksetup/HistoricalLog.java                         |    5 
 opends/src/quicksetup/org/opends/quicksetup/upgrader/UpgradeFileFilter.java            |   72 +
 opends/src/quicksetup/org/opends/quicksetup/upgrader/Reverter.java                     |  709 +++++++++++++++++
 opends/src/quicksetup/org/opends/quicksetup/Launcher.java                              |   42 
 opends/src/quicksetup/org/opends/quicksetup/upgrader/UpgraderCliHelper.java            |   11 
 opends/src/quicksetup/org/opends/quicksetup/uninstaller/UninstallLauncher.java         |   82 +
 opends/src/quicksetup/org/opends/quicksetup/upgrader/Upgrader.java                     |  199 ----
 opends/src/quicksetup/org/opends/quicksetup/Application.java                           |   93 +
 opends/src/quicksetup/org/opends/quicksetup/QuickSetupLog.java                         |    3 
 32 files changed, 2,030 insertions(+), 420 deletions(-)

diff --git a/opends/resource/revert b/opends/resource/revert
new file mode 100755
index 0000000..50b440d
--- /dev/null
+++ b/opends/resource/revert
@@ -0,0 +1,155 @@
+#!/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-2007 Sun Microsystems, Inc.
+
+
+# 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
+    if test -f "${INSTANCE_ROOT}/lib/set-java-home"
+    then
+      . "${INSTANCE_ROOT}/lib/set-java-home"
+      JAVA_BIN="${JAVA_HOME}/bin/java"
+      export JAVA_BIN
+    else
+      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 (or later) installation."
+        exit 1
+      fi
+    fi
+  else
+    JAVA_BIN="${JAVA_HOME}/bin/java"
+    export JAVA_BIN
+    export JAVA_WS
+  fi
+fi
+
+
+# Explicitly set the PATH, LD_LIBRARY_PATH, LD_PRELOAD, and other important
+# system environment variables for security and compatibility reasons.
+PATH=/bin:/usr/bin
+LD_LIBRARY_PATH=
+LD_LIBRARY_PATH_32=
+LD_LIBRARY_PATH_64=
+LD_PRELOAD=
+LD_PRELOAD_32=
+LD_PRELOAD_64=
+export PATH LD_LIBRARY_PATH LD_LIBRARY_PATH_32 LD_LIBRARY_PATH_64 \
+       LD_PRELOAD LD_PRELOAD_32 LD_PRELOAD_34
+
+
+# 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`
+
+INSTANCE_ROOT=${SCRIPT_DIR}
+export INSTANCE_ROOT
+
+cd "${WORKING_DIR}"
+
+
+# Configure the appropriate CLASSPATH to test.
+for JAR in ${INSTANCE_ROOT}/tmp/upgrade/lib/*.jar
+do
+  CLASSPATH=${CLASSPATH}:${JAR}
+done
+CLASSPATH=${CLASSPATH}:${INSTANCE_ROOT}/classes
+for JAR in ${INSTANCE_ROOT}/lib/*.jar
+do
+  CLASSPATH=${CLASSPATH}:${JAR}
+done
+export CLASSPATH
+
+# Determine whether the detected Java environment is acceptable for use.
+if test -z "${JAVA_ARGS}"
+then
+  "${JAVA_BIN}" -client org.opends.server.tools.InstallDS -t 2> /dev/null
+  if test ${?} -eq 0
+  then
+    JAVA_ARGS="-client"
+  else
+    "${JAVA_BIN}" org.opends.server.tools.InstallDS -t 2> /dev/null
+    if test ${?} -ne 0
+    then
+      echo "ERROR:  The detected Java version could not be used.  Please set "
+      echo "        JAVA_HOME to the root of a Java 5 (or later) installation."
+      exit 1
+    fi
+  fi
+else
+  "${JAVA_BIN}" ${JAVA_ARGS} org.opends.server.tools.InstallDS -t 2> /dev/null
+  if test ${?} -ne 0
+  then
+    echo "ERROR:  The detected Java version could not be used.  Please set "
+    echo "        JAVA_HOME to the root of a Java 5.0 installation."
+    exit 1
+  fi
+fi
+
+if [ -r "${INSTANCE_ROOT}/tmp/upgrade" ]
+then
+  rm -fr "${INSTANCE_ROOT}/tmp/upgrade"
+fi
+
+# Copy jars to a temporary place from which to run the reverter
+# in order to avoid potential file lock issues.
+mkdir -p tmp/revert
+cp -R lib tmp/revert
+if test ${?} -ne 0
+then
+  echo "ERROR:  Failed to initialize reversion."
+  exit 101
+else
+  CLASSPATH=${INSTANCE_ROOT}/tmp/revert/classes
+  for JAR in ${INSTANCE_ROOT}/tmp/revert/lib/*.jar
+  do
+    CLASSPATH=${JAR}:${CLASSPATH}
+  done
+  # Launch the upgrade process.
+  "${JAVA_BIN}" -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005 org.opends.quicksetup.upgrader.ReversionLauncher "${@}"
+  RETURN_CODE=$?
+  if test ${RETURN_CODE} -eq 0
+  then 
+    exit 0    
+  elif test ${RETURN_CODE} -eq 50
+  then
+    # Version info was on requested
+    exit 0
+  else
+    exit 101
+  fi
+fi
diff --git a/opends/src/quicksetup/org/opends/quicksetup/Application.java b/opends/src/quicksetup/org/opends/quicksetup/Application.java
index 594c160..789d738 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/Application.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/Application.java
@@ -30,7 +30,6 @@
 import org.opends.admin.ads.util.ApplicationTrustManager;
 import org.opends.quicksetup.event.ProgressNotifier;
 import org.opends.quicksetup.event.ProgressUpdateListener;
-import org.opends.quicksetup.event.ProgressUpdateEvent;
 import org.opends.quicksetup.util.ServerController;
 import org.opends.quicksetup.util.Utils;
 import org.opends.quicksetup.util.ProgressMessageFormatter;
@@ -39,9 +38,10 @@
 
 import java.io.PrintStream;
 import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
 import java.util.logging.Level;
 import java.util.logging.Logger;
-import java.util.HashSet;
 
 /**
  * This class represents an application that can be run in the context of
@@ -56,9 +56,6 @@
   /** Represents current install state. */
   protected CurrentInstallStatus installStatus;
 
-  private HashSet<ProgressUpdateListener> listeners =
-      new HashSet<ProgressUpdateListener>();
-
   private UserData userData;
 
   private Installation installation;
@@ -70,6 +67,9 @@
   /** Formats progress messages. */
   protected ProgressMessageFormatter formatter;
 
+  /** Handler for listeners and event firing. */
+  protected ProgressUpdateListenerDelegate listenerDelegate;
+
   /**
    * Creates an application by instantiating the Application class
    * denoted by the System property
@@ -138,7 +138,7 @@
    */
   public void addProgressUpdateListener(ProgressUpdateListener l)
   {
-    listeners.add(l);
+    listenerDelegate.addProgressUpdateListener(l);
   }
 
   /**
@@ -147,7 +147,7 @@
    */
   public void removeProgressUpdateListener(ProgressUpdateListener l)
   {
-    listeners.remove(l);
+    listenerDelegate.removeProgressUpdateListener(l);
   }
 
   /**
@@ -224,13 +224,8 @@
   public void notifyListeners(Integer ratio, String currentPhaseSummary,
       String newLogDetail)
   {
-    ProgressUpdateEvent ev =
-        new ProgressUpdateEvent(getCurrentProgressStep(), ratio,
-                currentPhaseSummary, newLogDetail);
-    for (ProgressUpdateListener l : listeners)
-    {
-      l.progressUpdate(ev);
-    }
+    listenerDelegate.notifyListeners(getCurrentProgressStep(),
+            ratio, currentPhaseSummary, newLogDetail);
   }
 
   /**
@@ -322,6 +317,7 @@
    */
   public void setProgressMessageFormatter(ProgressMessageFormatter formatter) {
     this.formatter = formatter;
+    this.listenerDelegate = new ProgressUpdateListenerDelegate(formatter);
   }
 
   /**
@@ -585,8 +581,73 @@
     return ui;
   }
 
-  static private String getMessage(String key, String... args) {
-    return ResourceProvider.getInstance().getMsg(key, args);
+  /**
+   * Conditionally notifies listeners of the log file if it
+   * has been initialized.
+   */
+  protected void notifyListenersOfLog() {
+    File logFile = QuickSetupLog.getLogFile();
+    if (logFile != null) {
+      notifyListeners(
+          getFormattedProgress(getMsg("general-see-for-details",
+              logFile.getPath())) +
+          formatter.getLineBreak());
+    }
+  }
+
+  /**
+   * Writes an initial record in the installation's historical
+   * log describing moving from one version to another.
+   * @param fromVersion from with install will be migrated
+   * @param toVersion to which install will be migrated
+   * @return Long ID for this session
+   * @throws ApplicationException if something goes wrong
+   */
+  protected Long writeInitialHistoricalRecord(
+          BuildInformation fromVersion,
+          BuildInformation toVersion)
+          throws ApplicationException {
+    Long id;
+    try {
+      HistoricalLog log =
+              new HistoricalLog(getInstallation().getHistoryLogFile());
+      id = log.append(fromVersion, toVersion,
+              HistoricalRecord.Status.STARTED,
+              "log file '" + QuickSetupLog.getLogFile().getPath() + "'");
+    } catch (IOException e) {
+      String msg = getMsg("error-logging-operation");
+      throw ApplicationException.createFileSystemException(
+              msg, e);
+    }
+    return id;
+  }
+
+  /**
+   * Writes a record into this installation's historical log.
+   * @param id obtained from calling <code>writeInitialHistoricalRecord</code>
+   * @param from version from with install will be migrated
+   * @param to version to which install will be migrated
+   * @param status of the operation
+   * @param note string with additional information
+   * @throws ApplicationException if something goes wrong
+   * @see {@link #writeInitialHistoricalRecord(BuildInformation,
+          BuildInformation)}
+   */
+  protected void writeHistoricalRecord(
+          Long id,
+          BuildInformation from,
+          BuildInformation to,
+          HistoricalRecord.Status status,
+          String note)
+          throws ApplicationException {
+    try {
+      HistoricalLog log =
+              new HistoricalLog(getInstallation().getHistoryLogFile());
+      log.append(id, from, to, status, note);
+    } catch (IOException e) {
+      String msg = getMsg("error-logging-operation");
+      throw ApplicationException.createFileSystemException(msg, e);
+    }
   }
 
   /**
diff --git a/opends/src/quicksetup/org/opends/quicksetup/CliApplication.java b/opends/src/quicksetup/org/opends/quicksetup/CliApplication.java
index dfdabd7..441326e 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/CliApplication.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/CliApplication.java
@@ -38,12 +38,11 @@
   /**
    * Creates a set of user data from command line arguments and installation
    * status.
-   * @param args String[] of arguments passed in from the command line
-   * @param status the current installation status
+   * @param launcher that launched this application
    * @return UserData object populated to reflect the input args and status
    * @throws UserDataException if something is wrong
    */
-  UserData createUserData(String[] args, CurrentInstallStatus status)
+  UserData createUserData(Launcher launcher)
           throws UserDataException;
 
   /**
@@ -66,17 +65,11 @@
   void setProgressMessageFormatter(ProgressMessageFormatter formatter);
 
   /**
-   * Indicates whether or not this applicat is finished running.
-   * @return boolean where true indicates we are not running
-   */
-  boolean isFinished();
-
-  /**
    * Gets any exception that happened while this application was running.
    * A null value returned from this method indicates that the execution
    * of the CLI program is not complete or was successful.
    * @return an exception that happened while the CLI was running
    */
-  ApplicationException getException();
+  ApplicationException getRunError();
 
 }
diff --git a/opends/src/quicksetup/org/opends/quicksetup/CliApplicationHelper.java b/opends/src/quicksetup/org/opends/quicksetup/CliApplicationHelper.java
index e813ecb..52b9983 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/CliApplicationHelper.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/CliApplicationHelper.java
@@ -308,6 +308,8 @@
                                                 String description,
                                                 boolean caseSensitive) {
 
+    // TODO: get rid of this method and user launcher.getArgumentParser
+
     // Create the command-line argument parser for use with this program.
     ArgumentParser argParser =
          new ArgumentParser(mainClass, description, caseSensitive);
diff --git a/opends/src/quicksetup/org/opends/quicksetup/upgrader/HistoricalLog.java b/opends/src/quicksetup/org/opends/quicksetup/HistoricalLog.java
similarity index 96%
rename from opends/src/quicksetup/org/opends/quicksetup/upgrader/HistoricalLog.java
rename to opends/src/quicksetup/org/opends/quicksetup/HistoricalLog.java
index 5c95aee..9c71e29 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/upgrader/HistoricalLog.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/HistoricalLog.java
@@ -25,10 +25,9 @@
  *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
  */
 
-package org.opends.quicksetup.upgrader;
+package org.opends.quicksetup;
 
 import org.opends.quicksetup.util.Utils;
-import org.opends.quicksetup.BuildInformation;
 
 import java.util.List;
 import java.util.ArrayList;
@@ -97,7 +96,7 @@
    * Creates a new historical log record and appends a new log record to the
    * log.
    * @param id Long ID obtained from a call to
-            {@link org.opends.quicksetup.upgrader.HistoricalLog#
+            {@link org.opends.quicksetup.HistoricalLog#
             append(Integer, Integer,
             org.opends.quicksetup.upgrader.HistoricalRecord.Status)}
    * @param from current version
diff --git a/opends/src/quicksetup/org/opends/quicksetup/upgrader/HistoricalRecord.java b/opends/src/quicksetup/org/opends/quicksetup/HistoricalRecord.java
similarity index 97%
rename from opends/src/quicksetup/org/opends/quicksetup/upgrader/HistoricalRecord.java
rename to opends/src/quicksetup/org/opends/quicksetup/HistoricalRecord.java
index fa1fe2a..d80ba94 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/upgrader/HistoricalRecord.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/HistoricalRecord.java
@@ -25,9 +25,8 @@
  *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
  */
 
-package org.opends.quicksetup.upgrader;
+package org.opends.quicksetup;
 
-import org.opends.quicksetup.BuildInformation;
 import org.opends.quicksetup.i18n.ResourceProvider;
 
 import java.util.StringTokenizer;
@@ -71,14 +70,18 @@
   /**
    * State of an upgrade.
    */
-  enum Status {
+  public enum Status {
 
+    /** Operation has started. */
     STARTED(getMsg("upgrade-log-status-started")),
 
+    /** Operation completed successfully. */
     SUCCESS(getMsg("upgrade-log-status-success")),
 
+    /** Operation failed. */
     FAILURE(getMsg("upgrade-log-status-failure")),
 
+    /** Operation was canceled. */
     CANCEL(getMsg("upgrade-log-status-cancel"));
 
     private String representation;
@@ -229,6 +232,7 @@
    * @param note containing details of status; can be null
    * @param creationError Exception that occurred while this record was
    * being created
+   * @param date of this operation
    */
   private HistoricalRecord(Long operationId, Date date, BuildInformation from,
                           BuildInformation to, Status status, String note,
diff --git a/opends/src/quicksetup/org/opends/quicksetup/Installation.java b/opends/src/quicksetup/org/opends/quicksetup/Installation.java
index f3bfd27..4856787 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/Installation.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/Installation.java
@@ -147,16 +147,26 @@
   public static final String WINDOWS_UNINSTALL_FILE_NAME = "uninstall.bat";
 
   /**
-   * The UNIX uninstall script file name.
+   * The UNIX upgrade script file name.
    */
   public static final String UNIX_UPGRADE_FILE_NAME = "upgrade";
 
   /**
-   * The Windows uninstall batch file name.
+   * The Windows upgrade batch file name.
    */
   public static final String WINDOWS_UPGRADE_FILE_NAME = "upgrade.bat";
 
   /**
+   * The UNIX revert script file name.
+   */
+  public static final String UNIX_REVERT_FILE_NAME = "revert";
+
+  /**
+   * The Windows revert batch file name.
+   */
+  public static final String WINDOWS_REVERT_FILE_NAME = "revert.bat";
+
+  /**
    * The UNIX start script file name.
    */
   public static final String UNIX_START_FILE_NAME = "start-ds";
@@ -203,6 +213,13 @@
   public static final String HISTORY_LOG_FILE_NAME = "log";
 
   /**
+   * The name of the directory in an upgrade backup directory (child
+   * of the 'history' directory) that contains the files from a
+   * previous version.
+   */
+  public static final String HISTORY_BACKUP_FILES_DIR_NAME = "files";
+
+  /**
    * Generic name for the backup tool.
    */
   public static final String BACKUP = "backup";
diff --git a/opends/src/quicksetup/org/opends/quicksetup/Launcher.java b/opends/src/quicksetup/org/opends/quicksetup/Launcher.java
index fad7cba..59969ca 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/Launcher.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/Launcher.java
@@ -28,6 +28,7 @@
 package org.opends.quicksetup;
 
 import static org.opends.server.util.DynamicConstants.PRINTABLE_VERSION_STRING;
+import org.opends.server.util.args.ArgumentParser;
 
 import org.opends.quicksetup.util.Utils;
 import org.opends.quicksetup.i18n.ResourceProvider;
@@ -58,9 +59,25 @@
       throw new IllegalArgumentException("args cannot be null");
     }
     this.args = args;
+
   }
 
   /**
+   * Gets the arguments with which this launcher was invoked.
+   * @return String[] args from the CLI invocation
+   */
+  public String[] getArguments() {
+    return this.args;
+  }
+
+  /**
+   * Gets an argument parser appropriate for this CLI launcher.
+   *
+   * @return ArgumentParser for parsing args
+   */
+  public abstract ArgumentParser getArgumentParser();
+
+  /**
    * Indicates whether or not the launcher should print a usage
    * statement based on the content of the arguments passed into
    * the constructor.
@@ -248,14 +265,13 @@
   /**
    * Launches the command line based uninstall.
    *
-   * @param args the arguments passed
    * @param cliApp the CLI application to launch
    * @return 0 if everything worked fine, and an error code if something wrong
    *         occurred.
    */
-  protected int launchCli(String[] args, CliApplication cliApp) {
+  protected int launchCli(CliApplication cliApp) {
     System.setProperty("org.opends.quicksetup.cli", "true");
-    QuickSetupCli cli = new QuickSetupCli(cliApp, args);
+    QuickSetupCli cli = new QuickSetupCli(cliApp, this);
     int returnValue = cli.run();
     if (returnValue == QuickSetupCli.USER_DATA_ERROR) {
       printUsage(true);
@@ -278,7 +294,21 @@
    * @param toStdErr whether the message must be printed to the standard error
    * or the standard output.
    */
-  protected abstract void printUsage(boolean toStdErr);
+  protected void printUsage(boolean toStdErr) {
+    try
+    {
+      ArgumentParser argParser = getArgumentParser();
+      if (argParser != null) {
+        String msg = argParser.getUsage();
+        printUsage(msg, toStdErr);
+      }
+    }
+    catch (Throwable t)
+    {
+      System.out.println("ERROR: "+t);
+      t.printStackTrace();
+    }
+  }
 
   /**
    * Creates a CLI application that will be run if the
@@ -318,7 +348,7 @@
       System.exit(QuickSetupCli.SUCCESSFUL);
     } else if (isCli()) {
       CliApplication cliApp = createCliApplication();
-      int exitCode = launchCli(args, cliApp);
+      int exitCode = launchCli(cliApp);
       preExit(cliApp);
       System.exit(exitCode);
     } else {
@@ -335,7 +365,7 @@
           guiLaunchFailed(null);
         }
         CliApplication cliApp = createCliApplication();
-        exitCode = launchCli(args, cliApp);
+        exitCode = launchCli(cliApp);
         if (exitCode != 0) {
           preExit(cliApp);
           System.exit(exitCode);
diff --git a/opends/src/quicksetup/org/opends/quicksetup/ProgressUpdateListenerDelegate.java b/opends/src/quicksetup/org/opends/quicksetup/ProgressUpdateListenerDelegate.java
new file mode 100644
index 0000000..26ff51c
--- /dev/null
+++ b/opends/src/quicksetup/org/opends/quicksetup/ProgressUpdateListenerDelegate.java
@@ -0,0 +1,123 @@
+/*
+ * 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 2007 Sun Microsystems, Inc.
+ */
+
+package org.opends.quicksetup;
+
+import org.opends.quicksetup.event.ProgressUpdateListener;
+import org.opends.quicksetup.event.ProgressUpdateEvent;
+import org.opends.quicksetup.util.ProgressMessageFormatter;
+import org.opends.quicksetup.i18n.ResourceProvider;
+
+import java.util.HashSet;
+import java.io.File;
+
+/**
+ * Delegate class for handling progress notification listeners and events.
+ */
+public class ProgressUpdateListenerDelegate {
+
+  private HashSet<ProgressUpdateListener> listeners =
+          new HashSet<ProgressUpdateListener>();
+
+  private ProgressMessageFormatter formatter;
+
+  /**
+   * Creates a parameterized instance.
+   * @param formatter for formatting messages.
+   */
+  public ProgressUpdateListenerDelegate(ProgressMessageFormatter formatter) {
+    this.formatter = formatter;
+  }
+
+  /**
+   * Adds a ProgressUpdateListener that will be notified of updates in
+   * the install progress.
+   *
+   * @param l the ProgressUpdateListener to be added.
+   */
+  public void addProgressUpdateListener(ProgressUpdateListener l) {
+    listeners.add(l);
+  }
+
+  /**
+   * Removes a ProgressUpdateListener.
+   *
+   * @param l the ProgressUpdateListener to be removed.
+   */
+  public void removeProgressUpdateListener(ProgressUpdateListener l) {
+    listeners.remove(l);
+  }
+
+  /**
+   * This method notifies the ProgressUpdateListeners that there was an
+   * update in the installation progress.
+   *
+   * @param current             progress step
+   * @param ratio               the integer that specifies which percentage of
+   *                            the whole installation has been completed.
+   * @param currentPhaseSummary the localized summary message for the
+   *                            current installation progress in formatted form.
+   * @param newLogDetail        the new log messages that we have for the
+   *                            installation in formatted form.
+   */
+  public void notifyListeners(ProgressStep current, Integer ratio,
+                              String currentPhaseSummary,
+                              String newLogDetail) {
+    ProgressUpdateEvent ev =
+            new ProgressUpdateEvent(current, ratio,
+                    currentPhaseSummary, newLogDetail);
+    for (ProgressUpdateListener l : listeners) {
+      l.progressUpdate(ev);
+    }
+  }
+
+  /**
+   * Conditionally notifies listeners of the log file if it
+   * has been initialized.
+   */
+  public void notifyListenersOfLog() {
+    File logFile = QuickSetupLog.getLogFile();
+    if (logFile != null) {
+      notifyListeners(
+          formatter.getFormattedProgress(getMsg("general-see-for-details",
+              logFile.getPath())) +
+          formatter.getLineBreak());
+    }
+  }
+
+  /**
+   * Notify listeners about a change in log detail.
+   * @param msg log detail
+   */
+  protected void notifyListeners(String msg) {
+    notifyListeners(null, null, null, msg);
+  }
+
+  private String getMsg(String key, String... args) {
+    return ResourceProvider.getInstance().getMsg(key, args);
+  }
+}
diff --git a/opends/src/quicksetup/org/opends/quicksetup/QuickSetupCli.java b/opends/src/quicksetup/org/opends/quicksetup/QuickSetupCli.java
index ba8e598..e293495 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/QuickSetupCli.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/QuickSetupCli.java
@@ -33,6 +33,7 @@
 import org.opends.quicksetup.event.ProgressUpdateListener;
 import org.opends.quicksetup.event.ProgressUpdateEvent;
 import org.opends.quicksetup.i18n.ResourceProvider;
+import org.opends.server.util.StaticUtils;
 
 /**
  * Controller for managing the execution of a CliApplication.
@@ -80,18 +81,28 @@
   static public int UNKNOWN = 100;
 
   /** Arguments passed in the command line. */
-  protected String[] args;
+  protected Launcher launcher;
 
   private CliApplication cliApp;
 
+  private UserData userData;
+
   /**
    * Creates a QuickSetupCli instance.
    * @param cliApp the application to be run
-   * @param args arguments passed in from the command line
+   * @param launcher that launched the app
    */
-  public QuickSetupCli(CliApplication cliApp, String[] args) {
+  public QuickSetupCli(CliApplication cliApp, Launcher launcher) {
     this.cliApp = cliApp;
-    this.args = args;
+    this.launcher = launcher;
+  }
+
+  /**
+   * Gets the user data this application will use when running.
+   * @return UserData to use when running
+   */
+  public UserData getUserData() {
+    return this.userData;
   }
 
   /**
@@ -107,8 +118,7 @@
     // Parse the arguments
     try
     {
-      CurrentInstallStatus installStatus = new CurrentInstallStatus();
-      UserData userData = cliApp.createUserData(args, installStatus);
+      userData = cliApp.createUserData(launcher);
       if (userData != null)
       {
         ProgressMessageFormatter formatter =
@@ -117,36 +127,26 @@
         cliApp.setProgressMessageFormatter(formatter);
         if (!userData.isSilent()) {
           cliApp.addProgressUpdateListener(
-              new ProgressUpdateListener()
-              {
-                /**
-                 * ProgressUpdateListener implementation.
-                 * @param ev the ProgressUpdateEvent we receive.
-                 *
-                 */
-                public void progressUpdate(ProgressUpdateEvent ev)
-                {
-                  System.out.print(
-                          org.opends.server.util.StaticUtils.wrapText(
-                                  ev.getNewLogs(),
-                                  Utils.getCommandLineMaxLineWidth()));
-                }
-              });
+                  new ProgressUpdateListener() {
+                    public void progressUpdate(ProgressUpdateEvent ev) {
+                      System.out.print(
+                              org.opends.server.util.StaticUtils.wrapText(
+                                      ev.getNewLogs(),
+                                      Utils.getCommandLineMaxLineWidth()));
+                    }
+                  });
         }
-        new Thread(cliApp).start();
-        while (!cliApp.isFinished())
-        {
-          try
-          {
+        Thread appThread = new Thread(cliApp, "CLI Application");
+        appThread.start();
+        while (!Thread.State.TERMINATED.equals(appThread.getState())) {
+          try {
             Thread.sleep(100);
-          }
-          catch (Exception ex)
-          {
+          } catch (Exception ex) {
             // do nothing;
           }
         }
 
-        ApplicationException ue = cliApp.getException();
+        ApplicationException ue = cliApp.getRunError();
         if (ue != null)
         {
           ApplicationException.Type type = ue.getType();
@@ -186,8 +186,10 @@
     }
     catch (UserDataException uude)
     {
-      System.err.println(Constants.LINE_SEPARATOR+uude.getLocalizedMessage()+
-          Constants.LINE_SEPARATOR);
+      System.err.println();
+      System.err.println(StaticUtils.wrapText(uude.getLocalizedMessage(),
+              Utils.getCommandLineMaxLineWidth()));
+      System.err.println();
       returnValue = USER_DATA_ERROR;
     }
     return returnValue;
diff --git a/opends/src/quicksetup/org/opends/quicksetup/QuickSetupLog.java b/opends/src/quicksetup/org/opends/quicksetup/QuickSetupLog.java
index 0113aa0..41f8853 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/QuickSetupLog.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/QuickSetupLog.java
@@ -41,6 +41,9 @@
  */
 public class QuickSetupLog {
 
+  /** Suffix for log files. */
+  static public final String LOG_FILE_SUFFIX = ".log";
+
   static private File logFile = null;
 
   /**
diff --git a/opends/src/quicksetup/org/opends/quicksetup/installandupgrader/InstallAndUpgrader.java b/opends/src/quicksetup/org/opends/quicksetup/installandupgrader/InstallAndUpgrader.java
index cd6045a..e650c67 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/installandupgrader/InstallAndUpgrader.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/installandupgrader/InstallAndUpgrader.java
@@ -82,7 +82,7 @@
         QuickSetupLog.initLogFileHandler(
                 File.createTempFile(
                         UpgradeLauncher.LOG_FILE_PREFIX,
-                        UpgradeLauncher.LOG_FILE_SUFFIX));
+                        QuickSetupLog.LOG_FILE_SUFFIX));
     } catch (IOException e) {
       System.err.println(
               ResourceProvider.getInstance().getMsg("error-initializing-log"));
diff --git a/opends/src/quicksetup/org/opends/quicksetup/installer/InstallLauncher.java b/opends/src/quicksetup/org/opends/quicksetup/installer/InstallLauncher.java
index 2426473..60d6785 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/installer/InstallLauncher.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/installer/InstallLauncher.java
@@ -32,6 +32,7 @@
 import java.io.File;
 import java.util.ArrayList;
 import java.util.logging.Logger;
+import java.util.logging.Level;
 
 import org.opends.quicksetup.Launcher;
 import org.opends.quicksetup.CliApplication;
@@ -63,7 +64,6 @@
   static private final Logger LOG =
           Logger.getLogger(InstallLauncher.class.getName());
 
-
   /**
    * The main method which is called by the setup command lines.
    *
@@ -82,6 +82,8 @@
     new InstallLauncher(args).launch();
   }
 
+  private ArgumentParser argParser;
+
   /**
    * Creates a launcher.
    *
@@ -89,43 +91,7 @@
    */
   public InstallLauncher(String[] args) {
     super(args);
-  }
 
-  /**
-   * {@inheritDoc}
-   */
-  protected void guiLaunchFailed(String logFileName) {
-    if (logFileName != null)
-    {
-      System.err.println(getMsg("setup-launcher-gui-launched-failed-details",
-          logFileName));
-    }
-    else
-    {
-      System.err.println(getMsg("setup-launcher-gui-launched-failed"));
-    }
-  }
-
-  /**
-   * {@inheritDoc}
-   */
-  protected void willLaunchGui() {
-    System.out.println(getMsg("setup-launcher-launching-gui"));
-    System.setProperty("org.opends.quicksetup.Application.class",
-            "org.opends.quicksetup.installer.offline.OfflineInstaller");
-  }
-
-  /**
-   * {@inheritDoc}
-   */
-  protected String getFrameTitle() {
-    return getI18n().getMsg("frame-install-title");
-  }
-
-  /**
-   * {@inheritDoc}
-   */
-  protected void printUsage(boolean toStdErr) {
     String scriptName;
     if (Utils.isWindows()) {
       scriptName = Installation.WINDOWS_SETUP_FILE_NAME;
@@ -133,7 +99,8 @@
       scriptName = Installation.UNIX_SETUP_FILE_NAME;
     }
     System.setProperty(ServerConstants.PROPERTY_SCRIPT_NAME, scriptName);
-    ArgumentParser argParser = new ArgumentParser(getClass().getName(),
+
+    argParser = new ArgumentParser(getClass().getName(),
         getI18n().getMsg("setup-launcher-usage-description"),
         false);
     BooleanArgument   addBaseEntry;
@@ -238,8 +205,6 @@
           MSGID_INSTALLDS_DESCRIPTION_HELP);
       argParser.addArgument(showUsage);
       argParser.setUsageArgument(showUsage);
-      String msg = argParser.getUsage();
-      printUsage(msg, toStdErr);
     }
     catch (Throwable t)
     {
@@ -251,6 +216,44 @@
   /**
    * {@inheritDoc}
    */
+  protected void guiLaunchFailed(String logFileName) {
+    if (logFileName != null)
+    {
+      System.err.println(getMsg("setup-launcher-gui-launched-failed-details",
+          logFileName));
+    }
+    else
+    {
+      System.err.println(getMsg("setup-launcher-gui-launched-failed"));
+    }
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public ArgumentParser getArgumentParser() {
+    return this.argParser;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  protected void willLaunchGui() {
+    System.out.println(getMsg("setup-launcher-launching-gui"));
+    System.setProperty("org.opends.quicksetup.Application.class",
+            "org.opends.quicksetup.installer.offline.OfflineInstaller");
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  protected String getFrameTitle() {
+    return getI18n().getMsg("frame-install-title");
+  }
+
+  /**
+   * {@inheritDoc}
+   */
   protected CliApplication createCliApplication() {
     // Setup currently has no implemented CliApplication
     // but rather relies on InstallDS from the server
@@ -264,7 +267,7 @@
    * {@inheritDoc}
    */
   @Override
-  protected int launchCli(String[] args, CliApplication cliApp) {
+  protected int launchCli(CliApplication cliApp) {
     System.setProperty("org.opends.quicksetup.cli", "true");
 
     if (Utils.isWindows()) {
@@ -276,10 +279,10 @@
     }
     ArrayList<String> newArgList = new ArrayList<String>();
     if (args != null) {
-      for (int i = 0; i < args.length; i++) {
-        if (!args[i].equalsIgnoreCase("--cli") &&
-            !args[i].equalsIgnoreCase("-c")) {
-          newArgList.add(args[i]);
+      for (String arg : args) {
+        if (!arg.equalsIgnoreCase("--cli") &&
+                !arg.equalsIgnoreCase("-c")) {
+          newArgList.add(arg);
         }
       }
     }
@@ -292,7 +295,8 @@
 
     String[] newArgs = new String[newArgList.size()];
     newArgList.toArray(newArgs);
-
+    LOG.log(Level.INFO, "Launching 'installMain' with args " +
+            Utils.listToString(newArgList, " "));
     return org.opends.server.tools.InstallDS.installMain(newArgs);
   }
 }
diff --git a/opends/src/quicksetup/org/opends/quicksetup/resources/Resources.properties b/opends/src/quicksetup/org/opends/quicksetup/resources/Resources.properties
index 04e8abc..a39e139 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/resources/Resources.properties
+++ b/opends/src/quicksetup/org/opends/quicksetup/resources/Resources.properties
@@ -106,6 +106,20 @@
 failed.  Check file {0} for more details.\n\nLaunching command line upgrade...
 cli-upgrade-unknown-argument=Unknown argument {0}
 
+revert-launcher-usage-description=This utility reverts the current installation \
+  of the Directory Server to a version prior to running the upgrade utility.   
+revert-error-no-history-dir=There are no existing backup locations from \
+  prior upgrades.  The 'history' directory does not exist.
+revert-error-empty-history-dir=There are no existing backup locations from \
+  prior upgrades.  The 'history' directory is empty.
+revert-error-null-files-dir=The upgrade backup directory is invalid or could not \
+  be determined.
+revert-error-not-dir-files-dir=The upgrade backup directory is not a directory.
+revert-error-invalid-files-dir=The upgrade backup directory does not appear to \
+  contain files backed up from an invocation of the upgrade tool.
+revert-error-no-dir=ERROR:  No reversion directory specified.  You must specify \
+  one of {0}
+
 
 #
 # Dialog titles
@@ -939,7 +953,34 @@
 summary-upgrade-finished-canceled-cli=OpenDS QuickUpgrade Canceled. \
   The upgrade operation was canceled and the installation has been \
   restored to the state it was in before the upgrade operation.
+
+summary-revert-not-started=Starting Reversion...
+summary-revert-initializing=Initializing Reversion...
+summary-revert-reverting-components=Reverting Components...
+summary-revert-verifying=Verifying revert...
+summary-revert-history=Recording Reversion History...
+summary-revert-cleanup=Cleaning Up...
+summary-revert-abort=Canceling Reversion...
+summary-revert-finished-successfully-cli=OpenDS Reversion Completed \
+  Successfully.  The OpenDS installation at {0} has now been reverted \
+  to version {1}.
+summary-revert-finished-with-errors-cli=OpenDS Reversion Failed. \
+  The reversion operation could not complete successfully due to errors and \
+  the installation has been restored to the state it was in before the reversion \
+  operation.  See the logs for details on why the reversion operation failed.
+summary-revert-finished-with-warnings-cli=OpenDS Reversion Succeeded With \
+  Warnings. The reversion operation completed successfully but the reverter \
+  had problems that require attention. See the logs for details on the \
+  problems.
+summary-revert-finished-canceled-cli=OpenDS Reversion Canceled. \
+  The upgrade operation was canceled and the installation has been \
+  restored to the state it was in before the reversion operation.
+
 #
+#
+#
+#
+##
 # Progress messages
 #
 progress-downloading=Downloading
@@ -1190,6 +1231,8 @@
 upgrade-verification-failure-view-details=View Error Details
 upgrade-file-prompt=Enter the name and path of the OpenDS install file (.zip):
 
+reversion-canceled=Reversion canceled.
+
 #
 # Upgrader Panels
 #
@@ -1315,6 +1358,7 @@
 general-checking-data=Checking Data...
 general-loading=Loading...
 general-see-for-details=See {0} for a detailed log of this operation.
+general-see-for-history=See {0} for a history installation history.
 not-available-label=<not available>
 general-build-id=Build ID
 general-unset=Unset
diff --git a/opends/src/quicksetup/org/opends/quicksetup/ui/GuiApplication.java b/opends/src/quicksetup/org/opends/quicksetup/ui/GuiApplication.java
index c467196..f5a026c 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/ui/GuiApplication.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/ui/GuiApplication.java
@@ -36,7 +36,6 @@
 
 import javax.swing.*;
 import java.awt.event.WindowEvent;
-import java.io.File;
 import java.security.cert.X509Certificate;
 import java.util.LinkedHashSet;
 import java.util.Set;
@@ -579,20 +578,6 @@
   }
 
   /**
-   * Conditionally notifies listeners of the log file if it
-   * has been initialized.
-   */
-  protected void notifyListenersOfLog() {
-    File logFile = QuickSetupLog.getLogFile();
-    if (logFile != null) {
-      notifyListeners(
-          getFormattedProgress(getMsg("general-see-for-details",
-              logFile.getPath())) +
-          formatter.getLineBreak());
-    }
-  }
-
-  /**
    * {@inheritDoc}
    */
   public UserInteraction userInteraction() {
diff --git a/opends/src/quicksetup/org/opends/quicksetup/uninstaller/UninstallCliHelper.java b/opends/src/quicksetup/org/opends/quicksetup/uninstaller/UninstallCliHelper.java
index 6f12ebe..85049dc 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/uninstaller/UninstallCliHelper.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/uninstaller/UninstallCliHelper.java
@@ -60,14 +60,13 @@
    * user for additional information if what is provided in the arguments is not
    * enough.
    * @param args the arguments provided in the command line.
-   * @param installStatus the current install status.
    * @return the UserData object with what the user wants to uninstall
    * and null if the user cancels the uninstallation.
    * @throws UserDataException if there is an error parsing the data
    * in the arguments.
    */
-  public UninstallUserData createUserData(String[] args,
-      CurrentInstallStatus installStatus) throws UserDataException
+  public UninstallUserData createUserData(String[] args
+  ) throws UserDataException
   {
     UninstallUserData userData = new UninstallUserData();
 
diff --git a/opends/src/quicksetup/org/opends/quicksetup/uninstaller/UninstallLauncher.java b/opends/src/quicksetup/org/opends/quicksetup/uninstaller/UninstallLauncher.java
index 535f947..eb5f0e3 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/uninstaller/UninstallLauncher.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/uninstaller/UninstallLauncher.java
@@ -77,6 +77,8 @@
     new UninstallLauncher(args).launch();
   }
 
+  private ArgumentParser argParser;
+
   /**
    * Creates a launcher.
    *
@@ -84,6 +86,39 @@
    */
   public UninstallLauncher(String[] args) {
     super(args);
+
+    String scriptName;
+    if (Utils.isWindows()) {
+      scriptName = Installation.WINDOWS_UNINSTALL_FILE_NAME;
+    } else {
+      scriptName = Installation.UNIX_UNINSTALL_FILE_NAME;
+    }
+    System.setProperty(ServerConstants.PROPERTY_SCRIPT_NAME, scriptName);
+
+    argParser = new ArgumentParser(getClass().getName(),
+        getI18n().getMsg("uninstall-launcher-usage-description"), false);
+    BooleanArgument cli;
+    BooleanArgument silent;
+    BooleanArgument showUsage;
+    try
+    {
+      cli = new BooleanArgument("cli", 'c', "cli",
+          MSGID_UNINSTALLDS_DESCRIPTION_CLI);
+      argParser.addArgument(cli);
+      silent = new BooleanArgument("silent", 's', "silent",
+          MSGID_UNINSTALLDS_DESCRIPTION_SILENT);
+      argParser.addArgument(silent);
+      showUsage = new BooleanArgument("showusage", OPTION_SHORT_HELP,
+        OPTION_LONG_HELP,
+        MSGID_DESCRIPTION_USAGE);
+      argParser.addArgument(showUsage);
+      argParser.setUsageArgument(showUsage);
+    }
+    catch (Throwable t)
+    {
+      System.out.println("ERROR: "+t);
+      t.printStackTrace();
+    }
   }
 
   /**
@@ -104,6 +139,13 @@
   /**
    * {@inheritDoc}
    */
+  public ArgumentParser getArgumentParser() {
+    return this.argParser;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
   protected void willLaunchGui() {
     System.out.println(getMsg("uninstall-launcher-launching-gui"));
     System.setProperty("org.opends.quicksetup.Application.class",
@@ -124,44 +166,4 @@
     return getI18n().getMsg("frame-uninstall-title");
   }
 
-  /**
-   * {@inheritDoc}
-   */
-  protected void printUsage(boolean toStdErr) {
-    ArgumentParser argParser = new ArgumentParser(getClass().getName(),
-        getI18n().getMsg("uninstall-launcher-usage-description"), false);
-    BooleanArgument cli;
-    BooleanArgument silent;
-    BooleanArgument showUsage;
-    String scriptName;
-    if (Utils.isWindows()) {
-      scriptName = Installation.WINDOWS_UNINSTALL_FILE_NAME;
-    } else {
-      scriptName = Installation.UNIX_UNINSTALL_FILE_NAME;
-    }
-    System.setProperty(ServerConstants.PROPERTY_SCRIPT_NAME, scriptName);
-    try
-    {
-      cli = new BooleanArgument("cli", 'c', "cli",
-          MSGID_UNINSTALLDS_DESCRIPTION_CLI);
-      argParser.addArgument(cli);
-      silent = new BooleanArgument("silent", 's', "silent",
-          MSGID_UNINSTALLDS_DESCRIPTION_SILENT);
-      argParser.addArgument(silent);
-      showUsage = new BooleanArgument("showusage", OPTION_SHORT_HELP,
-        OPTION_LONG_HELP,
-        MSGID_DESCRIPTION_USAGE);
-      argParser.addArgument(showUsage);
-      argParser.setUsageArgument(showUsage);
-
-      String msg = argParser.getUsage();
-      printUsage(msg, toStdErr);
-    }
-    catch (Throwable t)
-    {
-      System.out.println("ERROR: "+t);
-      t.printStackTrace();
-    }
-  }
-
 }
diff --git a/opends/src/quicksetup/org/opends/quicksetup/uninstaller/Uninstaller.java b/opends/src/quicksetup/org/opends/quicksetup/uninstaller/Uninstaller.java
index 64ceb83..77667c7 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/uninstaller/Uninstaller.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/uninstaller/Uninstaller.java
@@ -388,10 +388,11 @@
 
   /**
    * {@inheritDoc}
+   * @param launcher
    */
-  public UserData createUserData(String[] args, CurrentInstallStatus status)
+  public UserData createUserData(Launcher launcher)
           throws UserDataException {
-    return cliHelper.createUserData(args, status);
+    return cliHelper.createUserData(launcher.getArguments());
   }
 
   /**
@@ -408,7 +409,7 @@
    * @return the ApplicationException that might occur during installation or
    *         <CODE>null</CODE> if no exception occurred.
    */
-  public ApplicationException getException() {
+  public ApplicationException getRunError() {
     return ue;
   }
 
diff --git a/opends/src/quicksetup/org/opends/quicksetup/upgrader/BuildExtractor.java b/opends/src/quicksetup/org/opends/quicksetup/upgrader/BuildExtractor.java
index ffc7b40..cc00d6e 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/upgrader/BuildExtractor.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/upgrader/BuildExtractor.java
@@ -66,7 +66,7 @@
       QuickSetupLog.initLogFileHandler(
               File.createTempFile(
                       UpgradeLauncher.LOG_FILE_PREFIX + "ext-",
-                      UpgradeLauncher.LOG_FILE_SUFFIX));
+                      QuickSetupLog.LOG_FILE_SUFFIX));
     } catch (Throwable t) {
       System.err.println(
               ResourceProvider.getInstance().getMsg("error-initializing-log"));
@@ -164,8 +164,9 @@
 
   /**
    * {@inheritDoc}
+   * @param launcher
    */
-  public UserData createUserData(String[] args, CurrentInstallStatus status)
+  public UserData createUserData(Launcher launcher)
           throws UserDataException
   {
     return helper.createUserData(args);
@@ -204,7 +205,7 @@
   /**
    * {@inheritDoc}
    */
-  public ApplicationException getException() {
+  public ApplicationException getRunError() {
     return error;
   }
 
@@ -229,4 +230,5 @@
                               String newLogDetail) {
     // ignored;  no progress messages
   }
+
 }
diff --git a/opends/src/quicksetup/org/opends/quicksetup/upgrader/BuildExtractorCliHelper.java b/opends/src/quicksetup/org/opends/quicksetup/upgrader/BuildExtractorCliHelper.java
index f967860..b8c651e 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/upgrader/BuildExtractorCliHelper.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/upgrader/BuildExtractorCliHelper.java
@@ -80,7 +80,8 @@
     } else {
       throw new UserDataException(null,
               getMsg("error-option-required-or-interactive",
-                      "-" + FILE_OPTION_SHORT + "/--" + FILE_OPTION_LONG));
+                      "-" + UpgradeLauncher.FILE_OPTION_SHORT + "/--" +
+                              UpgradeLauncher.FILE_OPTION_LONG));
     }
     return uud;
   }
diff --git a/opends/src/quicksetup/org/opends/quicksetup/upgrader/ReversionLauncher.java b/opends/src/quicksetup/org/opends/quicksetup/upgrader/ReversionLauncher.java
new file mode 100644
index 0000000..a08b8c3
--- /dev/null
+++ b/opends/src/quicksetup/org/opends/quicksetup/upgrader/ReversionLauncher.java
@@ -0,0 +1,216 @@
+/*
+ * 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 2007 Sun Microsystems, Inc.
+ */
+
+package org.opends.quicksetup.upgrader;
+
+import org.opends.quicksetup.Launcher;
+import org.opends.quicksetup.CliApplication;
+import org.opends.quicksetup.QuickSetupLog;
+import org.opends.quicksetup.Installation;
+import org.opends.quicksetup.util.Utils;
+import org.opends.quicksetup.i18n.ResourceProvider;
+import org.opends.server.util.args.ArgumentParser;
+import org.opends.server.util.args.BooleanArgument;
+import org.opends.server.util.args.FileBasedArgument;
+import org.opends.server.util.ServerConstants;
+import static org.opends.server.messages.ToolMessages.*;
+import static org.opends.server.tools.ToolConstants.OPTION_SHORT_HELP;
+import static org.opends.server.tools.ToolConstants.OPTION_LONG_HELP;
+
+import java.io.File;
+
+/**
+ * Launches a reversion operation.
+ */
+public class ReversionLauncher extends Launcher {
+
+  /** Short form of the option for specifying the reversion files directory. */
+  static public final Character DIRECTORY_OPTION_SHORT = 'd';
+
+  /** Long form of the option for specifying the reversion files directory. */
+  static public final String DIRECTORY_OPTION_LONG = "directory";
+
+  /** Short form of the option for specifying the 'most recent' option. */
+  static public final Character MOST_RECENT_OPTION_SHORT = 'm';
+
+  /** Long form of the option for specifying the 'most recent' option. */
+  static public final String MOST_RECENT_OPTION_LONG = "mostRecent";
+
+  static private final String LOG_FILE_PREFIX = "opends-revert-";
+
+  /**
+   * Creates and launches a reversion operation.
+   * @param args from the command line
+   */
+  static public void main(String[] args) {
+    try {
+      QuickSetupLog.initLogFileHandler(
+              File.createTempFile(LOG_FILE_PREFIX,
+                      QuickSetupLog.LOG_FILE_SUFFIX));
+    } catch (Throwable t) {
+      System.err.println(
+              ResourceProvider.getInstance().getMsg("error-initializing-log"));
+      t.printStackTrace();
+    }
+    new ReversionLauncher(args).launch();
+  }
+
+  private ArgumentParser argParser;
+
+  private BooleanArgument showUsage;
+  private FileBasedArgument dir;
+  private BooleanArgument mostRecent;
+  private BooleanArgument silent;
+  private BooleanArgument interactive;
+
+  /**
+   * Gets the file's directory if specified on the command line.
+   * @return File representing the directory where the reversion files are
+   * stored.
+   */
+  public File getFilesDirectory() {
+    File f = null;
+    String s = dir.getValue();
+    if (s != null) {
+      f = new File(s);
+    }
+    return f;
+  }
+
+  /**
+   * Indicates whether the user has specified the 'mostRecent' option.
+   * @return boolean where true indicates use the most recent upgrade backup
+   */
+  public boolean useMostRecentUpgrade() {
+    return mostRecent.isPresent();
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  protected boolean isCli() {
+    // for now only CLI is supported via command line
+    return true;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  protected String getFrameTitle() {
+    return null;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  protected CliApplication createCliApplication() {
+    return new Reverter();
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  protected void willLaunchGui() {
+    // not supported;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  protected void guiLaunchFailed(String logFileName) {
+    // not supported;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public ArgumentParser getArgumentParser() {
+    return argParser;
+  }
+
+  /**
+   * Creates a new launcher.
+   * @param args from the command line
+   */
+  protected  ReversionLauncher(String[] args) {
+    super(args);
+
+    String scriptName;
+    if (Utils.isWindows()) {
+      scriptName = Installation.WINDOWS_REVERT_FILE_NAME;
+    } else {
+      scriptName = Installation.UNIX_REVERT_FILE_NAME;
+    }
+    System.setProperty(ServerConstants.PROPERTY_SCRIPT_NAME, scriptName);
+
+    argParser = new ArgumentParser(getClass().getName(),
+        getI18n().getMsg("revert-launcher-usage-description"), false);
+    try
+    {
+      dir = new FileBasedArgument("directory",
+              DIRECTORY_OPTION_SHORT,
+              DIRECTORY_OPTION_LONG,
+              false, false,
+              "{directory}",
+              null, null, MSGID_REVERT_DESCRIPTION_DIRECTORY);
+      argParser.addArgument(dir);
+
+      mostRecent = new BooleanArgument("mostRecent",
+              MOST_RECENT_OPTION_SHORT,
+              MOST_RECENT_OPTION_LONG,
+              MSGID_REVERT_DESCRIPTION_RECENT);
+      argParser.addArgument(mostRecent);
+
+      interactive = new BooleanArgument("interactive", 'i', "interactive",
+          MSGID_REVERT_DESCRIPTION_INTERACTIVE);
+      argParser.addArgument(interactive);
+
+      silent = new BooleanArgument("silent", 's', "silent",
+          MSGID_REVERT_DESCRIPTION_SILENT);
+      argParser.addArgument(silent);
+
+      showUsage = new BooleanArgument("showusage", OPTION_SHORT_HELP,
+        OPTION_LONG_HELP,
+        MSGID_DESCRIPTION_USAGE);
+      argParser.addArgument(showUsage);
+      argParser.setUsageArgument(showUsage);
+
+      argParser.parseArguments(args);
+    }
+    catch (Throwable t)
+    {
+      System.out.println("ERROR: "+t);
+      t.printStackTrace();
+    }
+
+  }
+
+  private void validate(ArgumentParser argParser) {
+
+  }
+
+}
diff --git a/opends/src/quicksetup/org/opends/quicksetup/upgrader/ReversionProgressStep.java b/opends/src/quicksetup/org/opends/quicksetup/upgrader/ReversionProgressStep.java
new file mode 100644
index 0000000..6883aec
--- /dev/null
+++ b/opends/src/quicksetup/org/opends/quicksetup/upgrader/ReversionProgressStep.java
@@ -0,0 +1,103 @@
+/*
+ * 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 2007 Sun Microsystems, Inc.
+ */
+
+package org.opends.quicksetup.upgrader;
+
+import org.opends.quicksetup.ProgressStep;
+
+/**
+ * Steps during the reversion process.
+ */
+enum ReversionProgressStep implements ProgressStep {
+
+  NOT_STARTED("summary-revert-not-started", 0),
+
+  INITIALIZING("summary-revert-initializing", 20),
+
+  STOPPING_SERVER("summary-stopping", 40),
+
+  REVERTING_FILESYSTEM("summary-revert-reverting-components", 60),
+
+  VERIFYING("summary-revert-verifying", 80),
+
+  RECORDING_HISTORY("summary-revert-history", 90),
+
+  CLEANUP("summary-revert-cleanup", 95),
+
+  ABORT("summary-revert-abort", 99),
+
+  FINISHED_WITH_ERRORS("summary-revert-finished-with-errors-cli", 100),
+
+  FINISHED_WITH_WARNINGS("summary-revert-finished-with-warnings-cli", 100),
+
+  FINISHED_CANCELED("summary-revert-finished-canceled-cli", 100),
+
+  FINISHED("summary-revert-finished-successfully-cli", 100);
+
+  private String summaryMsgKey;
+  private int progress;
+
+  private ReversionProgressStep(String summaryMsgKey, int progress) {
+    this.summaryMsgKey = summaryMsgKey;
+    this.progress = progress;
+  }
+
+  /**
+   * Return a key for access a summary message.
+   *
+   * @return String representing key for access summary in resource bundle
+   */
+  public String getSummaryMesssageKey() {
+    return summaryMsgKey;
+  }
+
+  /**
+   * Gets the amount of progress to show in the progress meter for this step.
+   *
+   * @return int representing progress
+   */
+  public int getProgress() {
+    return this.progress;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean isLast() {
+    return this == FINISHED ||
+            this == FINISHED_WITH_ERRORS ||
+            this == FINISHED_WITH_WARNINGS ||
+            this == FINISHED_CANCELED;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean isError() {
+    return this == FINISHED_WITH_ERRORS;
+  }
+}
diff --git a/opends/src/quicksetup/org/opends/quicksetup/upgrader/Reverter.java b/opends/src/quicksetup/org/opends/quicksetup/upgrader/Reverter.java
new file mode 100644
index 0000000..9bddfb3
--- /dev/null
+++ b/opends/src/quicksetup/org/opends/quicksetup/upgrader/Reverter.java
@@ -0,0 +1,709 @@
+/*
+ * 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 2007 Sun Microsystems, Inc.
+ */
+
+package org.opends.quicksetup.upgrader;
+
+import org.opends.quicksetup.CliApplication;
+import org.opends.quicksetup.UserData;
+import org.opends.quicksetup.UserDataException;
+import org.opends.quicksetup.ApplicationException;
+import org.opends.quicksetup.ProgressUpdateListenerDelegate;
+import org.opends.quicksetup.Installation;
+import org.opends.quicksetup.Launcher;
+import org.opends.quicksetup.Status;
+import org.opends.quicksetup.ProgressStep;
+import org.opends.quicksetup.BuildInformation;
+import org.opends.quicksetup.Application;
+import org.opends.quicksetup.HistoricalRecord;
+import org.opends.quicksetup.UserInteraction;
+import org.opends.quicksetup.event.ProgressUpdateListener;
+import org.opends.quicksetup.util.ProgressMessageFormatter;
+import org.opends.quicksetup.util.Utils;
+import org.opends.quicksetup.util.ServerController;
+import org.opends.quicksetup.util.FileManager;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.FilenameFilter;
+import java.io.FileFilter;
+import java.util.Arrays;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.EnumSet;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Reverts an installation from its current version to a prior version.
+ */
+public class Reverter extends Application implements CliApplication {
+
+  static private final Logger LOG =
+          Logger.getLogger(Reverter.class.getName());
+
+  private ReversionProgressStep currentProgressStep =
+          ReversionProgressStep.NOT_STARTED;
+
+  private ReverterUserData userData;
+  private ProgressMessageFormatter formatter;
+  private ProgressUpdateListenerDelegate listenerDelegate;
+  private ApplicationException runError;
+  private ApplicationException runWarning;
+  private Installation installation;
+  private File tempBackupDir;
+  private long historicalOperationId;
+  private BuildInformation fromBuildInfo;
+  private BuildInformation toBuildInfo;
+  private boolean abort = false;
+
+  /**
+   * {@inheritDoc}
+   */
+  public UserData createUserData(Launcher launcher) throws UserDataException {
+    ReverterUserData ud = null;
+    if (launcher instanceof ReversionLauncher) {
+      ud = new ReverterUserData();
+      ReversionLauncher rl = (ReversionLauncher)launcher;
+      File filesDir = null;
+      if (rl.useMostRecentUpgrade()) {
+        Installation install = getInstallation();
+        File historyDir = install.getHistoryDirectory();
+        if (historyDir.exists()) {
+          FilenameFilter filter = new FilenameFilter() {
+            public boolean accept(File dir, String name) {
+              return !Installation.HISTORY_LOG_FILE_NAME.equals(name);
+            }
+          };
+          String[] childNames = historyDir.list(filter);
+          if (childNames != null && childNames.length > 0) {
+
+            // The directories beneath 'history' are named according
+            // to the system time at which they were generated.
+            // Go through the directory names in order of most
+            // recent to oldest looking for the first one that
+            // looks like a backup directory
+            Arrays.sort(childNames);
+            for (String childName : childNames) {
+              File b = new File(historyDir, childName);
+              File d = new File(b, Installation.HISTORY_BACKUP_FILES_DIR_NAME);
+              if (isFilesDirectory(d)) {
+                filesDir = d;
+                break;
+              }
+            }
+
+          } else {
+            throw new UserDataException(null,
+                    getMsg("revert-error-empty-history-dir"));
+          }
+        } else {
+          throw new UserDataException(null,
+                  getMsg("revert-error-no-history-dir"));
+        }
+      } else {
+        filesDir = rl.getFilesDirectory();
+
+        if (filesDir != null) {
+          // Automatically append the 'filesDir' subdirectory if necessary
+          if (!filesDir.getName().
+                  endsWith(Installation.HISTORY_BACKUP_FILES_DIR_NAME)) {
+            filesDir = new File(filesDir,
+                    Installation.HISTORY_BACKUP_FILES_DIR_NAME);
+          }
+        } else {
+          StringBuilder sb = new StringBuilder()
+                  .append("-")
+                  .append(ReversionLauncher.DIRECTORY_OPTION_SHORT)
+                  .append("/--")
+                  .append(ReversionLauncher.DIRECTORY_OPTION_LONG)
+                  .append(", -")
+                  .append(ReversionLauncher.MOST_RECENT_OPTION_SHORT)
+                  .append("/--")
+                  .append(ReversionLauncher.MOST_RECENT_OPTION_LONG);
+          throw new UserDataException(null,
+                  getMsg("revert-error-no-dir", sb.toString()));
+        }
+      }
+      if (validateFilesDirectory(filesDir)) {
+        ud.setFilesDirectory(filesDir);
+      }
+    }
+    return ud;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public UserData getUserData() {
+    return this.userData;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public void setUserData(UserData userData) {
+    if (userData instanceof ReverterUserData) {
+      this.userData = (ReverterUserData)userData;
+    }
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public void setProgressMessageFormatter(ProgressMessageFormatter formatter) {
+    this.formatter = formatter;
+    this.listenerDelegate = new ProgressUpdateListenerDelegate(formatter);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public ApplicationException getRunError() {
+    return this.runError;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public void addProgressUpdateListener(ProgressUpdateListener l) {
+    listenerDelegate.addProgressUpdateListener(l);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public void removeProgressUpdateListener(ProgressUpdateListener l) {
+    listenerDelegate.removeProgressUpdateListener(l);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public void notifyListeners(Integer ratio,
+                              String currentPhaseSummary,
+                              String newLogDetail) {
+    listenerDelegate.notifyListeners(null,
+            ratio,
+            currentPhaseSummary,
+            newLogDetail);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public String getInstallationPath() {
+    String installationPath = null;
+    String path = Utils.getInstallPathFromClasspath();
+    if (path != null) {
+      File f = new File(path);
+      if (f.getParentFile() != null &&
+              f.getParentFile().getParentFile() != null &&
+              new File(f.getParentFile().getParentFile(),
+                      Installation.LOCKS_PATH_RELATIVE).exists()) {
+        installationPath = Utils.getPath(f.getParentFile().getParentFile());
+      } else {
+        installationPath = path;
+      }
+    }
+    return installationPath;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public ProgressStep getCurrentProgressStep() {
+    return this.currentProgressStep;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public Integer getRatio(ProgressStep step) {
+    Integer ratio = null;
+    if (step instanceof ReversionProgressStep) {
+      ratio = ((ReversionProgressStep)step).getProgress();
+    }
+    return ratio;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public String getSummary(ProgressStep step) {
+    String txt;
+    if (step == ReversionProgressStep.FINISHED) {
+      txt = getFinalSuccessMessage();
+//    } else if (step == ReversionProgressStep.FINISHED_CANCELED) {
+//      txt = getFinalCanceledMessage();
+//    } else if (step == ReversionProgressStep.FINISHED_WITH_ERRORS) {
+//      txt = getFinalErrorMessage();
+//    } else if (step == ReversionProgressStep.FINISHED_WITH_WARNINGS) {
+//      txt = getFinalWarningMessage();
+    }
+    else {
+      txt = getMsg(((ReversionProgressStep) step).getSummaryMesssageKey());
+    }
+    return txt;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean isFinished() {
+    return getCurrentProgressStep() ==
+            ReversionProgressStep.FINISHED
+            || getCurrentProgressStep() ==
+            ReversionProgressStep.FINISHED_WITH_ERRORS
+            || getCurrentProgressStep() ==
+            ReversionProgressStep.FINISHED_WITH_WARNINGS
+            || getCurrentProgressStep() ==
+            ReversionProgressStep.FINISHED_CANCELED;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean isCancellable() {
+    return false;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public void cancel() {
+    // not supported
+  }
+
+  /**
+   * Gets the OpenDS installation associated with the execution of this
+   * command.
+   * @return Installation object representing the current OpenDS installation
+   */
+  public Installation getInstallation() {
+    if (installation == null) {
+      String installPath = getInstallationPath();
+      if (installPath != null) {
+        installation = new Installation(installPath);
+      }
+    }
+    return installation;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public void run() {
+
+    try {
+      initialize();
+
+      UserInteraction ui = userInteraction();
+      if (ui != null) {
+        String cont = "Continue";
+        String cancel = "Cancel";
+
+        String toBuildString = null;
+        BuildInformation toBi = getToBuildInformation();
+        if (toBi != null) {
+          toBuildString = toBi.toString();
+        } else {
+          toBuildString = getMsg("upgrade-build-id-unknown");
+        }
+        if (cancel.equals(ui.confirm("Confirm Reversion",
+                "This installation will be reverted to version " +
+                        toBuildString +
+                        " using the files in " + getFilesDirectory() + ".",
+                "Confirm",
+                UserInteraction.MessageType.WARNING,
+                new String[] { cont, cancel },
+                cont))) {
+          throw new ApplicationException(ApplicationException.Type.CANCEL,
+                  getMsg("reversion-canceled"), null);
+        }
+      }
+
+      stopServer();
+      revertFiles();
+    } catch (Throwable e) {
+      if (!(e instanceof ApplicationException)) {
+        runError = new ApplicationException(
+                ApplicationException.Type.BUG,
+                e.getLocalizedMessage(), e);
+      } else {
+        runError = (ApplicationException)e;
+      }
+    } finally {
+      end();
+    }
+  }
+
+  private void setCurrentProgressStep(ReversionProgressStep step) {
+    this.currentProgressStep = step;
+    int progress = step.getProgress();
+    String msg = getSummary(step);
+    notifyListeners(progress, msg, formatter.getFormattedProgress(msg));
+  }
+
+  private void initialize() throws ApplicationException {
+    this.historicalOperationId =
+      writeInitialHistoricalRecord(
+              getFromBuildInformation(),
+              getToBuildInformation());
+  }
+
+  private void stopServer() throws ApplicationException {
+    Installation installation = getInstallation();
+    Status status = installation.getStatus();
+    if (status.isServerRunning()) {
+      setCurrentProgressStep(ReversionProgressStep.STOPPING_SERVER);
+      ServerController sc = new ServerController(installation);
+      sc.stopServer(true);
+    }
+  }
+
+  private void revertFiles() throws ApplicationException {
+    backupFilesytem();
+    revertComponents();
+  }
+
+  private void backupFilesytem() throws ApplicationException {
+    try {
+      File filesBackupDirectory = getTempBackupDirectory();
+      FileManager fm = new FileManager();
+      File root = getInstallation().getRootDirectory();
+      FileFilter filter = new UpgradeFileFilter(root);
+      for (String fileName : root.list()) {
+        File f = new File(root, fileName);
+        //fm.copyRecursively(f, filesBackupDirectory,
+        fm.move(f, filesBackupDirectory, filter);
+      }
+    } catch (ApplicationException ae) {
+      throw ae;
+    } catch (Exception e) {
+      throw new ApplicationException(
+              ApplicationException.Type.FILE_SYSTEM_ERROR,
+              getMsg("error-backup-filesystem"),
+              e);
+    }
+  }
+
+  private void revertComponents() throws ApplicationException {
+    try {
+      File stageDir = getFilesDirectory();
+      Installation installation = getInstallation();
+      File root = installation.getRootDirectory();
+      FileManager fm = new FileManager();
+      for (String fileName : stageDir.list()) {
+        File f = new File(stageDir, fileName);
+        fm.copyRecursively(f, root,
+                new UpgradeFileFilter(stageDir),
+                /*overwrite=*/true);
+      }
+
+      // The bits should now be of the new version.  Have
+      // the installation update the build information so
+      // that it is correct.
+      LOG.log(Level.INFO, "reverted bits to " +
+              installation.getBuildInformation(false));
+
+    } catch (IOException e) {
+      throw ApplicationException.createFileSystemException(
+              getMsg("error-upgrading-components"), e);
+    }
+  }
+
+  private File getFilesDirectory()
+          throws ApplicationException, IOException {
+    return userData.getFilesDirectory();
+  }
+
+  private boolean validateFilesDirectory(File filesDir)
+          throws UserDataException
+  {
+    if (filesDir == null) {
+      throw new UserDataException(null,
+              getMsg("revert-error-null-files-dir"));
+    } else if (!filesDir.isDirectory()) {
+      throw new UserDataException(null,
+              getMsg("revert-error-not-dir-files-dir"));
+    } else if (!isFilesDirectory(filesDir)) {
+      throw new UserDataException(null,
+              getMsg("revert-error-not-dir-files-dir"));
+    }
+    return true;
+  }
+
+  private boolean isFilesDirectory(File filesDir) {
+    boolean isFilesDir = false;
+    if (filesDir != null && filesDir.isDirectory()) {
+      String[] children = filesDir.list();
+      Set<String> cs = new HashSet<String>(Arrays.asList(children));
+
+      // TODO:  more testing of file dir
+      isFilesDir = cs.contains(Installation.CONFIG_PATH_RELATIVE) &&
+              cs.contains(Installation.LIBRARIES_PATH_RELATIVE);
+    }
+    return isFilesDir;
+  }
+
+  private void end() {
+    try {
+      HistoricalRecord.Status status;
+      String note = null;
+      if (runError == null && !abort) {
+        status = HistoricalRecord.Status.SUCCESS;
+      } else {
+        if (abort) {
+          status = HistoricalRecord.Status.CANCEL;
+        } else {
+          status = HistoricalRecord.Status.FAILURE;
+          note = runError.getLocalizedMessage();
+        }
+
+        // Abort the reversion and put things back like we found it
+        LOG.log(Level.INFO, "canceling reversion");
+        ProgressStep lastProgressStep = currentProgressStep;
+        setCurrentProgressStep(ReversionProgressStep.ABORT);
+        abort(lastProgressStep);
+        notifyListeners(formatter.getFormattedDone() +
+                formatter.getLineBreak());
+        LOG.log(Level.INFO, "cancelation complete");
+      }
+
+      LOG.log(Level.INFO, "cleaning up after reversion");
+      setCurrentProgressStep(ReversionProgressStep.CLEANUP);
+      cleanup();
+      notifyListeners(formatter.getFormattedDone() +
+              formatter.getLineBreak());
+      LOG.log(Level.INFO, "clean up complete");
+
+
+      // Write a record in the log file indicating success/failure
+      LOG.log(Level.INFO, "recording history");
+      setCurrentProgressStep(ReversionProgressStep.RECORDING_HISTORY);
+      writeHistoricalRecord(historicalOperationId,
+              getFromBuildInformation(),
+              getToBuildInformation(),
+              status,
+              note);
+
+      notifyListeners(formatter.getFormattedDone() +
+              formatter.getLineBreak());
+      LOG.log(Level.INFO, "history recorded");
+      notifyListeners(getMsg("general-see-for-history",
+              Utils.getPath(getInstallation().getHistoryLogFile())) +
+              formatter.getLineBreak());
+    } catch (ApplicationException e) {
+      notifyListeners(formatter.getFormattedError() +
+              formatter.getLineBreak());
+      LOG.log(Level.INFO, "Error cleaning up after upgrade.", e);
+    }
+
+    // Decide final status based on presense of error
+
+    // WARNING: change this code at your own risk!  The ordering
+    // of these statements is important.  There are differences
+    // in how the CLI and GUI application's processes exit.
+    // Changing the ordering here may result in messages being
+    // skipped because the process has already exited by the time
+    // processing messages has finished.  Need to resolve these
+    // issues.
+    if (abort) {
+      LOG.log(Level.INFO, "upgrade canceled by user");
+      setCurrentProgressStep(ReversionProgressStep.FINISHED_CANCELED);
+    } else if (runError != null) {
+      LOG.log(Level.INFO, "upgrade completed with errors", runError);
+      notifyListeners(formatter.getFormattedError(runError, true) +
+                      formatter.getLineBreak());
+      notifyListeners(formatter.getLineBreak());
+      setCurrentProgressStep(ReversionProgressStep.FINISHED_WITH_ERRORS);
+      notifyListeners(formatter.getLineBreak());
+    } else if (runWarning != null) {
+      LOG.log(Level.INFO, "upgrade completed with warnings");
+      String warningText = runWarning.getLocalizedMessage();
+
+      // By design, the warnings are written as errors to the details section
+      // as errors.  Warning markup is used surrounding the main message
+      // at the end of progress.
+      notifyListeners(formatter.getFormattedError(warningText, true) +
+                      formatter.getLineBreak());
+      notifyListeners(formatter.getLineBreak());
+      setCurrentProgressStep(ReversionProgressStep.FINISHED_WITH_WARNINGS);
+      notifyListeners(formatter.getLineBreak());
+
+    } else {
+      LOG.log(Level.INFO, "reversion completed successfully");
+      setCurrentProgressStep(ReversionProgressStep.FINISHED);
+    }
+  }
+
+  /**
+   * Abort this reversion and repair the installation.
+   *
+   * @param lastStep ProgressStep indicating how much work we will have to
+   *                 do to get the installation back like we left it
+   * @throws ApplicationException of something goes wrong
+   */
+  private void abort(ProgressStep lastStep) throws ApplicationException {
+
+    // This can be used to bypass the aborted reversion cleanup
+    // process so that an autopsy can be performed on the
+    // crippled server.
+    if ("true".equals(System.getProperty(Upgrader.SYS_PROP_NO_ABORT))) {
+      return;
+    }
+
+    ReversionProgressStep lastReversionStep = (ReversionProgressStep) lastStep;
+    EnumSet<ReversionProgressStep> stepsStarted =
+            EnumSet.range(ReversionProgressStep.NOT_STARTED, lastReversionStep);
+
+    if (stepsStarted.contains(ReversionProgressStep.REVERTING_FILESYSTEM)) {
+
+      // Files were copied from the reversion directory to the current
+      // directory.  Repair things by overwriting file in the
+      // root with those that were copied to the backup directory
+      // during revertFiles()
+
+      File root = getInstallation().getRootDirectory();
+      File backupDirectory;
+      try {
+        backupDirectory = getTempBackupDirectory();
+        FileManager fm = new FileManager();
+        boolean restoreError = false;
+        for (String fileName : backupDirectory.list()) {
+          File f = new File(backupDirectory, fileName);
+
+          // Do our best to restore the filesystem like
+          // we found it.  Just report potential problems
+          // to the user.
+          try {
+            fm.move(f, root, null);
+          } catch (Throwable t) {
+            restoreError = true;
+            notifyListeners(getMsg("error-restoring-file",
+                    Utils.getPath(f),
+                    Utils.getPath(root)));
+          }
+        }
+        if (!restoreError) {
+          fm.deleteRecursively(backupDirectory);
+        }
+
+        // Restart the server after putting the files
+        // back like we found them.
+        ServerController sc = new ServerController(getInstallation());
+        sc.stopServer(true);
+        sc.startServer(true);
+
+      } catch (IOException e) {
+        LOG.log(Level.INFO, "Error getting backup directory", e);
+      }
+    }
+
+  }
+
+  private void cleanup() {
+    // TODO:
+  }
+
+  /**
+   * Gets the directory that will be used to store the bits that this
+   * reversion operation will replace.  The bits are stored in case there
+   * is a problem with this reversion in which case they can be restored.
+   *
+   * @return File directory where the unreverted bits will be stored.
+   */
+  private File getTempBackupDirectory()
+          throws IOException, ApplicationException
+  {
+    if (tempBackupDir == null) {
+      tempBackupDir = new File(getInstallation().getTemporaryDirectory(),
+              Installation.HISTORY_BACKUP_FILES_DIR_NAME);
+      if (tempBackupDir.exists()) {
+        FileManager fm = new FileManager();
+        fm.deleteRecursively(tempBackupDir);
+      }
+      if (!tempBackupDir.mkdirs()) {
+        throw new IOException("error creating files backup directory");
+      }
+    }
+    return tempBackupDir;
+  }
+
+  private BuildInformation getFromBuildInformation() {
+    if (fromBuildInfo == null) {
+      if (currentProgressStep.ordinal() <
+              ReversionProgressStep.REVERTING_FILESYSTEM.ordinal()) {
+        try {
+          fromBuildInfo = installation.getBuildInformation(false);
+        } catch (ApplicationException e) {
+          LOG.log(Level.INFO, "Failed to obtain 'from' build information", e);
+        }
+      }
+    }
+    return fromBuildInfo;
+  }
+
+  private BuildInformation getToBuildInformation() {
+    if (toBuildInfo == null) {
+      if (currentProgressStep.ordinal() >
+              ReversionProgressStep.REVERTING_FILESYSTEM.ordinal()) {
+        try {
+          toBuildInfo = installation.getBuildInformation(false);
+        } catch (ApplicationException e) {
+          LOG.log(Level.INFO, "Failed to obtain 'from' build information", e);
+        }
+      } else {
+        // TODO: try to determine build info from backed up bits
+      }
+    }
+    return toBuildInfo;
+  }
+
+  private String getFinalSuccessMessage() {
+    String txt;
+    String installPath = Utils.getPath(getInstallation().getRootDirectory());
+    String newVersion;
+    try {
+      BuildInformation bi = getInstallation().getBuildInformation();
+      if (bi != null) {
+        newVersion = bi.toString();
+      } else {
+        newVersion = getMsg("reversion-build-id-unknown");
+      }
+    } catch (ApplicationException e) {
+      newVersion = getMsg("reversion-build-id-unknown");
+    }
+    String[] args = {
+            formatter.getFormattedText(installPath),
+            newVersion};
+    txt = getMsg("summary-revert-finished-successfully-cli", args);
+    return txt;
+  }
+
+
+}
diff --git a/opends/src/quicksetup/org/opends/quicksetup/upgrader/ReverterUserData.java b/opends/src/quicksetup/org/opends/quicksetup/upgrader/ReverterUserData.java
new file mode 100644
index 0000000..9f26da1
--- /dev/null
+++ b/opends/src/quicksetup/org/opends/quicksetup/upgrader/ReverterUserData.java
@@ -0,0 +1,57 @@
+/*
+ * 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 2007 Sun Microsystems, Inc.
+ */
+
+package org.opends.quicksetup.upgrader;
+
+import org.opends.quicksetup.UserData;
+
+import java.io.File;
+
+/**
+ * Holds state data specific to a reversion operation.
+ */
+class ReverterUserData extends UserData {
+
+  File filesDir = null;
+
+  /**
+   * Gets the directory where the files are stored for the reversion.
+   * @return File where the reversion files are kept
+   */
+  public File getFilesDirectory() {
+    return filesDir;
+  }
+
+  /**
+   * Sets the directory where the files are stored for the reversion.
+   * @param files where the reversion files are kept
+   */
+  public void setFilesDirectory(File files) {
+    this.filesDir = files;
+  }
+
+}
diff --git a/opends/src/quicksetup/org/opends/quicksetup/upgrader/UpgradeFileFilter.java b/opends/src/quicksetup/org/opends/quicksetup/upgrader/UpgradeFileFilter.java
new file mode 100644
index 0000000..1cb7aad
--- /dev/null
+++ b/opends/src/quicksetup/org/opends/quicksetup/upgrader/UpgradeFileFilter.java
@@ -0,0 +1,72 @@
+/*
+ * 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 2007 Sun Microsystems, Inc.
+ */
+
+package org.opends.quicksetup.upgrader;
+
+import org.opends.quicksetup.util.Utils;
+
+import java.io.FileFilter;
+import java.io.File;
+import java.util.Set;
+import java.util.HashSet;
+
+/**
+   * Filter defining files we want to manage in the upgrade
+ * process.
+ */
+class UpgradeFileFilter implements FileFilter {
+
+  Set<File> filesToIgnore;
+
+  /**
+   * Creates a filter for ignoring in an OpenDS installation at
+   * <code>root</code>certain OpenDS files below root.
+   * @param root the root of the installation
+   */
+  public UpgradeFileFilter(File root) { //throws IOException {
+    this.filesToIgnore = new HashSet<File>();
+    for (String rootFileNamesToIgnore :
+            Upgrader.ROOT_FILES_TO_IGNORE_DURING_BACKUP) {
+      filesToIgnore.add(new File(root, rootFileNamesToIgnore));
+    }
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean accept(File file) {
+    boolean accept = true;
+    for (File ignoreFile : filesToIgnore) {
+      if (ignoreFile.equals(file) ||
+              Utils.isParentOf(ignoreFile, file)) {
+        accept = false;
+        break;
+      }
+    }
+    return accept;
+  }
+}
diff --git a/opends/src/quicksetup/org/opends/quicksetup/upgrader/UpgradeOracle.java b/opends/src/quicksetup/org/opends/quicksetup/upgrader/UpgradeIssueNotifier.java
similarity index 94%
rename from opends/src/quicksetup/org/opends/quicksetup/upgrader/UpgradeOracle.java
rename to opends/src/quicksetup/org/opends/quicksetup/upgrader/UpgradeIssueNotifier.java
index 15f3b64..1f2f43e 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/upgrader/UpgradeOracle.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/upgrader/UpgradeIssueNotifier.java
@@ -40,13 +40,13 @@
 import java.util.logging.Level;
 
 /**
- * {@link org.opends.quicksetup.upgrader.VersionOracle} specific
+ * {@link org.opends.quicksetup.upgrader.VersionIssueNotifier} specific
  * to upgrade tools.
  */
-public class UpgradeOracle extends VersionOracle {
+public class UpgradeIssueNotifier extends VersionIssueNotifier {
 
   static private final Logger LOG =
-          Logger.getLogger(UpgradeOracle.class.getName());
+          Logger.getLogger(UpgradeIssueNotifier.class.getName());
 
   /**
    * Creates a new instance that can analyze a hypothetical upgrade/reversion
@@ -55,7 +55,7 @@
    * @param current BuildInformation representing the current version
    * @param neu BuildInformation representing the proposed next version
    */
-  public UpgradeOracle(UserInteraction ui,
+  public UpgradeIssueNotifier(UserInteraction ui,
                        BuildInformation current,
                        BuildInformation neu) {
     super(ui, current, neu);
@@ -72,7 +72,7 @@
       List<Directive> issues = getIssues();
       if (!isSupported()) {
         if (issues != null) {
-          for (VersionOracle.Directive directive : issues) {
+          for (VersionIssueNotifier.Directive directive : issues) {
             LOG.log(Level.INFO, "Unsupported upgrade details: " +
                     directive.getMessage());
           }
@@ -81,7 +81,7 @@
                 getMsg("upgrade-oracle-unsupported", args), null);
       } else {
         if (ui != null) {
-          for (VersionOracle.Directive directive : issues) {
+          for (VersionIssueNotifier.Directive directive : issues) {
             String title;
             String summary;
             String details;
diff --git a/opends/src/quicksetup/org/opends/quicksetup/upgrader/UpgradeLauncher.java b/opends/src/quicksetup/org/opends/quicksetup/upgrader/UpgradeLauncher.java
index 0999a2f..11084c6 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/upgrader/UpgradeLauncher.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/upgrader/UpgradeLauncher.java
@@ -53,12 +53,15 @@
   /** Prefix for log files. */
   static public final String LOG_FILE_PREFIX = "opends-upgrade-";
 
-  /** Suffix for log files. */
-  static public final String LOG_FILE_SUFFIX = ".log";
-
   static private final Logger LOG =
           Logger.getLogger(UpgradeLauncher.class.getName());
 
+  /** Short form of the option for specifying the installation package file. */
+  static public final Character FILE_OPTION_SHORT = 'f';
+
+  /** Long form of the option for specifying the installation package file. */
+  static public final String FILE_OPTION_LONG = "file";
+
   /**
    * The main method which is called by the setup command lines.
    *
@@ -67,7 +70,8 @@
   public static void main(String[] args) {
     try {
       QuickSetupLog.initLogFileHandler(
-              File.createTempFile(LOG_FILE_PREFIX, LOG_FILE_SUFFIX));
+              File.createTempFile(LOG_FILE_PREFIX,
+                      QuickSetupLog.LOG_FILE_SUFFIX));
     } catch (Throwable t) {
       System.err.println(
               ResourceProvider.getInstance().getMsg("error-initializing-log"));
@@ -76,6 +80,8 @@
     new UpgradeLauncher(args).launch();
   }
 
+  private ArgumentParser argParser;
+
   /**
    * {@inheritDoc}
    */
@@ -95,40 +101,13 @@
    * {@inheritDoc}
    */
   protected void printUsage(boolean toStdErr) {
-    ArgumentParser argParser = new ArgumentParser(getClass().getName(),
-        getI18n().getMsg("upgrade-launcher-usage-description"), false);
-    BooleanArgument showUsage;
-    FileBasedArgument file;
-    BooleanArgument silent;
-    BooleanArgument interactive;
-    String scriptName;
-    if (Utils.isWindows()) {
-      scriptName = Installation.WINDOWS_UPGRADE_FILE_NAME;
-    } else {
-      scriptName = Installation.UNIX_UPGRADE_FILE_NAME;
-    }
-    System.setProperty(ServerConstants.PROPERTY_SCRIPT_NAME, scriptName);
     try
     {
-      file = new FileBasedArgument("file", 'f',
-          "file", false, false,
-          "{file}",
-          null, null, MSGID_UPGRADE_DESCRIPTION_FILE);
-      argParser.addArgument(file);
-      interactive = new BooleanArgument("interactive", 'i', "interactive",
-          MSGID_UPGRADE_DESCRIPTION_INTERACTIVE);
-      argParser.addArgument(interactive);
-      silent = new BooleanArgument("silent", 's', "silent",
-          MSGID_UPGRADE_DESCRIPTION_SILENT);
-      argParser.addArgument(silent);
-      showUsage = new BooleanArgument("showusage", OPTION_SHORT_HELP,
-        OPTION_LONG_HELP,
-        MSGID_DESCRIPTION_USAGE);
-      argParser.addArgument(showUsage);
-      argParser.setUsageArgument(showUsage);
-
-      String msg = argParser.getUsage();
-      printUsage(msg, toStdErr);
+      ArgumentParser argParser = getArgumentParser();
+      if (argParser != null) {
+        String msg = argParser.getUsage();
+        printUsage(msg, toStdErr);
+      }
     }
     catch (Throwable t)
     {
@@ -169,12 +148,62 @@
   }
 
   /**
+   * {@inheritDoc}
+   */
+  public ArgumentParser getArgumentParser() {
+    return argParser;
+  }
+
+  /**
    * Creates an instance.
    *
    * @param args specified on command line
    */
   protected UpgradeLauncher(String[] args) {
     super(args);
+
+    String scriptName;
+    if (Utils.isWindows()) {
+      scriptName = Installation.WINDOWS_UPGRADE_FILE_NAME;
+    } else {
+      scriptName = Installation.UNIX_UPGRADE_FILE_NAME;
+    }
+    System.setProperty(ServerConstants.PROPERTY_SCRIPT_NAME, scriptName);
+
+    argParser = new ArgumentParser(getClass().getName(),
+        getI18n().getMsg("upgrade-launcher-usage-description"), false);
+    BooleanArgument showUsage;
+    FileBasedArgument file;
+    BooleanArgument silent;
+    BooleanArgument interactive;
+    try
+    {
+      file = new FileBasedArgument(
+              "file",
+              FILE_OPTION_SHORT,
+              FILE_OPTION_LONG,
+              false, false,
+              "{file}",
+              null, null, MSGID_UPGRADE_DESCRIPTION_FILE);
+      argParser.addArgument(file);
+      interactive = new BooleanArgument("interactive", 'i', "interactive",
+          MSGID_UPGRADE_DESCRIPTION_INTERACTIVE);
+      argParser.addArgument(interactive);
+      silent = new BooleanArgument("silent", 's', "silent",
+          MSGID_UPGRADE_DESCRIPTION_SILENT);
+      argParser.addArgument(silent);
+      showUsage = new BooleanArgument("showusage", OPTION_SHORT_HELP,
+        OPTION_LONG_HELP,
+        MSGID_DESCRIPTION_USAGE);
+      argParser.addArgument(showUsage);
+      argParser.setUsageArgument(showUsage);
+    }
+    catch (Throwable t)
+    {
+      System.out.println("ERROR: "+t);
+      t.printStackTrace();
+    }
+
   }
 
 }
diff --git a/opends/src/quicksetup/org/opends/quicksetup/upgrader/UpgradeProgressStep.java b/opends/src/quicksetup/org/opends/quicksetup/upgrader/UpgradeProgressStep.java
new file mode 100644
index 0000000..dead65a
--- /dev/null
+++ b/opends/src/quicksetup/org/opends/quicksetup/upgrader/UpgradeProgressStep.java
@@ -0,0 +1,128 @@
+/*
+ * 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 2007 Sun Microsystems, Inc.
+ */
+
+package org.opends.quicksetup.upgrader;
+
+import org.opends.quicksetup.ProgressStep;
+
+/**
+   * Steps during the upgrade process.
+ */
+enum UpgradeProgressStep implements ProgressStep {
+
+  NOT_STARTED("summary-upgrade-not-started", 0),
+
+  DOWNLOADING("summary-upgrade-downloading", 10),
+
+  EXTRACTING("summary-upgrade-extracting", 20),
+
+  INITIALIZING("summary-upgrade-initializing", 30),
+
+  CHECK_SERVER_HEALTH("summary-upgrade-check-server-health", 35),
+
+  CALCULATING_SCHEMA_CUSTOMIZATIONS(
+          "summary-upgrade-calculating-schema-customization", 40),
+
+  CALCULATING_CONFIGURATION_CUSTOMIZATIONS(
+          "summary-upgrade-calculating-config-customization", 48),
+
+  BACKING_UP_DATABASES("summary-upgrade-backing-up-db", 50),
+
+  BACKING_UP_FILESYSTEM("summary-upgrade-backing-up-files",52),
+
+  UPGRADING_COMPONENTS("summary-upgrade-upgrading-components", 60),
+
+  PREPARING_CUSTOMIZATIONS("summary-upgrade-preparing-customizations", 65),
+
+  APPLYING_SCHEMA_CUSTOMIZATIONS(
+          "summary-upgrade-applying-schema-customization", 70),
+
+  APPLYING_CONFIGURATION_CUSTOMIZATIONS(
+          "summary-upgrade-applying-config-customization", 75),
+
+  VERIFYING("summary-upgrade-verifying", 80),
+
+  STARTING_SERVER("summary-starting", 90),
+
+  STOPPING_SERVER("summary-stopping", 90),
+
+  RECORDING_HISTORY("summary-upgrade-history", 97),
+
+  CLEANUP("summary-upgrade-cleanup", 99),
+
+  ABORT("summary-upgrade-abort", 99),
+
+  FINISHED_WITH_ERRORS("summary-upgrade-finished-with-errors", 100),
+
+  FINISHED_WITH_WARNINGS("summary-upgrade-finished-with-warnings", 100),
+
+  FINISHED_CANCELED("summary-upgrade-finished-canceled", 100),
+
+  FINISHED("summary-upgrade-finished-successfully", 100);
+
+  private String summaryMsgKey;
+  private int progress;
+
+  private UpgradeProgressStep(String summaryMsgKey, int progress) {
+    this.summaryMsgKey = summaryMsgKey;
+    this.progress = progress;
+  }
+
+  /**
+   * Return a key for access a summary message.
+   *
+   * @return String representing key for access summary in resource bundle
+   */
+  public String getSummaryMesssageKey() {
+    return summaryMsgKey;
+  }
+
+  /**
+   * Gets the amount of progress to show in the progress meter for this step.
+   * @return int representing progress
+   */
+  public int getProgress() {
+    return this.progress;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean isLast() {
+    return this == FINISHED ||
+            this == FINISHED_WITH_ERRORS ||
+            this == FINISHED_WITH_WARNINGS ||
+            this == FINISHED_CANCELED;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean isError() {
+    return this == FINISHED_WITH_ERRORS;
+  }
+}
diff --git a/opends/src/quicksetup/org/opends/quicksetup/upgrader/Upgrader.java b/opends/src/quicksetup/org/opends/quicksetup/upgrader/Upgrader.java
index 8cfd0f8..9d1616d 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/upgrader/Upgrader.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/upgrader/Upgrader.java
@@ -39,9 +39,10 @@
 import org.opends.quicksetup.ButtonName;
 import org.opends.quicksetup.UserDataException;
 import org.opends.quicksetup.BuildInformation;
-import org.opends.quicksetup.CurrentInstallStatus;
 import org.opends.quicksetup.UserInteraction;
 import org.opends.quicksetup.Constants;
+import org.opends.quicksetup.Launcher;
+import org.opends.quicksetup.HistoricalRecord;
 import org.opends.quicksetup.i18n.ResourceProvider;
 import org.opends.quicksetup.webstart.WebStartDownloader;
 import org.opends.quicksetup.util.Utils;
@@ -76,7 +77,6 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.EnumSet;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 import java.util.logging.Level;
@@ -88,104 +88,6 @@
  */
 public class Upgrader extends GuiApplication implements CliApplication {
 
-  /**
-   * Steps during the upgrade process.
-   */
-  enum UpgradeProgressStep implements ProgressStep {
-
-    NOT_STARTED("summary-upgrade-not-started", 0),
-
-    DOWNLOADING("summary-upgrade-downloading", 10),
-
-    EXTRACTING("summary-upgrade-extracting", 20),
-
-    INITIALIZING("summary-upgrade-initializing", 30),
-
-    CHECK_SERVER_HEALTH("summary-upgrade-check-server-health", 35),
-
-    CALCULATING_SCHEMA_CUSTOMIZATIONS(
-            "summary-upgrade-calculating-schema-customization", 40),
-
-    CALCULATING_CONFIGURATION_CUSTOMIZATIONS(
-            "summary-upgrade-calculating-config-customization", 48),
-
-    BACKING_UP_DATABASES("summary-upgrade-backing-up-db", 50),
-
-    BACKING_UP_FILESYSTEM("summary-upgrade-backing-up-files",52),
-
-    UPGRADING_COMPONENTS("summary-upgrade-upgrading-components", 60),
-
-    PREPARING_CUSTOMIZATIONS("summary-upgrade-preparing-customizations", 65),
-
-    APPLYING_SCHEMA_CUSTOMIZATIONS(
-            "summary-upgrade-applying-schema-customization", 70),
-
-    APPLYING_CONFIGURATION_CUSTOMIZATIONS(
-            "summary-upgrade-applying-config-customization", 75),
-
-    VERIFYING("summary-upgrade-verifying", 80),
-
-    STARTING_SERVER("summary-starting", 90),
-
-    STOPPING_SERVER("summary-stopping", 90),
-
-    RECORDING_HISTORY("summary-upgrade-history", 97),
-
-    CLEANUP("summary-upgrade-cleanup", 99),
-
-    ABORT("summary-upgrade-abort", 99),
-
-    FINISHED_WITH_ERRORS("summary-upgrade-finished-with-errors", 100),
-
-    FINISHED_WITH_WARNINGS("summary-upgrade-finished-with-warnings", 100),
-
-    FINISHED_CANCELED("summary-upgrade-finished-canceled", 100),
-
-    FINISHED("summary-upgrade-finished-successfully", 100);
-
-    private String summaryMsgKey;
-    private int progress;
-
-    private UpgradeProgressStep(String summaryMsgKey, int progress) {
-      this.summaryMsgKey = summaryMsgKey;
-      this.progress = progress;
-    }
-
-    /**
-     * Return a key for access a summary message.
-     *
-     * @return String representing key for access summary in resource bundle
-     */
-    public String getSummaryMesssageKey() {
-      return summaryMsgKey;
-    }
-
-    /**
-     * Gets the amount of progress to show in the progress meter for this step.
-     * @return int representing progress
-     */
-    public int getProgress() {
-      return this.progress;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public boolean isLast() {
-      return this == FINISHED ||
-              this == FINISHED_WITH_ERRORS ||
-              this == FINISHED_WITH_WARNINGS ||
-              this == FINISHED_CANCELED;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public boolean isError() {
-      return this == FINISHED_WITH_ERRORS;
-    }
-  }
-
   static private final Logger LOG = Logger.getLogger(Upgrader.class.getName());
 
   /**
@@ -215,11 +117,11 @@
    * changes is made a no-op leaving the server in the
    * erroneous state.
    */
-  static private final String SYS_PROP_NO_ABORT =
+  static final String SYS_PROP_NO_ABORT =
           "org.opends.quicksetup.upgrader.NoAbort";
 
   // Root files that will be ignored during backup
-  static private final String[] ROOT_FILES_TO_IGNORE_DURING_BACKUP = {
+  static final String[] ROOT_FILES_TO_IGNORE_DURING_BACKUP = {
           CHANGELOG_PATH_RELATIVE, // changelogDb
           DATABASES_PATH_RELATIVE, // db
           LOGS_PATH_RELATIVE, // logs
@@ -288,7 +190,7 @@
         QuickSetupLog.initLogFileHandler(
                 File.createTempFile(
                         UpgradeLauncher.LOG_FILE_PREFIX,
-                        UpgradeLauncher.LOG_FILE_SUFFIX));
+                        QuickSetupLog.LOG_FILE_SUFFIX));
     } catch (IOException e) {
       System.err.println(
               ResourceProvider.getInstance().getMsg("error-initializing-log"));
@@ -1134,9 +1036,9 @@
         notifyListeners(formatter.getFormattedDone() +
                 formatter.getLineBreak());
         LOG.log(Level.INFO, "history recorded");
-        notifyListeners("See '" +
-                Utils.getPath(getInstallation().getHistoryLogFile()) +
-                " for upgrade history" + formatter.getLineBreak());
+        notifyListeners(getMsg("general-see-for-history",
+                Utils.getPath(getInstallation().getHistoryLogFile())) +
+                formatter.getLineBreak());
       } catch (ApplicationException e) {
         notifyListeners(formatter.getFormattedError() +
                 formatter.getLineBreak());
@@ -1279,45 +1181,6 @@
 
   }
 
-
-
-
-  private Long writeInitialHistoricalRecord(
-          BuildInformation fromVersion,
-          BuildInformation toVersion)
-          throws ApplicationException {
-    Long id;
-    try {
-      HistoricalLog log =
-              new HistoricalLog(getInstallation().getHistoryLogFile());
-      id = log.append(fromVersion, toVersion,
-              HistoricalRecord.Status.STARTED,
-              "log file '" + QuickSetupLog.getLogFile().getPath() + "'");
-    } catch (IOException e) {
-      String msg = getMsg("error-logging-operation");
-      throw ApplicationException.createFileSystemException(
-              msg, e);
-    }
-    return id;
-  }
-
-  private void writeHistoricalRecord(
-          Long id,
-          BuildInformation from,
-          BuildInformation to,
-          HistoricalRecord.Status status,
-          String note)
-          throws ApplicationException {
-    try {
-      HistoricalLog log =
-              new HistoricalLog(getInstallation().getHistoryLogFile());
-      log.append(id, from, to, status, note);
-    } catch (IOException e) {
-      String msg = getMsg("error-logging-operation");
-      throw ApplicationException.createFileSystemException(msg, e);
-    }
-  }
-
   private void upgradeComponents() throws ApplicationException {
     try {
       File stageDir = getStageDirectory();
@@ -1490,7 +1353,7 @@
               getMsg("error-determining-upgrade-build"), e);
     }
 
-    UpgradeOracle uo = new UpgradeOracle(
+    UpgradeIssueNotifier uo = new UpgradeIssueNotifier(
             userInteraction(), currentVersion, newVersion);
     uo.notifyUser();
     if (uo.noServerStartFollowingOperation()) {
@@ -1532,16 +1395,17 @@
 
   /**
    * {@inheritDoc}
+   * @param launcher
    */
-  public UserData createUserData(String[] args, CurrentInstallStatus cis)
+  public UserData createUserData(Launcher launcher)
           throws UserDataException {
-    return getCliHelper().createUserData(args);
+    return getCliHelper().createUserData(launcher.getArguments());
   }
 
   /**
    * {@inheritDoc}
    */
-  public ApplicationException getException() {
+  public ApplicationException getRunError() {
     return runError;
   }
 
@@ -1629,7 +1493,8 @@
   }
 
   private File getFilesBackupDirectory() throws IOException {
-    File files = new File(getUpgradeBackupDirectory(), "files");
+    File files = new File(getUpgradeBackupDirectory(),
+            Installation.HISTORY_BACKUP_FILES_DIR_NAME);
     if (!files.exists()) {
       if (!files.mkdirs()) {
         throw new IOException("error creating files backup directory");
@@ -1668,38 +1533,4 @@
     return stagedVersion;
   }
 
-  /**
-   * Filter defining files we want to manage in the upgrade
-   * process.
-   */
-  private class UpgradeFileFilter implements FileFilter {
-
-    Set<File> filesToIgnore;
-
-    public UpgradeFileFilter(File root) throws IOException {
-      this.filesToIgnore = new HashSet<File>();
-      for (String rootFileNamesToIgnore : ROOT_FILES_TO_IGNORE_DURING_BACKUP) {
-        filesToIgnore.add(new File(root, rootFileNamesToIgnore));
-      }
-
-      // Definitely want to not back this up since it would create
-      // infinite recursion.  This may not be necessary if we are
-      // ignoring the entire history directory but its added here for
-      // safe measure.
-      filesToIgnore.add(getUpgradeBackupDirectory());
-    }
-
-    public boolean accept(File file) {
-      boolean accept = true;
-      for (File ignoreFile : filesToIgnore) {
-        if (ignoreFile.equals(file) ||
-                Utils.isParentOf(ignoreFile, file)) {
-          accept = false;
-          break;
-        }
-      }
-      return accept;
-    }
-  }
-
 }
diff --git a/opends/src/quicksetup/org/opends/quicksetup/upgrader/UpgraderCliHelper.java b/opends/src/quicksetup/org/opends/quicksetup/upgrader/UpgraderCliHelper.java
index b62f39d..73fc68f 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/upgrader/UpgraderCliHelper.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/upgrader/UpgraderCliHelper.java
@@ -41,12 +41,6 @@
  */
 public class UpgraderCliHelper extends CliApplicationHelper {
 
-  /** Short form of the option for specifying the installation package file. */
-  static public final Character FILE_OPTION_SHORT = 'f';
-
-  /** Long form of the option for specifying the installation package file. */
-  static public final String FILE_OPTION_LONG = "file";
-
   static private final Logger LOG =
           Logger.getLogger(UpgraderCliHelper.class.getName());
 
@@ -79,6 +73,8 @@
 
   private ArgumentParser createArgumentParser() {
 
+    // TODO: get rid of this method and user launcher.getArgumentParser
+
     String toolDescription = getMsg("upgrade-launcher-description");
     ArgumentParser argParser = createArgumentParser(
             "org.opends.quicksetup.upgrader.Upgrader",
@@ -90,7 +86,8 @@
     try {
       localInstallPackFileNameArg =
               new StringArgument("install package file",
-                      FILE_OPTION_SHORT, FILE_OPTION_LONG,
+                      UpgradeLauncher.FILE_OPTION_SHORT,
+                      UpgradeLauncher.FILE_OPTION_LONG,
                       false, true, "{install package file}", 0);
       argParser.addArgument(localInstallPackFileNameArg);
     } catch (ArgumentException e) {
diff --git a/opends/src/quicksetup/org/opends/quicksetup/upgrader/VersionOracle.java b/opends/src/quicksetup/org/opends/quicksetup/upgrader/VersionIssueNotifier.java
similarity index 98%
rename from opends/src/quicksetup/org/opends/quicksetup/upgrader/VersionOracle.java
rename to opends/src/quicksetup/org/opends/quicksetup/upgrader/VersionIssueNotifier.java
index db0a271..850ed79 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/upgrader/VersionOracle.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/upgrader/VersionIssueNotifier.java
@@ -50,10 +50,10 @@
  * interacting with the user to inform them of an actions or information
  * that they dictate.
  */
-public abstract class VersionOracle {
+public abstract class VersionIssueNotifier {
 
   static private final Logger LOG =
-          Logger.getLogger(VersionOracle.class.getName());
+          Logger.getLogger(VersionIssueNotifier.class.getName());
 
   /** Descriptor for a directive. */
   protected enum DirectiveType {
@@ -131,7 +131,7 @@
    * @param current build version
    * @param neu build version
    */
-  public VersionOracle(UserInteraction ui,
+  public VersionIssueNotifier(UserInteraction ui,
                        BuildInformation current,
                        BuildInformation neu) {
     this.ui = ui;
diff --git a/opends/src/server/org/opends/server/messages/ToolMessages.java b/opends/src/server/org/opends/server/messages/ToolMessages.java
index 615a0b2..a59cc29 100644
--- a/opends/src/server/org/opends/server/messages/ToolMessages.java
+++ b/opends/src/server/org/opends/server/messages/ToolMessages.java
@@ -9181,6 +9181,13 @@
   public static final int MSGID_CLI_HEADING_PROPERTY_DEFAULT_VALUE =
     CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 1215;
 
+<<<<<<< .mine
+  /**
+   * Message ID for reverter tool's directory option.
+   */
+  public static final int MSGID_REVERT_DESCRIPTION_DIRECTORY =
+          CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 1216;
+=======
   /**
    * The message ID for the message that will be used as the
    * description of the advanced mode argument in get-xxx-prop
@@ -9189,8 +9196,29 @@
    */
   public static final int MSGID_DSCFG_DESCRIPTION_ADVANCED_GET =
        CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 1216;
+>>>>>>> .r2457
 
   /**
+<<<<<<< .mine
+   * Message ID for reverter tool's directory option.
+   */
+  public static final int MSGID_REVERT_DESCRIPTION_RECENT =
+          CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 1217;
+
+  /**
+   * Message ID for reverter tool's directory option.
+   */
+  public static final int MSGID_REVERT_DESCRIPTION_INTERACTIVE =
+          CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 1218;
+
+  /**
+   * Message ID for reverter tool's directory option.
+   */
+  public static final int MSGID_REVERT_DESCRIPTION_SILENT =
+          CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 1219;
+
+  /**
+=======
    * The message ID for the message that will be used as the
    * description of the advanced mode argument in create-xxx and
    * set-xxx-prop sub-commands. This takes no arguments.
@@ -9208,6 +9236,7 @@
 
 
   /**
+>>>>>>> .r2457
    * Associates a set of generic messages with the message IDs defined in this
    * class.
    */
@@ -12181,6 +12210,18 @@
                     "invalid");
     registerMessage(MSGID_CLI_HEADING_PROPERTY_DEFAULT_VALUE,
                     "Default value");
+    registerMessage(MSGID_REVERT_DESCRIPTION_DIRECTORY,
+                    "Directory where reversion files are stored.  This " +
+                    "should be one of the child directories of the 'history' " +
+                    "directory that is created when the upgrade tool is run");
+    registerMessage(MSGID_REVERT_DESCRIPTION_RECENT,
+                    "Indicates that the installation will be reverted to the " +
+                    "state before the most recent upgrade");
+    registerMessage(MSGID_REVERT_DESCRIPTION_INTERACTIVE,
+                    "Prompt for any required information rather than fail");
+    registerMessage(MSGID_REVERT_DESCRIPTION_SILENT,
+                    "Perform a silent reversion");
+
   }
 }
 

--
Gitblit v1.10.0