From 6df6635f1250c399a2f39d87d0534301ce4c22d7 Mon Sep 17 00:00:00 2001
From: kenneth_suter <kenneth_suter@localhost>
Date: Fri, 31 Aug 2007 15:43:58 +0000
Subject: [PATCH] Exposes the reversion functionality of the upgrader (issue 2169).  Originally it was intended to be exposed as a new script but in order to avoid the negativity of having a command devoted to undoing the upgrade and to avoid more scripts in the top-level directory, I've exposed the functionality as 2 new options in the existing upgrade script.  I will update the Wiki with documentation for these new options soon.

---
 opends/src/quicksetup/org/opends/quicksetup/ReturnCode.java                           |  139 +++
 opends/src/quicksetup/org/opends/quicksetup/upgrader/ReversionProgressStep.java       |    6 
 opends/src/quicksetup/org/opends/quicksetup/CliApplication.java                       |    6 
 opends/src/quicksetup/org/opends/quicksetup/upgrader/UpgradeIssueNotifier.java        |    8 
 opends/src/quicksetup/org/opends/quicksetup/installer/offline/OfflineInstaller.java   |    6 
 opends/src/guitools/org/opends/guitools/uninstaller/ui/LoginDialog.java               |    2 
 opends/src/quicksetup/org/opends/quicksetup/upgrader/BuildExtractor.java              |  118 ++
 opends/src/quicksetup/org/opends/quicksetup/installer/webstart/WebStartInstaller.java |   12 
 opends/src/quicksetup/org/opends/quicksetup/BuildInformation.java                     |    4 
 opends/src/quicksetup/org/opends/quicksetup/installer/Installer.java                  |   48 
 opends/src/quicksetup/org/opends/quicksetup/QuickSetupCli.java                        |   39 
 opends/src/quicksetup/org/opends/quicksetup/ui/GuiApplication.java                    |    4 
 opends/src/quicksetup/org/opends/quicksetup/installer/InstallerHelper.java            |   20 
 opends/src/quicksetup/org/opends/quicksetup/CliApplicationHelper.java                 |   46 +
 opends/src/quicksetup/org/opends/quicksetup/upgrader/BuildExtractorCliHelper.java     |   72 +
 opends/src/quicksetup/org/opends/quicksetup/upgrader/MigrationManager.java            |   10 
 opends/resource/upgrade.bat                                                           |   17 
 opends/src/quicksetup/org/opends/quicksetup/util/ZipExtractor.java                    |    6 
 opends/src/quicksetup/org/opends/quicksetup/upgrader/UpgradeLauncher.java             |  203 ++++
 opends/src/quicksetup/org/opends/quicksetup/ui/GuiUserInteraction.java                |   12 
 opends/src/quicksetup/org/opends/quicksetup/upgrader/ReversionIssueNotifier.java      |  232 ++++++
 opends/src/messages/messages/quicksetup.properties                                    |   53 +
 opends/src/messages/messages/tools.properties                                         |    5 
 opends/src/quicksetup/org/opends/quicksetup/Installation.java                         |   10 
 opends/src/quicksetup/org/opends/quicksetup/upgrader/ReversionLauncher.java           |  147 ---
 opends/src/quicksetup/org/opends/quicksetup/upgrader/ReverterUserData.java            |   30 
 opends/src/quicksetup/org/opends/quicksetup/UserData.java                             |    3 
 opends/src/quicksetup/org/opends/quicksetup/util/InProcessServerController.java       |   33 
 opends/src/quicksetup/org/opends/quicksetup/util/ServerController.java                |   12 
 /dev/null                                                                             |  143 ---
 opends/resource/upgrade                                                               |   33 
 opends/src/quicksetup/org/opends/quicksetup/upgrader/UpgradeUserData.java             |   25 
 opends/src/quicksetup/org/opends/quicksetup/upgrader/Reverter.java                    |  469 +++++++++--
 opends/src/quicksetup/org/opends/quicksetup/util/ServerHealthChecker.java             |    4 
 opends/src/quicksetup/org/opends/quicksetup/ApplicationException.java                 |    1 
 opends/src/quicksetup/org/opends/quicksetup/Launcher.java                             |   65 +
 opends/src/guitools/org/opends/guitools/uninstaller/Uninstaller.java                  |   17 
 opends/src/quicksetup/org/opends/quicksetup/UserInteraction.java                      |    9 
 opends/src/quicksetup/org/opends/quicksetup/upgrader/UpgraderCliHelper.java           |   61 -
 opends/src/quicksetup/org/opends/quicksetup/util/FileManager.java                     |   10 
 opends/src/guitools/org/opends/guitools/uninstaller/UninstallGuiLauncher.java         |    7 
 opends/src/quicksetup/org/opends/quicksetup/webstart/WebStartDownloader.java          |   10 
 opends/src/quicksetup/org/opends/quicksetup/CliUserInteraction.java                   |    9 
 opends/src/quicksetup/org/opends/quicksetup/upgrader/Upgrader.java                    |   64 
 opends/src/quicksetup/org/opends/quicksetup/Application.java                          |    5 
 45 files changed, 1,530 insertions(+), 705 deletions(-)

diff --git a/opends/resource/revert b/opends/resource/revert
deleted file mode 100755
index 50b440d..0000000
--- a/opends/resource/revert
+++ /dev/null
@@ -1,155 +0,0 @@
-#!/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/resource/upgrade b/opends/resource/upgrade
index 90e2792..a0d072f 100644
--- a/opends/resource/upgrade
+++ b/opends/resource/upgrade
@@ -135,9 +135,16 @@
   CLASSPATH=${CLASSPATH}:${JAR}
 done
 export CLASSPATH
+
+# Run the build extractor first.  An exit code of 99 from the extractor
+# means that this is indeed an upgrade (as opposed to a reversion) and
+# that the upgrade should continue.  An exit code of 98 means that this
+# operation is a reversion.  An exit code of 50 means that the usage
+# statement was printed and there is nothing else to do
+
 "${JAVA_BIN}" org.opends.quicksetup.upgrader.BuildExtractor "${@}"
 RETURN_CODE=$?
-if test ${RETURN_CODE} -eq 0
+if test ${RETURN_CODE} -eq 99
 then
   # Configure the appropriate CLASSPATH.
   # Unlike BuildExtractor, the Upgrader uses
@@ -149,10 +156,34 @@
   done
   # Launch the upgrade process.
   "${JAVA_BIN}" org.opends.quicksetup.upgrader.UpgradeLauncher "${@}"
+elif test ${RETURN_CODE} -eq 98
+then
+  # 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}" org.opends.quicksetup.upgrader.ReversionLauncher "${@}"
+  fi
 elif test ${RETURN_CODE} -eq 50
 then
   # Version info was on requested
   exit 0
+elif test ${RETURN_CODE} -eq 0
+then
+  # Usage printed
+  exit 0
 else
+  # Some unknown return code returned
   exit 101
 fi
diff --git a/opends/resource/upgrade.bat b/opends/resource/upgrade.bat
index d5dd67a..2eec34b 100644
--- a/opends/resource/upgrade.bat
+++ b/opends/resource/upgrade.bat
@@ -70,9 +70,11 @@
 FOR %%x in ("%INSTANCE_ROOT%\lib\*.jar") DO call "%INSTANCE_ROOT%\lib\setcp.bat" %%x
 set CLASSPATH=%DIR_HOME%\classes;%CLASSPATH%
 "%JAVA_BIN%" org.opends.quicksetup.upgrader.BuildExtractor %*
+if %errorlevel% == 99 goto upgrader
+if %errorlevel% == 98 goto reverter
 if %errorlevel% == 50 goto version
-if not %errorlevel% == 0 goto end
-goto upgrader
+if %errorlevel% == 0 goto end
+goto error
 
 :upgrader
 set CLASSPATH=""
@@ -80,8 +82,19 @@
 "%JAVA_BIN%" org.opends.quicksetup.upgrader.UpgradeLauncher %*
 goto end
 
+:reverter
+if EXIST "%INSTANCE_ROOT%\tmp\revert" rd "%INSTANCE_ROOT%\tmp\revert" /s /q
+xcopy "%INSTANCE_ROOT%\lib\*.*" "%INSTANCE_ROOT%\tmp\revert" /E /D /Y
+set CLASSPATH=""
+FOR %%x in ("%INSTANCE_ROOT%\tmp\revert\lib\*.jar") DO call "%INSTANCE_ROOT%\lib\setcp.bat" %%x
+"%JAVA_BIN%" org.opends.quicksetup.upgrader.ReversionLauncher %*
+goto end
+
 :version
 rem version information was requested. Return code should be 0.
 exit /B 0
 
+:error
+exit /B 101
+
 :end
diff --git a/opends/src/guitools/org/opends/guitools/uninstaller/UninstallGuiLauncher.java b/opends/src/guitools/org/opends/guitools/uninstaller/UninstallGuiLauncher.java
index ed9839a..5d3fe73 100644
--- a/opends/src/guitools/org/opends/guitools/uninstaller/UninstallGuiLauncher.java
+++ b/opends/src/guitools/org/opends/guitools/uninstaller/UninstallGuiLauncher.java
@@ -34,7 +34,7 @@
 import java.io.File;
 import java.util.logging.Logger;
 
-import org.opends.quicksetup.ApplicationReturnCode;
+import org.opends.quicksetup.ReturnCode;
 import org.opends.quicksetup.Installation;
 import org.opends.quicksetup.QuickSetupLog;
 import org.opends.quicksetup.util.Utils;
@@ -136,15 +136,14 @@
       {
         printVersion();
       }
-      System.exit(ApplicationReturnCode.ReturnCode.PRINT_VERSION
-          .getReturnCode());
+      System.exit(ReturnCode.PRINT_VERSION.getReturnCode());
     }
     else if (shouldPrintUsage()) {
       if (!argParser.usageOrVersionDisplayed())
       {
         printUsage(false);
       }
-      System.exit(ApplicationReturnCode.ReturnCode.SUCCESSFUL.getReturnCode());
+      System.exit(ReturnCode.SUCCESSFUL.getReturnCode());
     } else {
       willLaunchGui();
       int exitCode = launchGui(args);
diff --git a/opends/src/guitools/org/opends/guitools/uninstaller/Uninstaller.java b/opends/src/guitools/org/opends/guitools/uninstaller/Uninstaller.java
index cb7cf07..b27b742 100644
--- a/opends/src/guitools/org/opends/guitools/uninstaller/Uninstaller.java
+++ b/opends/src/guitools/org/opends/guitools/uninstaller/Uninstaller.java
@@ -592,6 +592,13 @@
   }
 
   /**
+   * {@inheritDoc}
+   */
+  public ReturnCode getReturnCode() {
+    return null;
+  }
+
+  /**
    * Initialize the different map used in this class.
    */
   private void initMaps() {
@@ -828,7 +835,7 @@
     }
     catch (Throwable t) {
       ue = new ApplicationException(
-              ApplicationReturnCode.ReturnCode.BUG,
+              ReturnCode.BUG,
               getThrowableMsg(INFO_BUG_MSG.get(), t), t);
       status = UninstallProgressStep.FINISHED_WITH_ERROR;
       Message msg = getFormattedError(ue, true);
@@ -1137,7 +1144,7 @@
         errMsg = INFO_ERROR_DELETING_DIRECTORY.get(file.getAbsolutePath());
       }
       throw new ApplicationException(
-          ApplicationReturnCode.ReturnCode.FILE_SYSTEM_ACCESS_ERROR,
+          ReturnCode.FILE_SYSTEM_ACCESS_ERROR,
           errMsg, null);
     }
 
@@ -1250,7 +1257,7 @@
         break;
       default:
         throw new ApplicationException(
-            ApplicationReturnCode.ReturnCode.WINDOWS_SERVICE_ERROR,
+            ReturnCode.WINDOWS_SERVICE_ERROR,
                 errorMessage, null);
     }
   }
@@ -1869,7 +1876,7 @@
       Message errorMessage = INFO_ERROR_CONFIGURING_REMOTE_GENERIC.get(
               serverDisplay, t.toString());
       throw new ApplicationException(
-          ApplicationReturnCode.ReturnCode.CONFIGURATION_ERROR, errorMessage,
+          ReturnCode.CONFIGURATION_ERROR, errorMessage,
           t);
     }
     ADSContext adsContext = new ADSContext(ctx);
@@ -1887,7 +1894,7 @@
         ADSContextException.ErrorType.NOT_YET_REGISTERED)
       {
         throw new ApplicationException(
-            ApplicationReturnCode.ReturnCode.CONFIGURATION_ERROR,
+            ReturnCode.CONFIGURATION_ERROR,
             INFO_REMOTE_ADS_EXCEPTION.get(
                     serverDisplay, ace.toString()), ace);
       }
diff --git a/opends/src/guitools/org/opends/guitools/uninstaller/ui/LoginDialog.java b/opends/src/guitools/org/opends/guitools/uninstaller/ui/LoginDialog.java
index a79d6bb..f5faa55 100644
--- a/opends/src/guitools/org/opends/guitools/uninstaller/ui/LoginDialog.java
+++ b/opends/src/guitools/org/opends/guitools/uninstaller/ui/LoginDialog.java
@@ -59,7 +59,7 @@
 import org.opends.quicksetup.Step;
 import org.opends.quicksetup.UserData;
 import org.opends.quicksetup.UserDataCertificateException;
-import org.opends.quicksetup.ApplicationReturnCode.ReturnCode;
+import org.opends.quicksetup.ReturnCode;
 import org.opends.quicksetup.event.MinimumSizeComponentListener;
 import org.opends.quicksetup.ui.CertificateDialog;
 import org.opends.quicksetup.ui.UIFactory;
diff --git a/opends/src/messages/messages/quicksetup.properties b/opends/src/messages/messages/quicksetup.properties
index e1c8552..107dbc5 100644
--- a/opends/src/messages/messages/quicksetup.properties
+++ b/opends/src/messages/messages/quicksetup.properties
@@ -315,6 +315,8 @@
 INFO_ERROR_DETERMINING_SERVER_STATE=Failed to determine the server's state.
 INFO_ERROR_DETERMINING_SVN_REV=Error determining installation's Subversion \
  revision number.
+INFO_ERROR_DETERMINING_REVERSION_BUILD=Error determining upgrade build \
+ information.
 INFO_ERROR_DETERMINING_UPGRADE_BUILD=Error determining upgrade build \
  information.
 INFO_ERROR_DISABLING_WINDOWS_SERVICE=Error Disabling Windows service.  Try to \
@@ -364,7 +366,9 @@
 INFO_ERROR_LOGGING_OPERATION=Error writting operation details to log.
 INFO_ERROR_OPTION_REQUIRED=Option %s is required.
 INFO_ERROR_OPTION_REQUIRED_OR_INTERACTIVE=Option %s is required when invoking \
- this command in non-interactive mode.  See the usage statement.
+ this command in non-prompting mode.  See the usage statement.
+INFO_ERROR_OPTIONS_REQUIRED_OR_INTERACTIVE=Additional options are required \
+ when invoking this command in non-prompting mode.  See the usage statement.
 INFO_ERROR_PARSING_OPTIONS=Error parsing options.
 INFO_ERROR_POOLING_INITIALIZATION=Error reading the progress of the \
  initialization with contents from server %s.
@@ -452,6 +456,7 @@
 INFO_GENERAL_SEE_FOR_HISTORY=See %s for a history installation history.
 INFO_GENERAL_SERVER_STARTED=started
 INFO_GENERAL_SERVER_STOPPED=stopped
+INFO_GENERAL_UNKNOWN=Unknown
 INFO_GENERAL_UNSET=Unset
 INFO_GENERAL_UNSPECIFIED=Unspecified
 INFO_GENERAL_UNSUPPORTED=Unsupported
@@ -747,19 +752,22 @@
  supported.
 INFO_REVERT_ERROR_EMPTY_HISTORY_DIR=There are no existing backup locations \
  from prior upgrades.  The 'history' directory is empty.
-INFO_REVERT_ERROR_INVALID_FILES_DIR=The upgrade backup directory does not \
+INFO_REVERT_ERROR_INVALID_FILES_DIR=The reversion archive directory does not \
  appear to contain files backed up from an invocation of the upgrade tool.
-INFO_REVERT_ERROR_NO_DIR=ERROR:  No reversion directory specified.  You must \
- specify one of %s
+INFO_REVERT_ERROR_NO_DIR=ERROR:  No reversion archive directory specified.  \
+ You must specify one of %s
 INFO_REVERT_ERROR_NO_HISTORY_DIR=There are no existing backup locations from \
  prior upgrades.  The 'history' directory does not exist.
-INFO_REVERT_ERROR_NOT_DIR_FILES_DIR=The upgrade backup directory is not a \
+INFO_REVERT_ERROR_NOT_DIR_FILES_DIR=The reversion archive directory is not a \
  directory.
-INFO_REVERT_ERROR_NULL_FILES_DIR=The upgrade backup directory is invalid or \
+INFO_REVERT_ERROR_NULL_FILES_DIR=The reversion archive directory is invalid or \
  could not be determined.
 INFO_REVERT_LAUNCHER_USAGE_DESCRIPTION=This utility reverts the current \
  installation of the Directory Server to a version prior to running the \
  upgrade utility.
+INFO_REVERT_CONFIRM_TITLE=Confirm Reversion
+INFO_REVERT_CONFIRM_PROMPT=This installation will be reverted to version \
+ %s using the files in %s.
 INFO_REVIEW_CREATE_BASE_ENTRY_LABEL=Only Create Base Entry (%s)
 INFO_REVIEW_CREATE_SUFFIX=Create New Base DN %s.Base DN Data: %s
 INFO_REVIEW_IMPORT_AUTOMATICALLY_GENERATED=Import Automatically-Generated \
@@ -1028,6 +1036,12 @@
 INFO_UPGRADE_CHOOSE_VERSION_REMOTE_WEEKLY=Weekly Builds
 INFO_UPGRADE_CHOOSE_VERSION_UNABLE_TO_ACCESS_BUILD_INFO=Unable to access \
  remote build information.
+INFO_UPGRADE_OPERATION_PROMPT=Would you like to upgrade this installation to \
+  a newer version or revert to an older version?
+INFO_UPGRADE_OPERATION_REVERSION=Revert to a previous version
+INFO_UPGRADE_OPERATION_UPGRADE=Upgrade to a newer version
+INFO_UPGRADE_OPERATION_REVERSION_RESPONSE=Please rerun this command specifying \
+  options that indicate a reversion operation.  See the usage guide for details.  
 INFO_UPGRADE_FILE_PROMPT=Enter the name and path of the OpenDS install file \
  (.zip):
 INFO_UPGRADE_LAUNCHER_DESCRIPTION=This utility may be used to upgrade the \
@@ -1040,10 +1054,16 @@
 INFO_UPGRADE_LAUNCHER_LAUNCHING_CLI=Launching command line upgrade...
 INFO_UPGRADE_LAUNCHER_LAUNCHING_GUI=Launching graphical upgrade...
 INFO_UPGRADE_LAUNCHER_USAGE_DESCRIPTION=This utility may be used to upgrade \
- the Directory Server to a newer version.  Use of this tool assumes that you \
- have already downloaded an OpenDS install package (.zip) file.  You can also \
- upgrade your server using the Java Web Start version of this tool by visiting \
- the OpenDS web site at www.opends.org.
+ the Directory Server to a newer version or revert to a previous version.%n%n\
+ When using this tool to upgrade OpenDS you should first downloaded an OpenDS \
+ install package (.zip) file and specify its location using the -f/--file \
+ option.  You can also upgrade your server using the Java \
+ Web Start version of this tool by visiting the OpenDS web site at \
+ www.opends.org.%n%n\
+ When using the tool to revert to a previous version you must either indicate \
+ that you want to revert to version before the most recent upgrade using the \
+ -r/--revertMostRecent option or specify the location of a reversion archive \
+ using the -a/--reversionArchive option.%n
 INFO_UPGRADE_LOCATION_LABEL=Server to Upgrade:
 INFO_UPGRADE_LOCATION_TOOLTIP=File system location of the build that will be \
  upgraded
@@ -1061,6 +1081,19 @@
 INFO_UPGRADE_MOD_IGNORE=Attribute or value already exists: %s
 INFO_UPGRADE_MOD_NO_SCHEMA=Processed server modifications (schema checking \
  disabled): %s
+INFO_REVERSION_ORACLE_WARNING=Reversion warning
+INFO_REVERSION_ORACLE_ACTION=Upgrade requires manual action
+INFO_REVERSION_ORACLE_INFO=Upgrade information
+INFO_REVERSION_ORACLE_UNSUPPORTED=Upgrade not supportedfrom version %s to \
+ version %s is not supported.  To upgrade You must uninstall the current \
+ server, install the new server, and manually migrate your data.
+INFO_REVERSION_TYPE_PROMPT=How would you like to specify the archive used \
+ to revert this instance?
+INFO_REVERSION_TYPE_PROMPT_RECENT=Use the most recent versioned archive
+INFO_REVERSION_TYPE_PROMPT_FILE=Manually specify a reversion archive directory
+INFO_REVERSION_DIR_PROMPT=Select a reversion archive directory:
+INFO_REVERSION_DIR_WAIT=Initializing archives...
+INFO_REVERSION_DIR_FROM_UPGRADE=%s archived on %s
 INFO_UPGRADE_ORACLE_ACTION=Upgrade requires manual action
 INFO_UPGRADE_ORACLE_INFO=Upgrade information
 INFO_UPGRADE_ORACLE_SUCCESS=Upgrade from version %s to version %s is \
diff --git a/opends/src/messages/messages/tools.properties b/opends/src/messages/messages/tools.properties
index ae5f24b..c6df939 100644
--- a/opends/src/messages/messages/tools.properties
+++ b/opends/src/messages/messages/tools.properties
@@ -1808,7 +1808,7 @@
  line version of this tool
 INFO_UPGRADE_DESCRIPTION_NO_PROMPT_1191=Use non-interactive mode.  Prompt for \
  any required information rather than fail
-INFO_UPGRADE_DESCRIPTION_SILENT_1192=Perform a quiet upgrade
+INFO_UPGRADE_DESCRIPTION_SILENT_1192=Perform a quiet upgrade or reversion
 INFO_LDIFIMPORT_DESCRIPTION_COUNT_REJECTS_1195=Count the number of entries \
  rejected by the server and return that value as the exit code (values > 255 \
  will be reduced to 255 due to exit code restrictions)
@@ -2007,3 +2007,6 @@
  passed to the JVM when running the server
 SEVERE_ERR_CREATERC_JAVA_HOME_DOESNT_EXIST_1378=The directory %s specified \
  as the JAVA_HOME path does not exist or is not a directory
+SEVERE_ERR_UPGRADE_INCOMPATIBLE_ARGS_1379=The argument '%s' is incompatible \
+ with '%s'
+
diff --git a/opends/src/quicksetup/org/opends/quicksetup/Application.java b/opends/src/quicksetup/org/opends/quicksetup/Application.java
index ee0d598..47e7733 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/Application.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/Application.java
@@ -605,7 +605,8 @@
   public UserInteraction userInteraction() {
     // Note:  overridden in GuiApplication
     UserInteraction ui = null;
-    if (!getUserData().isQuiet()) {
+    UserData ud = getUserData();
+    if (ud != null && ud.isInteractive()) {
       ui = new CliUserInteraction();
     }
     return ui;
@@ -721,7 +722,7 @@
       Message errorMessage = INFO_CANNOT_CONNECT_TO_REMOTE_GENERIC.get(
           server.getHostPort(true), ne.toString(true));
       throw new ApplicationException(
-          ApplicationReturnCode.ReturnCode.CONFIGURATION_ERROR, errorMessage,
+          ReturnCode.CONFIGURATION_ERROR, errorMessage,
           ne);
     }
     return ctx;
diff --git a/opends/src/quicksetup/org/opends/quicksetup/ApplicationException.java b/opends/src/quicksetup/org/opends/quicksetup/ApplicationException.java
index 63b1832..e683b7b 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/ApplicationException.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/ApplicationException.java
@@ -29,7 +29,6 @@
 import org.opends.messages.Message;
 
 import org.opends.server.types.OpenDsException;
-import static org.opends.quicksetup.ApplicationReturnCode.ReturnCode;
 
 /**
  * This exception is used to encapsulate all the error that we might have
diff --git a/opends/src/quicksetup/org/opends/quicksetup/ApplicationReturnCode.java b/opends/src/quicksetup/org/opends/quicksetup/ApplicationReturnCode.java
deleted file mode 100644
index 10fe956..0000000
--- a/opends/src/quicksetup/org/opends/quicksetup/ApplicationReturnCode.java
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * 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;
-
-/**
- * This class defines enumeration of application return code.
- */
-public final class ApplicationReturnCode
-{
-  /**
-   * Enumeration defining return code.
-   */
-  public enum ReturnCode
-  {
-    /**
-     * Return code: Application successful.
-     */
-    SUCCESSFUL(0),
-
-    /**
-     * Return code: User Cancelled uninstall.
-     */
-    CANCELLED(0),
-
-    /**
-     * Return code: User provided invalid data.
-     */
-    USER_DATA_ERROR(2),
-
-    /**
-     * Return code: Error accessing file system (reading/writing).
-     */
-    FILE_SYSTEM_ACCESS_ERROR(3),
-
-    /**
-     * Error downloading jar files from web start server.  This is specific
-     * to the web start installation.
-     */
-    DOWNLOAD_ERROR(4),
-    /**
-     * Error during the configuration of the Directory Server.
-     */
-    CONFIGURATION_ERROR(5),
-    /**
-     * Error during the import of data (base entry, from LDIF file or
-     * automatically generated data).
-     */
-    IMPORT_ERROR(6),
-    /**
-     * Error starting the Open DS server.
-     */
-    START_ERROR(7),
-
-    /**
-     * Error stopping the Open DS server.
-     */
-    STOP_ERROR(8),
-
-    /**
-     * Error enabling the Windows service.
-     */
-    WINDOWS_SERVICE_ERROR(9),
-
-    /**
-     * Application specific error.
-     */
-    APPLICATION_ERROR(10),
-
-    /**
-     * Error invoking an OpenDS tool.
-     */
-    TOOL_ERROR(11),
-
-    /**
-     * Return code: Bug.
-     */
-    BUG(12),
-    /**
-     * Return code: Bug.
-     */
-    PRINT_VERSION(50),
-
-    /**
-     * Return code for errors that are non-specified.
-     */
-    UNKNOWN(100);
-
-    private int returnCode;
-
-    /**
-     * Private constructor.
-     *
-     * @param returnCode
-     *          the return code.
-     */
-    private ReturnCode(int returnCode)
-    {
-      this.returnCode = returnCode;
-    }
-
-    /**
-     * Returns the return code.
-     *
-     * @return the return code.
-     */
-    public int getReturnCode()
-    {
-      return returnCode;
-    }
-  }
-
-  /**
-   * Private constructor.
-   */
-  private ApplicationReturnCode()
-  {
-  }
-}
diff --git a/opends/src/quicksetup/org/opends/quicksetup/BuildInformation.java b/opends/src/quicksetup/org/opends/quicksetup/BuildInformation.java
index c079645..6cb72b5 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/BuildInformation.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/BuildInformation.java
@@ -115,7 +115,7 @@
       }
     } catch (IOException e) {
       throw new ApplicationException(
-          ApplicationReturnCode.ReturnCode.START_ERROR,
+          ReturnCode.START_ERROR,
           INFO_ERROR_CREATING_BUILD_INFO.get(), e);
     } finally {
       if (is != null) {
@@ -389,7 +389,7 @@
     for (String prop : props) {
       if (null == values.get(prop)) {
         throw new ApplicationException(
-                ApplicationReturnCode.ReturnCode.TOOL_ERROR,
+                ReturnCode.TOOL_ERROR,
                 INFO_ERROR_PROP_VALUE.get(prop), null);
       }
     }
diff --git a/opends/src/quicksetup/org/opends/quicksetup/CliApplication.java b/opends/src/quicksetup/org/opends/quicksetup/CliApplication.java
index 441326e..7e62339 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/CliApplication.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/CliApplication.java
@@ -72,4 +72,10 @@
    */
   ApplicationException getRunError();
 
+  /**
+   * Gets the return code to return to the console.
+   * @return return code to return;  if null the return code indicated in the
+   *         error returned by <code>getRunError</code> will be used.
+   */
+  ReturnCode getReturnCode();
 }
diff --git a/opends/src/quicksetup/org/opends/quicksetup/CliApplicationHelper.java b/opends/src/quicksetup/org/opends/quicksetup/CliApplicationHelper.java
index 3061c6e..3e83a4b 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/CliApplicationHelper.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/CliApplicationHelper.java
@@ -52,6 +52,7 @@
 import java.security.cert.X509Certificate;
 import java.util.Set;
 import java.util.ArrayList;
+import java.util.List;
 import java.util.logging.Logger;
 import java.util.logging.Level;
 
@@ -154,6 +155,47 @@
   }
 
   /**
+   * Interactively prompts (on standard output) the user to provide select
+   * one option from a set of options.
+   *
+   * @param  prompt        The prompt to present to the user.
+   * @param  defaultOption The default value returned if the user clicks enter.
+   * @param  options       The valid values that can be accepted as user input.
+   *
+   * @return index of options that was chosen or -1 if none where chosen
+   */
+  public int promptOptions(Message prompt,
+                           Message defaultOption,
+                           Message[] options) {
+    Message choiceDefault = null;
+    List<Message> choiceList = new ArrayList<Message>();
+    MessageBuilder mb = new MessageBuilder(prompt);
+    for (int i = 0; i < options.length; i++) {
+      Message choice = Message.raw(Integer.toString(i + 1));
+      choiceList.add(choice);
+      if (options[i].equals(defaultOption)) {
+        choiceDefault = choice;
+      }
+      mb.append("\n");
+      mb.append(choice);
+      mb.append(". ");
+      mb.append(options[i]);
+    }
+    int ret = -1;
+    Message resp = promptConfirm(mb.toMessage(), choiceDefault,
+            choiceList.toArray(new Message[0]));
+    if (resp != null) {
+      for (int i = 0; i < choiceList.size(); i++) {
+        if (resp.equals(choiceList.get(i))) {
+          ret = i;
+          break;
+        }
+      }
+    }
+    return ret;
+  }
+
+  /**
    * Interactively prompts (on standard output) the user to provide a string
    * value.  Any non-empty string will be allowed (the empty string will
    * indicate that the default should be used, if there is one).
@@ -166,7 +208,7 @@
    *
    * @return  The string value read from the user.
    */
-  protected String promptForString(Message prompt, String defaultValue) {
+  public String promptForString(Message prompt, String defaultValue) {
     String wrappedPrompt = StaticUtils.wrapText(prompt,
             Utils.getCommandLineMaxLineWidth());
 
@@ -391,6 +433,8 @@
   }
 
   /**
+<<<<<<< .mine
+=======
    * Returns <CODE>true</CODE> if this is a quiet session and
    * <CODE>false</CODE> otherwise.  This method relies on the a previous
    * call to createArgumentParser having been made and the parser
diff --git a/opends/src/quicksetup/org/opends/quicksetup/CliUserInteraction.java b/opends/src/quicksetup/org/opends/quicksetup/CliUserInteraction.java
index 57c8c77..1f0eb14 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/CliUserInteraction.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/CliUserInteraction.java
@@ -144,6 +144,15 @@
     return sb.toString();
   }
 
+  /**
+   * {@inheritDoc}
+   */
+  public String promptForString(Message prompt, Message title,
+                                String defaultValue) {
+
+    return promptForString(prompt, defaultValue);
+  }
+
   private String createOption(int index, String option) {
     return new StringBuilder().
             append(Integer.toString(index)).
diff --git a/opends/src/quicksetup/org/opends/quicksetup/Installation.java b/opends/src/quicksetup/org/opends/quicksetup/Installation.java
index 8716da8..5514825 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/Installation.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/Installation.java
@@ -170,16 +170,6 @@
   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";
diff --git a/opends/src/quicksetup/org/opends/quicksetup/Launcher.java b/opends/src/quicksetup/org/opends/quicksetup/Launcher.java
index d46f1c0..f3ad57d 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/Launcher.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/Launcher.java
@@ -100,6 +100,46 @@
   }
 
   /**
+   * Indicates whether or not the launcher should print a usage
+   * statement based on the content of the arguments passed into
+   * the constructor.
+   * @return boolean where true indicates usage should be printed
+   */
+  protected boolean isQuiet() {
+    boolean printUsage = false;
+    if ((args != null) && (args.length > 0)) {
+      for (String arg : args) {
+        if (arg.equals("-?") ||
+          arg.equalsIgnoreCase("-Q") ||
+          arg.equalsIgnoreCase("--quiet")) {
+          printUsage = true;
+        }
+      }
+    }
+    return printUsage;
+  }
+
+  /**
+   * Indicates whether or not the launcher should print a usage
+   * statement based on the content of the arguments passed into
+   * the constructor.
+   * @return boolean where true indicates usage should be printed
+   */
+  protected boolean isNoPrompt() {
+    boolean printUsage = false;
+    if ((args != null) && (args.length > 0)) {
+      for (String arg : args) {
+        if (arg.equals("-?") ||
+          arg.equalsIgnoreCase("-n") ||
+          arg.equalsIgnoreCase("--no-prompt")) {
+          printUsage = true;
+        }
+      }
+    }
+    return printUsage;
+  }
+
+  /**
    * Indicates whether or not the launcher should print a version
    * statement based on the content of the arguments passed into
    * the constructor.
@@ -249,12 +289,11 @@
   {
     System.setProperty(Constants.CLI_JAVA_PROPERTY, "true");
     QuickSetupCli cli = new QuickSetupCli(cliApp, this);
-    ApplicationReturnCode.ReturnCode returnValue = cli.run();
-    if (returnValue.equals(ApplicationReturnCode.ReturnCode.USER_DATA_ERROR))
+    ReturnCode returnValue = cli.run();
+    if (returnValue.equals(ReturnCode.USER_DATA_ERROR))
     {
       printUsage(true);
-      System.exit(ApplicationReturnCode.ReturnCode.USER_DATA_ERROR
-          .getReturnCode());
+      System.exit(ReturnCode.USER_DATA_ERROR.getReturnCode());
     }
     return returnValue.getReturnCode();
   }
@@ -317,15 +356,19 @@
    * The main method which is called by the command lines.
    */
   public void launch() {
-    if (shouldPrintVersion())
-    {
-      printVersion();
-      System.exit(ApplicationReturnCode.ReturnCode.PRINT_VERSION
-          .getReturnCode());
+    if (shouldPrintVersion()) {
+      ArgumentParser parser = getArgumentParser();
+      if (parser == null || !parser.usageOrVersionDisplayed()) {
+        printVersion();
+      }
+      System.exit(ReturnCode.PRINT_VERSION.getReturnCode());
     }
     else if (shouldPrintUsage()) {
-      printUsage(false);
-      System.exit(ApplicationReturnCode.ReturnCode.SUCCESSFUL.getReturnCode());
+      ArgumentParser parser = getArgumentParser();
+      if (parser == null || !parser.usageOrVersionDisplayed()) {
+        printUsage(false);
+      }
+      System.exit(ReturnCode.SUCCESSFUL.getReturnCode());
     } else if (isCli()) {
       CliApplication cliApp = createCliApplication();
       int exitCode = launchCli(cliApp);
diff --git a/opends/src/quicksetup/org/opends/quicksetup/QuickSetupCli.java b/opends/src/quicksetup/org/opends/quicksetup/QuickSetupCli.java
index eba7e0a..0d32f1a 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/QuickSetupCli.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/QuickSetupCli.java
@@ -30,10 +30,10 @@
 import org.opends.quicksetup.util.ProgressMessageFormatter;
 import org.opends.quicksetup.util.PlainTextProgressMessageFormatter;
 import org.opends.quicksetup.util.Utils;
-import org.opends.quicksetup.ApplicationReturnCode.ReturnCode;
 import org.opends.quicksetup.event.ProgressUpdateListener;
 import org.opends.quicksetup.event.ProgressUpdateEvent;
 import org.opends.server.util.StaticUtils;
+import org.opends.messages.Message;
 
 /**
  * This enum contains the different type of ApplicationException that we can
@@ -91,10 +91,13 @@
           cliApp.addProgressUpdateListener(
                   new ProgressUpdateListener() {
                     public void progressUpdate(ProgressUpdateEvent ev) {
-                      System.out.print(
-                              org.opends.server.util.StaticUtils.wrapText(
-                                      ev.getNewLogs(),
-                                      Utils.getCommandLineMaxLineWidth()));
+                      Message newLogs = ev.getNewLogs();
+                      if (newLogs != null) {
+                        System.out.print(
+                                StaticUtils.wrapText(
+                                        newLogs,
+                                        Utils.getCommandLineMaxLineWidth()));
+                      }
                     }
                   });
         }
@@ -107,21 +110,23 @@
             // do nothing;
           }
         }
-
-        ApplicationException ue = cliApp.getRunError();
-        if (ue != null)
-        {
-          returnValue = ue.getType();
-        }
-        else
-        {
-          returnValue = ApplicationReturnCode.ReturnCode.SUCCESSFUL;
+        returnValue = cliApp.getReturnCode();
+        if (returnValue == null) {
+          ApplicationException ue = cliApp.getRunError();
+          if (ue != null)
+          {
+            returnValue = ue.getType();
+          }
+          else
+          {
+            returnValue = ReturnCode.SUCCESSFUL;
+          }
         }
       }
-      else
-      {
+    else
+    {
         // User cancelled installation.
-        returnValue = ApplicationReturnCode.ReturnCode.CANCELLED;
+        returnValue = ReturnCode.CANCELLED;
       }
     }
     catch (UserDataException uude)
diff --git a/opends/src/quicksetup/org/opends/quicksetup/ReturnCode.java b/opends/src/quicksetup/org/opends/quicksetup/ReturnCode.java
new file mode 100644
index 0000000..346ed94
--- /dev/null
+++ b/opends/src/quicksetup/org/opends/quicksetup/ReturnCode.java
@@ -0,0 +1,139 @@
+/*
+ * 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;
+
+/**
+ * This class defines enumeration of application return code.
+ */
+public class ReturnCode {
+
+  /**
+   * Return code: Application successful.
+   */
+  public static final ReturnCode SUCCESSFUL = new ReturnCode(0);
+
+  /**
+   * Return code: User Cancelled uninstall.
+   */
+  public static final ReturnCode CANCELLED = new ReturnCode(0);
+
+  /**
+   * Return code: User provided invalid data.
+   */
+  public static final ReturnCode USER_DATA_ERROR = new ReturnCode(2);
+
+  /**
+   * Return code: Error accessing file system (reading/writing).
+   */
+  public static final ReturnCode FILE_SYSTEM_ACCESS_ERROR = new ReturnCode(3);
+
+  /**
+   * Error downloading jar files from web start server.  This is specific
+   * to the web start installation.
+   */
+  public static final ReturnCode DOWNLOAD_ERROR = new ReturnCode(4);
+
+  /**
+   * Error during the configuration of the Directory Server.
+   */
+  public static final ReturnCode CONFIGURATION_ERROR = new ReturnCode(5);
+
+  /**
+   * Error during the import of data (base entry, from LDIF file or
+   * automatically generated data).
+   */
+
+  public static final ReturnCode IMPORT_ERROR = new ReturnCode(6);
+
+  /**
+   * Error starting the Open DS server.
+   */
+  public static final ReturnCode START_ERROR = new ReturnCode(7);
+
+  /**
+   * Error stopping the Open DS server.
+   */
+  public static final ReturnCode STOP_ERROR = new ReturnCode(8);
+
+  /**
+   * Error enabling the Windows service.
+   */
+  public static final ReturnCode WINDOWS_SERVICE_ERROR = new ReturnCode(9);
+
+  /**
+   * Application specific error.
+   */
+  public static final ReturnCode APPLICATION_ERROR = new ReturnCode(10);
+
+  /**
+   * Error invoking an OpenDS tool.
+   */
+  public static final ReturnCode TOOL_ERROR = new ReturnCode(11);
+
+  /**
+   * Return code: Bug.
+   */
+  public static final ReturnCode BUG = new ReturnCode(12);
+
+  /**
+   * Return code: Bug.
+   */
+  public static final ReturnCode PRINT_VERSION = new ReturnCode(50);
+
+  /**
+   * Return code: Bug.
+   */
+  public static final ReturnCode PRINT_USAGE = new ReturnCode(51);
+
+  /**
+   * Return code for errors that are non-specified.
+   */
+  public static final ReturnCode UNKNOWN = new ReturnCode(100);
+
+
+  private int code;
+
+  /**
+   * Creates a new parameterized instance.
+   *
+   * @param code to return
+   */
+  public ReturnCode(int code) {
+    this.code = code;
+  }
+
+  /**
+   * Gets the return code to return to the console.
+   *
+   * @return int code
+   */
+  public int getReturnCode() {
+    return code;
+  }
+
+}
diff --git a/opends/src/quicksetup/org/opends/quicksetup/UserData.java b/opends/src/quicksetup/org/opends/quicksetup/UserData.java
index 3dcada9..1afa23a 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/UserData.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/UserData.java
@@ -91,6 +91,7 @@
    * Creates a user data object with default values.
    */
   public UserData() {
+    interactive = true;
     startServer = true;
     enableWindowsService = false;
     forceOnError = true;
@@ -509,7 +510,7 @@
    * @return boolean where true indicates this session should be interactive
    */
   public boolean isInteractive() {
-    return !this.quiet && this.interactive;
+    return this.interactive;
   }
 
   /**
diff --git a/opends/src/quicksetup/org/opends/quicksetup/UserInteraction.java b/opends/src/quicksetup/org/opends/quicksetup/UserInteraction.java
index 3cf0736..cb987e8 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/UserInteraction.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/UserInteraction.java
@@ -106,4 +106,13 @@
    */
   String createUnorderedList(List list);
 
+  /**
+   * Promt the user for a string.
+   * @param prompt for string
+   * @param title of prompt dialog
+   * @param defaultValue for default
+   * @return String typed by user
+   */
+  String promptForString(Message prompt, Message title, String defaultValue);
+
 }
diff --git a/opends/src/quicksetup/org/opends/quicksetup/installer/Installer.java b/opends/src/quicksetup/org/opends/quicksetup/installer/Installer.java
index e76ece4..9995e93 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/installer/Installer.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/installer/Installer.java
@@ -728,7 +728,7 @@
       Message failedMsg = getThrowableMsg(
               INFO_ERROR_CREATING_TEMP_FILE.get(), ioe);
       throw new ApplicationException(
-          ApplicationReturnCode.ReturnCode.FILE_SYSTEM_ACCESS_ERROR,
+          ReturnCode.FILE_SYSTEM_ACCESS_ERROR,
           failedMsg, ioe);
     }
   }
@@ -851,13 +851,13 @@
       if (result != 0)
       {
         throw new ApplicationException(
-            ApplicationReturnCode.ReturnCode.CONFIGURATION_ERROR,
+            ReturnCode.CONFIGURATION_ERROR,
             INFO_ERROR_CONFIGURING.get(), null);
       }
     } catch (Throwable t)
     {
       throw new ApplicationException(
-          ApplicationReturnCode.ReturnCode.CONFIGURATION_ERROR,
+          ReturnCode.CONFIGURATION_ERROR,
           getThrowableMsg(INFO_ERROR_CONFIGURING.get(), t), t);
     }
 
@@ -964,7 +964,7 @@
     catch (Throwable t)
     {
       throw new ApplicationException(
-          ApplicationReturnCode.ReturnCode.CONFIGURATION_ERROR,
+          ReturnCode.CONFIGURATION_ERROR,
           getThrowableMsg(INFO_ERROR_CONFIGURING_CERTIFICATE.get(),
                   t), t);
     }
@@ -1011,13 +1011,13 @@
       if (result != 0)
       {
         throw new ApplicationException(
-            ApplicationReturnCode.ReturnCode.CONFIGURATION_ERROR,
+            ReturnCode.CONFIGURATION_ERROR,
             INFO_ERROR_CREATING_BASE_ENTRY.get(), null);
       }
     } catch (Throwable t)
     {
       throw new ApplicationException(
-          ApplicationReturnCode.ReturnCode.CONFIGURATION_ERROR,
+          ReturnCode.CONFIGURATION_ERROR,
           getThrowableMsg(INFO_ERROR_CREATING_BASE_ENTRY.get(), t), t);
     }
     finally
@@ -1062,13 +1062,13 @@
       if (result != 0)
       {
         throw new ApplicationException(
-            ApplicationReturnCode.ReturnCode.CONFIGURATION_ERROR,
+            ReturnCode.CONFIGURATION_ERROR,
             INFO_ERROR_IMPORTING_LDIF.get(), null);
       }
     } catch (Throwable t)
     {
       throw new ApplicationException(
-          ApplicationReturnCode.ReturnCode.CONFIGURATION_ERROR,
+          ReturnCode.CONFIGURATION_ERROR,
           getThrowableMsg(INFO_ERROR_IMPORTING_LDIF.get(), t), t);
     }
   }
@@ -1112,14 +1112,14 @@
       if (result != 0)
       {
         throw new ApplicationException(
-            ApplicationReturnCode.ReturnCode.CONFIGURATION_ERROR,
+            ReturnCode.CONFIGURATION_ERROR,
             INFO_ERROR_IMPORT_LDIF_TOOL_RETURN_CODE.get(
                     Integer.toString(result)), null);
       }
     } catch (Throwable t)
     {
       throw new ApplicationException(
-          ApplicationReturnCode.ReturnCode.CONFIGURATION_ERROR,
+          ReturnCode.CONFIGURATION_ERROR,
           getThrowableMsg(INFO_ERROR_IMPORT_AUTOMATICALLY_GENERATED.get(
                   listToString(argList, " "), t.getLocalizedMessage()), t), t);
     }
@@ -1367,7 +1367,7 @@
       Message failedMsg = getThrowableMsg(
               INFO_ERROR_CONNECTING_TO_LOCAL.get(), ne);
       throw new ApplicationException(
-          ApplicationReturnCode.ReturnCode.CONFIGURATION_ERROR, failedMsg, ne);
+          ReturnCode.CONFIGURATION_ERROR, failedMsg, ne);
     }
     finally
     {
@@ -1564,7 +1564,7 @@
       setCurrentProgressStep(InstallProgressStep.CANCELING);
       notifyListeners(null);
       throw new ApplicationException(
-          ApplicationReturnCode.ReturnCode.CANCELLED,
+          ReturnCode.CANCELLED,
             INFO_UPGRADE_CANCELED.get(), null);
     }
   }
@@ -1709,7 +1709,7 @@
       {
       }
       throw new ApplicationException(
-          ApplicationReturnCode.ReturnCode.CONFIGURATION_ERROR, failedMsg, t);
+          ReturnCode.CONFIGURATION_ERROR, failedMsg, t);
     }
 
     Set<SuffixDescriptor> suffixes =
@@ -1737,7 +1737,7 @@
       catch (NamingException ne)
       {
         throw new ApplicationException(
-                ApplicationReturnCode.ReturnCode.CONFIGURATION_ERROR,
+                ReturnCode.CONFIGURATION_ERROR,
                 INFO_CANNOT_CONNECT_TO_REMOTE_GENERIC.get(
                         server.getHostPort(true),
                         ne.getLocalizedMessage()), ne);
@@ -1784,7 +1784,7 @@
           catch (NamingException ne)
           {
             throw new ApplicationException(
-                ApplicationReturnCode.ReturnCode.CONFIGURATION_ERROR,
+                ReturnCode.CONFIGURATION_ERROR,
                 INFO_CANNOT_CONNECT_TO_REMOTE_GENERIC.get(
                         server.getHostPort(true),
                         ne.getLocalizedMessage()), ne);
@@ -1820,7 +1820,7 @@
             if (nTries == 1)
             {
               throw new ApplicationException(
-                  ApplicationReturnCode.ReturnCode.APPLICATION_ERROR,
+                  ReturnCode.APPLICATION_ERROR,
                   pnfe.getMessageObject(), null);
             }
             try
@@ -1985,7 +1985,7 @@
       if (remoteServer)
       {
         throw new ApplicationException(
-                ApplicationReturnCode.ReturnCode.CONFIGURATION_ERROR,
+                ReturnCode.CONFIGURATION_ERROR,
                 INFO_CANNOT_CONNECT_TO_REMOTE_PERMISSIONS.get(
                         getHostDisplay(auth)), ne);
       }
@@ -1995,7 +1995,7 @@
         Message failedMsg = getThrowableMsg(
                 INFO_ERROR_CONNECTING_TO_LOCAL.get(), ne);
         throw new ApplicationException(
-                ApplicationReturnCode.ReturnCode.CONFIGURATION_ERROR,
+                ReturnCode.CONFIGURATION_ERROR,
                 failedMsg, ne);
       }
     }
@@ -2004,21 +2004,21 @@
       if (remoteServer)
       {
         throw new ApplicationException(
-                ApplicationReturnCode.ReturnCode.CONFIGURATION_ERROR,
+                ReturnCode.CONFIGURATION_ERROR,
                 INFO_CANNOT_CONNECT_TO_REMOTE_GENERIC.get(
                         getHostDisplay(auth), ne.getLocalizedMessage()), ne);
       }
       else
       {
         throw new ApplicationException(
-                ApplicationReturnCode.ReturnCode.CONFIGURATION_ERROR,
+                ReturnCode.CONFIGURATION_ERROR,
                 getThrowableMsg(INFO_ERROR_CONNECTING_TO_LOCAL.get(), ne), ne);
       }
     }
     catch (ADSContextException ace)
     {
       throw new ApplicationException(
-              ApplicationReturnCode.ReturnCode.CONFIGURATION_ERROR,
+              ReturnCode.CONFIGURATION_ERROR,
               ((remoteServer)
                       ? INFO_REMOTE_ADS_EXCEPTION.get(
                       getHostDisplay(auth), ace.getReason())
@@ -3669,7 +3669,7 @@
       {
         LOG.log(Level.SEVERE, "Error creating task "+attrs, ne);
         throw new ApplicationException(
-            ApplicationReturnCode.ReturnCode.APPLICATION_ERROR,
+            ReturnCode.APPLICATION_ERROR,
                 getThrowableMsg(INFO_ERROR_LAUNCHING_INITIALIZATION.get(
                         sourceServerDisplay
                 ), ne), ne);
@@ -3822,7 +3822,7 @@
               helper.isStoppedByError(state))
           {
             ApplicationException ae = new ApplicationException(
-                ApplicationReturnCode.ReturnCode.APPLICATION_ERROR, errorMsg,
+                ReturnCode.APPLICATION_ERROR, errorMsg,
                 null);
             if ((lastLogMsg == null) ||
                 helper.isPeersNotFoundError(lastLogMsg))
@@ -3851,7 +3851,7 @@
       catch (NamingException ne)
       {
         throw new ApplicationException(
-            ApplicationReturnCode.ReturnCode.APPLICATION_ERROR,
+            ReturnCode.APPLICATION_ERROR,
                 getThrowableMsg(INFO_ERROR_POOLING_INITIALIZATION.get(
                         sourceServerDisplay),
                         ne), ne);
diff --git a/opends/src/quicksetup/org/opends/quicksetup/installer/InstallerHelper.java b/opends/src/quicksetup/org/opends/quicksetup/installer/InstallerHelper.java
index fe56f11..edc2f11 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/installer/InstallerHelper.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/installer/InstallerHelper.java
@@ -40,7 +40,7 @@
 import javax.naming.ldap.InitialLdapContext;
 
 import org.opends.quicksetup.ApplicationException;
-import org.opends.quicksetup.ApplicationReturnCode;
+import org.opends.quicksetup.ReturnCode;
 import static org.opends.quicksetup.util.Utils.*;
 import org.opends.server.admin.DefaultBehaviorException;
 import org.opends.server.admin.ManagedObjectNotFoundException;
@@ -133,7 +133,7 @@
         break;
       default:
         throw new ApplicationException(
-            ApplicationReturnCode.ReturnCode.WINDOWS_SERVICE_ERROR,
+            ReturnCode.WINDOWS_SERVICE_ERROR,
                 errorMessage, null);
     }
   }
@@ -148,7 +148,7 @@
     if (code == ConfigureWindowsService.SERVICE_DISABLE_ERROR) {
       throw new ApplicationException(
           // TODO: fix this message's format string
-          ApplicationReturnCode.ReturnCode.WINDOWS_SERVICE_ERROR,
+          ReturnCode.WINDOWS_SERVICE_ERROR,
               INFO_ERROR_DISABLING_WINDOWS_SERVICE.get(""), null);
     }
   }
@@ -172,7 +172,7 @@
       Message failedMsg =
               getThrowableMsg(INFO_ERROR_CREATING_TEMP_FILE.get(), ioe);
       throw new ApplicationException(
-          ApplicationReturnCode.ReturnCode.FILE_SYSTEM_ACCESS_ERROR,
+          ReturnCode.FILE_SYSTEM_ACCESS_ERROR,
           failedMsg, ioe);
     }
 
@@ -190,19 +190,19 @@
       writer.close();
     } catch (DirectoryException de) {
       throw new ApplicationException(
-          ApplicationReturnCode.ReturnCode.CONFIGURATION_ERROR,
+          ReturnCode.CONFIGURATION_ERROR,
               getThrowableMsg(INFO_ERROR_IMPORTING_LDIF.get(), de), de);
     } catch (LDIFException le) {
       throw new ApplicationException(
-          ApplicationReturnCode.ReturnCode.CONFIGURATION_ERROR,
+          ReturnCode.CONFIGURATION_ERROR,
               getThrowableMsg(INFO_ERROR_IMPORTING_LDIF.get(), le), le);
     } catch (IOException ioe) {
       throw new ApplicationException(
-          ApplicationReturnCode.ReturnCode.CONFIGURATION_ERROR,
+          ReturnCode.CONFIGURATION_ERROR,
               getThrowableMsg(INFO_ERROR_IMPORTING_LDIF.get(), ioe), ioe);
     } catch (Throwable t) {
       throw new ApplicationException(
-          ApplicationReturnCode.ReturnCode.BUG, getThrowableMsg(
+          ReturnCode.BUG, getThrowableMsg(
               INFO_BUG_MSG.get(), t), t);
     }
     return ldifFile;
@@ -398,7 +398,7 @@
       Message errorMessage = INFO_ERROR_CONFIGURING_REMOTE_GENERIC.get(
               serverDisplay, t.toString());
       throw new ApplicationException(
-          ApplicationReturnCode.ReturnCode.CONFIGURATION_ERROR, errorMessage,
+          ReturnCode.CONFIGURATION_ERROR, errorMessage,
           t);
     }
   }
@@ -502,7 +502,7 @@
       Message errorMessage = INFO_ERROR_CONFIGURING_REMOTE_GENERIC.get(
               serverDisplay, t.toString());
       throw new ApplicationException(
-          ApplicationReturnCode.ReturnCode.CONFIGURATION_ERROR, errorMessage,
+          ReturnCode.CONFIGURATION_ERROR, errorMessage,
           t);
     }
   }
diff --git a/opends/src/quicksetup/org/opends/quicksetup/installer/offline/OfflineInstaller.java b/opends/src/quicksetup/org/opends/quicksetup/installer/offline/OfflineInstaller.java
index 29a7d85..0570855 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/installer/offline/OfflineInstaller.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/installer/offline/OfflineInstaller.java
@@ -39,7 +39,7 @@
 import java.security.KeyStoreException;
 
 import org.opends.quicksetup.ApplicationException;
-import org.opends.quicksetup.ApplicationReturnCode;
+import org.opends.quicksetup.ReturnCode;
 import org.opends.quicksetup.ProgressStep;
 import org.opends.quicksetup.Installation;
 import org.opends.quicksetup.SecurityOptions;
@@ -159,7 +159,7 @@
 
     } catch (ApplicationException ex)
     {
-      if (ApplicationReturnCode.ReturnCode.CANCELLED.equals(ex.getType())) {
+      if (ReturnCode.CANCELLED.equals(ex.getType())) {
         uninstall();
         setCurrentProgressStep(InstallProgressStep.FINISHED_CANCELED);
         notifyListeners(null);
@@ -198,7 +198,7 @@
       updateSummaryWithServerState(hmSummary);
       setCurrentProgressStep(InstallProgressStep.FINISHED_WITH_ERROR);
       ApplicationException ex = new ApplicationException(
-          ApplicationReturnCode.ReturnCode.BUG,
+          ReturnCode.BUG,
           Utils.getThrowableMsg(INFO_BUG_MSG.get(), t), t);
       Message msg = getFormattedError(ex, true);
       notifyListeners(msg);
diff --git a/opends/src/quicksetup/org/opends/quicksetup/installer/webstart/WebStartInstaller.java b/opends/src/quicksetup/org/opends/quicksetup/installer/webstart/WebStartInstaller.java
index b9b2d38..2a34f8a 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/installer/webstart/WebStartInstaller.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/installer/webstart/WebStartInstaller.java
@@ -37,7 +37,7 @@
 import java.util.logging.Logger;
 
 import org.opends.quicksetup.ApplicationException;
-import org.opends.quicksetup.ApplicationReturnCode;
+import org.opends.quicksetup.ReturnCode;
 import org.opends.quicksetup.ProgressStep;
 import org.opends.quicksetup.Installation;
 import org.opends.quicksetup.installer.Installer;
@@ -211,7 +211,7 @@
 
     } catch (ApplicationException ex)
     {
-      if (ApplicationReturnCode.ReturnCode.CANCELLED.equals(ex.getType())) {
+      if (ReturnCode.CANCELLED.equals(ex.getType())) {
         uninstall();
         setCurrentProgressStep(InstallProgressStep.FINISHED_CANCELED);
         notifyListeners(null);
@@ -250,7 +250,7 @@
       updateSummaryWithServerState(hmSummary);
       setCurrentProgressStep(InstallProgressStep.FINISHED_WITH_ERROR);
       ApplicationException ex = new ApplicationException(
-          ApplicationReturnCode.ReturnCode.BUG,
+          ReturnCode.BUG,
           Utils.getThrowableMsg(INFO_BUG_MSG.get(), t), t);
       Message msg = getFormattedError(ex, true);
       notifyListeners(msg);
@@ -407,7 +407,7 @@
     if (in == null)
     {
       throw new ApplicationException(
-          ApplicationReturnCode.ReturnCode.DOWNLOAD_ERROR,
+          ReturnCode.DOWNLOAD_ERROR,
               INFO_ERROR_ZIPINPUTSTREAMNULL.get(zipName), null);
     }
 
@@ -431,14 +431,14 @@
         if (!Utils.createDirectory(parent))
         {
           throw new ApplicationException(
-              ApplicationReturnCode.ReturnCode.FILE_SYSTEM_ACCESS_ERROR,
+              ReturnCode.FILE_SYSTEM_ACCESS_ERROR,
               INFO_ERROR_COULD_NOT_CREATE_PARENT_DIR.get(parent), null);
         }
       }
       catch (IOException ioe)
       {
         throw new ApplicationException(
-            ApplicationReturnCode.ReturnCode.FILE_SYSTEM_ACCESS_ERROR,
+            ReturnCode.FILE_SYSTEM_ACCESS_ERROR,
             INFO_ERROR_COULD_NOT_CREATE_PARENT_DIR.get(parent),
             ioe);
       }
diff --git a/opends/src/quicksetup/org/opends/quicksetup/ui/GuiApplication.java b/opends/src/quicksetup/org/opends/quicksetup/ui/GuiApplication.java
index 29da0bc..3e2d081 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/ui/GuiApplication.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/ui/GuiApplication.java
@@ -569,7 +569,7 @@
               (t.getMessage() == null) ? t.toString() : t.getMessage());
       LOG.log(Level.INFO, msg.toString(), t);
       throw new ApplicationException(
-          ApplicationReturnCode.ReturnCode.IMPORT_ERROR, msg, t);
+          ReturnCode.IMPORT_ERROR, msg, t);
     }
   }
 
@@ -578,7 +578,7 @@
    */
   public UserInteraction userInteraction() {
     UserInteraction ui = null;
-    if (!getUserData().isQuiet()) {
+    if (!getUserData().isInteractive()) {
       if (Utils.isCli()) {
         ui = new CliUserInteraction();
       } else {
diff --git a/opends/src/quicksetup/org/opends/quicksetup/ui/GuiUserInteraction.java b/opends/src/quicksetup/org/opends/quicksetup/ui/GuiUserInteraction.java
index 67a9c5f..6f2dff1 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/ui/GuiUserInteraction.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/ui/GuiUserInteraction.java
@@ -148,6 +148,18 @@
   }
 
   /**
+   * {@inheritDoc}
+   */
+  public String promptForString(Message prompt, Message title,
+                                String defaultValue) {
+    Object o = JOptionPane.showInputDialog(
+            parent, prompt.toString(), title.toString(),
+            JOptionPane.QUESTION_MESSAGE,
+            null, null, defaultValue);
+    return o != null ? o.toString() : null;
+  }
+
+  /**
    * JOptionPane that controls the number of characters that are allowed
    * to appear on a single line in the input area of the dialog.
    */
diff --git a/opends/src/quicksetup/org/opends/quicksetup/upgrader/BuildExtractor.java b/opends/src/quicksetup/org/opends/quicksetup/upgrader/BuildExtractor.java
index d0200ee..a17d7cc 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/upgrader/BuildExtractor.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/upgrader/BuildExtractor.java
@@ -43,10 +43,17 @@
 import java.util.logging.Logger;
 
 /**
- * BuildExtractor unzips an OpenDS installation package (.zip file) from a user
- * specified location into the current builds staging directory.  This Java
- * program handles this task so that we don't need to rely on the operating
- * system's tools for managing zip files.
+ * BuildExtractor runs prior to an upgrade or reversion operation.  Its main
+ * purpose is to unzip an OpenDS installation package (.zip file) from a user
+ * specified location into the current builds staging directory.  However,
+ * this program is also responsible for determining whether or not this
+ * invocation is intended to be an upgrade or reversion operation.  If this
+ * is a reversion, this program just exists with the appropriate exit code
+ * indicating reversion.  If this is an upgrade this program unzips the
+ * installation package.
+ *
+ * This Java program handles unzipping files so that we don't need to rely on
+ * the operating system's tools for managing zip files.
  *
  * This tool is a stand-alone program since it is run in preparation for a
  * off line upgrade and runs using the current program's jars rather than
@@ -60,6 +67,12 @@
   static private final Logger LOG =
           Logger.getLogger(BuildExtractor.class.getName());
 
+  /** Return code indicating that this invocation is an upgrade. */
+  private static final int RC_CONTINUE_WITH_UPGRADE = 99;
+
+  /** Return code indicating that this invocation is a reversion. */
+  private static final int RC_CONTINUE_WITH_REVERSION = 98;
+
   /**
    * Creates and run a BuildExtractor using command line arguments.
    * @param args String[] command line arguments
@@ -78,14 +91,14 @@
     new BuildExtractor(args).launch();
   }
 
-  private BuildExtractorCliHelper helper = new BuildExtractorCliHelper();
-
   private UpgradeUserData userData;
 
   private boolean finished;
 
   private ApplicationException error;
 
+  private ReturnCode rc;
+
   private BuildExtractor(String[] args) {
     super(args);
   }
@@ -101,37 +114,49 @@
    * contents into the current build's staging are and exits with return code 0.
    */
   public void run() {
-    try {
-      UpgradeUserData uud = (UpgradeUserData)getUserData();
-      File buildFile = uud.getInstallPackage();
-      if (buildFile != null) {
-        LOG.log(Level.INFO, "expanding zip file " + buildFile.getPath());
-        File stageDirectory = initStageDirectory();
-        ZipExtractor extractor = new ZipExtractor(buildFile);
-        extractor.extract(stageDirectory);
-        LOG.log(Level.INFO, "extraction finished");
-        Installation installation = new Installation(stageDirectory);
-        if (!installation.isValid()) {
-          LOG.log(Level.INFO, "extraction produed an invalid OpenDS" +
-                  "installation: " + installation.getInvalidityReason());
-          Message invalidMsg = INFO_BUILD_EXTRACTOR_FILE_INVALID.get(
-                  Utils.getPath(buildFile),
-                  installation.getInvalidityReason());
-          error = new ApplicationException(
-              ApplicationReturnCode.ReturnCode.APPLICATION_ERROR,
-                  invalidMsg, null);
-          System.err.println(invalidMsg);
+    UpgradeUserData uud = (UpgradeUserData)getUserData();
+    if (UpgradeUserData.Operation.REVERSION.equals(uud.getOperation())) {
+      rc = new ReturnCode(RC_CONTINUE_WITH_REVERSION);
+    } else {
+      try {
+        File buildFile = uud.getInstallPackage();
+        if (buildFile != null) {
+          LOG.log(Level.INFO, "Expanding zip file " + buildFile.getPath());
+          File stageDirectory = initStageDirectory();
+          ZipExtractor extractor = new ZipExtractor(buildFile);
+          extractor.extract(stageDirectory);
+          LOG.log(Level.INFO, "Extraction finished");
+          Installation installation = new Installation(stageDirectory);
+          if (!installation.isValid()) {
+            LOG.log(Level.INFO, "Extraction produed an invalid OpenDS" +
+                    "installation: " + installation.getInvalidityReason());
+            Message invalidMsg = INFO_BUILD_EXTRACTOR_FILE_INVALID.get(
+                    Utils.getPath(buildFile),
+                    installation.getInvalidityReason());
+            error = new ApplicationException(
+                ReturnCode.APPLICATION_ERROR,
+                    invalidMsg, null);
+            System.err.println(invalidMsg);
+          }
+          rc = new ReturnCode(RC_CONTINUE_WITH_UPGRADE);
+        } else {
+          // This should never happen assuming createUserData did the
+          // right thing
+          LOG.log(Level.INFO, "Build extractor failed to " +
+                  "specify valid installation zip file");
+          throw new IllegalStateException("Build extractor failed to " +
+                  "specify valid installation zip file");
         }
+      } catch (Throwable t) {
+        LOG.log(Level.INFO, "Unexpected error extracting build", t);
+        String reason = t.getLocalizedMessage();
+        error = new ApplicationException(
+                ReturnCode.APPLICATION_ERROR,
+                INFO_BUILD_EXTRACTOR_ERROR.get(reason), t);
+        System.err.println(reason);
+      } finally   {
+        finished = true;
       }
-    } catch (Throwable t) {
-      LOG.log(Level.INFO, "unexpected error extracting build", t);
-      String reason = t.getLocalizedMessage();
-      error = new ApplicationException(
-              ApplicationReturnCode.ReturnCode.APPLICATION_ERROR,
-              INFO_BUILD_EXTRACTOR_ERROR.get(reason), t);
-      System.err.println(reason);
-    } finally   {
-      finished = true;
     }
   }
 
@@ -173,7 +198,21 @@
   public UserData createUserData(Launcher launcher)
           throws UserDataException
   {
-    return helper.createUserData(args);
+    BuildExtractorCliHelper helper =
+            new BuildExtractorCliHelper((UpgradeLauncher)launcher);
+    UpgradeUserData uud = helper.createUserData(args);
+
+    // Build Extractor is always quiet
+    uud.setQuiet(true);
+
+    // The user may have indicated the operation via interactivity
+    if (UpgradeUserData.Operation.UPGRADE.equals(uud.getOperation())) {
+      isUpgrade = true;
+    } else if (UpgradeUserData.Operation.REVERSION.equals(uud.getOperation())) {
+      isReversion = true;
+    }
+
+    return uud;
   }
 
   /**
@@ -216,6 +255,13 @@
   /**
    * {@inheritDoc}
    */
+  public ReturnCode getReturnCode() {
+    return rc;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
   public void addProgressUpdateListener(ProgressUpdateListener l) {
     // 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 5b03db0..ec58cdd 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/upgrader/BuildExtractorCliHelper.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/upgrader/BuildExtractorCliHelper.java
@@ -28,6 +28,7 @@
 package org.opends.quicksetup.upgrader;
 
 import static org.opends.messages.QuickSetupMessages.*;
+import org.opends.messages.Message;
 
 import org.opends.quicksetup.UserDataException;
 
@@ -44,6 +45,14 @@
           Logger.getLogger(BuildExtractorCliHelper.class.getName());
 
   /**
+   * Create a parameterized instance.
+   * @param launcher for this CLI
+   */
+  public BuildExtractorCliHelper(UpgradeLauncher launcher) {
+    super(launcher);
+  }
+
+  /**
    * Creates a set of user data from command line arguments and installation
    * status.
    * @param args String[] of arguments passed in from the command line
@@ -53,37 +62,44 @@
   public UpgradeUserData createUserData(String[] args)
     throws UserDataException {
     UpgradeUserData uud = super.createUserData(args);
-
-    // Build extractor is always quiet whether user
-    // has specified this or not.
-    uud.setQuiet(true);
-
-    if (localInstallPackFileNameArg.isPresent()) {
-      String localInstallPackFileName =
-              localInstallPackFileNameArg.getValue();
-      LOG.log(Level.INFO, "file specified on command line: " +
-              localInstallPackFileName);
-      uud.setInstallPackage(
-              validateInstallPackFile(localInstallPackFileName));
-    } else if (isInteractive()) {
-      LOG.log(Level.INFO, "obtaining file information interactively");
-      while(true) {
-        String fileName = promptForString(
-                INFO_UPGRADE_FILE_PROMPT.get(), null);
-        try {
-          uud.setInstallPackage(validateInstallPackFile(fileName));
-          LOG.log(Level.INFO, "file specified interactively: " +
-                  fileName);
-          break;
-        } catch (UserDataException ude) {
-          System.out.println(ude.getMessage());
+    if (launcher.isInteractive()) {
+      if (!launcher.isNoPrompt()) {
+        LOG.log(Level.INFO, "obtaining file information interactively");
+        Message[] options = new Message[] {
+                INFO_UPGRADE_OPERATION_UPGRADE.get(),
+                INFO_UPGRADE_OPERATION_REVERSION.get()
+        };
+        int response = promptOptions(
+                INFO_UPGRADE_OPERATION_PROMPT.get(),
+                options[0],
+                options);
+        if (response == 0) {
+          uud.setOperation(UpgradeUserData.Operation.UPGRADE);
+          while(true) {
+            String fileName = promptForString(
+                    INFO_UPGRADE_FILE_PROMPT.get(), null);
+            try {
+              uud.setInstallPackage(validateInstallPackFile(fileName));
+              LOG.log(Level.INFO, "file specified interactively: " +
+                      fileName);
+              break;
+            } catch (UserDataException ude) {
+              System.out.println(ude.getMessage());
+            }
+          }
+        } else {
+          uud.setOperation(UpgradeUserData.Operation.REVERSION);
         }
+      } else {
+        throw new UserDataException(null,
+                INFO_ERROR_OPTIONS_REQUIRED_OR_INTERACTIVE.get());
       }
     } else {
-      throw new UserDataException(null,
-              INFO_ERROR_OPTION_REQUIRED_OR_INTERACTIVE.get("-" +
-                      UpgradeLauncher.FILE_OPTION_SHORT + "/--" +
-                              UpgradeLauncher.FILE_OPTION_LONG));
+      String upgradeFile = launcher.getUpgradeFileName();
+      if (upgradeFile != null) {
+        uud.setInstallPackage(
+                validateInstallPackFile(upgradeFile));
+      }
     }
     return uud;
   }
diff --git a/opends/src/quicksetup/org/opends/quicksetup/upgrader/MigrationManager.java b/opends/src/quicksetup/org/opends/quicksetup/upgrader/MigrationManager.java
index 7b02e34..c32c544 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/upgrader/MigrationManager.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/upgrader/MigrationManager.java
@@ -32,7 +32,7 @@
 import static org.opends.messages.QuickSetupMessages.*;
 
 import org.opends.quicksetup.ApplicationException;
-import org.opends.quicksetup.ApplicationReturnCode;
+import org.opends.quicksetup.ReturnCode;
 import org.opends.quicksetup.Installation;
 import org.opends.quicksetup.UserInteraction;
 import org.opends.quicksetup.Constants;
@@ -179,7 +179,7 @@
       Message msg = INFO_ERROR_APPLYING_CUSTOM_CONFIG.get();
       LOG.log(Level.INFO, msg.toString(), e);
       throw new ApplicationException(
-          ApplicationReturnCode.ReturnCode.IMPORT_ERROR, msg, e);
+          ReturnCode.IMPORT_ERROR, msg, e);
     }
   }
 
@@ -201,7 +201,7 @@
       Message msg = INFO_ERROR_APPLYING_CUSTOM_SCHEMA.get();
       LOG.log(Level.INFO, msg.toString(), e);
       throw new ApplicationException(
-          ApplicationReturnCode.ReturnCode.IMPORT_ERROR, msg, e);
+          ReturnCode.IMPORT_ERROR, msg, e);
     }
   }
 
@@ -274,7 +274,7 @@
             // do nothing; will retry;
           } else {
             throw new ApplicationException(
-                ApplicationReturnCode.ReturnCode.CANCELLED,
+                ReturnCode.CANCELLED,
                 INFO_UPGRADE_CANCELED.get(), e);
           }
         } else {
@@ -341,7 +341,7 @@
     int ret = oo.getReturnCode();
     if (ret != 0) {
       throw new ApplicationException(
-          ApplicationReturnCode.ReturnCode.TOOL_ERROR,
+          ReturnCode.TOOL_ERROR,
               INFO_ERROR_LDIF_DIFF_TOOL_RETURN_CODE.get(Integer.toString(ret)),
               null);
     }
diff --git a/opends/src/quicksetup/org/opends/quicksetup/upgrader/ReversionIssueNotifier.java b/opends/src/quicksetup/org/opends/quicksetup/upgrader/ReversionIssueNotifier.java
new file mode 100644
index 0000000..c29fc1a
--- /dev/null
+++ b/opends/src/quicksetup/org/opends/quicksetup/upgrader/ReversionIssueNotifier.java
@@ -0,0 +1,232 @@
+/*
+ * 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.UserInteraction;
+import org.opends.quicksetup.BuildInformation;
+import org.opends.quicksetup.ApplicationException;
+import org.opends.quicksetup.ReturnCode;
+import org.opends.quicksetup.Constants;
+import org.opends.messages.Message;
+import org.opends.messages.MessageBuilder;
+import static org.opends.messages.QuickSetupMessages.*;
+import org.opends.server.util.VersionCompatibilityIssue;
+import static org.opends.server.util.VersionCompatibilityIssue.*;
+
+import java.util.logging.Logger;
+import java.util.logging.Level;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * {@link VersionIssueNotifier} specific
+ * to upgrade tools.
+ */
+public class ReversionIssueNotifier extends VersionIssueNotifier {
+
+  static private final Logger LOG =
+          Logger.getLogger(ReversionIssueNotifier.class.getName());
+
+  /**
+   * Creates a new instance that can analyze a hypothetical upgrade/reversion
+   * operation from one version to another.
+   * @param ui UserInteraction for relaying information to the user
+   * @param current BuildInformation representing the current version
+   * @param neu BuildInformation representing the proposed next version
+   */
+  public ReversionIssueNotifier(UserInteraction ui,
+                       BuildInformation current,
+                       BuildInformation neu) {
+    super(ui, current, neu);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public void notifyUser() throws ApplicationException {
+    Message cont = INFO_ORACLE_ACTION_PROMPT_CONTINUE.get();
+    Message cancel = INFO_ORACLE_ACTION_PROMPT_CANCEL.get();
+    if (hasIssues()) {
+      List<Directive> issues = getIssues();
+      if (!isSupported()) {
+        if (issues != null) {
+          for (Directive directive : issues) {
+            LOG.log(Level.INFO, "Unsupported reversion details: " +
+                    directive.getMessage());
+          }
+        }
+        throw new ApplicationException(
+            ReturnCode.APPLICATION_ERROR,
+                INFO_REVERSION_ORACLE_UNSUPPORTED.get(
+                        currentBuildInfo.toString(),
+                        newBuildInfo.toString()),
+                null);
+      } else {
+        if (ui != null) {
+          for (Directive directive : issues) {
+            Message title;
+            Message summary;
+            Message details;
+            Message defaultAction;
+            UserInteraction.MessageType msgType;
+            switch (directive.getType()) {
+              case ACTION:
+                title = INFO_GENERAL_ACTION_REQUIRED.get();
+                summary = INFO_REVERSION_ORACLE_ACTION.get();
+                details = new MessageBuilder(directive.getMessage())
+                        .append(Constants.HTML_LINE_BREAK)
+                        .append(Constants.HTML_LINE_BREAK)
+                        .append(INFO_ORACLE_ACTION_PROMPT.get())
+                        .toMessage();
+                msgType = UserInteraction.MessageType.WARNING;
+                defaultAction = cancel;
+                break;
+              case INFO:
+                title = INFO_GENERAL_INFO.get();
+                summary = INFO_REVERSION_ORACLE_INFO.get();
+                details = new MessageBuilder(directive.getMessage())
+                        .append(Constants.HTML_LINE_BREAK)
+                        .append(Constants.HTML_LINE_BREAK)
+                        .append(INFO_ORACLE_INFO_PROMPT.get())
+                        .toMessage();
+                msgType = UserInteraction.MessageType.INFORMATION;
+                defaultAction = cont;
+                break;
+              case WARNING:
+                title = INFO_GENERAL_WARNING.get();
+                summary = INFO_REVERSION_ORACLE_WARNING.get();
+                details = new MessageBuilder(directive.getMessage())
+                        .append(Constants.HTML_LINE_BREAK)
+                        .append(Constants.HTML_LINE_BREAK)
+                        .append(INFO_ORACLE_INFO_PROMPT.get())
+                        .toMessage();
+                msgType = UserInteraction.MessageType.WARNING;
+                defaultAction = cont;
+                break;
+              default:
+                LOG.log(Level.INFO, "Unexpected issue type " +
+                        directive.getType());
+                title = Message.EMPTY;
+                summary = Message.EMPTY;
+                details = directive.getMessage();
+                msgType = UserInteraction.MessageType.WARNING;
+                defaultAction = cont;
+            }
+            if (cancel.equals(ui.confirm(
+                    summary,
+                    details,
+                    title,
+                    msgType,
+                    new Message[]{cont, cancel},
+                    defaultAction))) {
+              throw new ApplicationException(
+                  ReturnCode.CANCELLED,
+                      INFO_REVERSION_CANCELED.get(), null);
+            }
+          }
+        } else {
+          throw new ApplicationException(
+              ReturnCode.APPLICATION_ERROR,
+              INFO_ORACLE_NO_SILENT.get(), null);
+        }
+      }
+    }
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  protected Message getLocalizedDetailMessage(
+          VersionCompatibilityIssue.Cause cause)
+  {
+    Message msg = cause.getLocalizedUpgradeMessage();
+
+    // See if we need to supply a generic message
+    Set<VersionCompatibilityIssue.Effect> effects = cause.getEffects();
+
+    // If the import/export effect is present, append the detailed
+    // instructions.
+    if (effects.contains(Effect.REVERSION_DATA_EXPORT_AND_REIMPORT_REQUIRED)) {
+      msg = new MessageBuilder(msg)
+              .append(Constants.HTML_LINE_BREAK)
+              .append(ui.createUnorderedList(getExportImportInstructions()))
+              .toMessage();
+    }
+    return msg;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  protected boolean isActionRequired(VersionCompatibilityIssue.Cause cause) {
+    boolean isAction = false;
+    if (cause != null) {
+      Set<VersionCompatibilityIssue.Effect> effects = cause.getEffects();
+      isAction =
+              effects.contains(
+                      Effect.REVERSION_DATA_EXPORT_AND_REIMPORT_REQUIRED) ||
+                      (effects.contains(
+                              Effect.REVERSION_MANUAL_ACTION_REQUIRED) &&
+                              cause.getLocalizedUpgradeMessage() != null);
+    }
+    return isAction;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  protected boolean isWarning(VersionCompatibilityIssue.Cause cause) {
+    boolean isWarning = false;
+    if (cause != null && !isActionRequired(cause)) {
+      Set<VersionCompatibilityIssue.Effect> effects = cause.getEffects();
+      isWarning = effects.contains(Effect.REVERSION_SHOW_WARNING_MESSAGE) &&
+              cause.getLocalizedUpgradeMessage() != null;
+    }
+    return isWarning;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  protected boolean isUnsupported(VersionCompatibilityIssue.Cause cause) {
+    boolean isUnsupported = false;
+    if (cause != null) {
+      Set<VersionCompatibilityIssue.Effect> effects = cause.getEffects();
+      for (VersionCompatibilityIssue.Effect effect : effects) {
+        switch (effect) {
+          case REVERSION_NOT_POSSIBLE:
+            isUnsupported = true; break;
+          default:
+            // assume not an tion;
+        }
+      }
+    }
+    return isUnsupported;
+  }
+
+}
diff --git a/opends/src/quicksetup/org/opends/quicksetup/upgrader/ReversionLauncher.java b/opends/src/quicksetup/org/opends/quicksetup/upgrader/ReversionLauncher.java
index 5e778c4..bc2d911 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/upgrader/ReversionLauncher.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/upgrader/ReversionLauncher.java
@@ -27,42 +27,19 @@
 
 package org.opends.quicksetup.upgrader;
 
-import org.opends.messages.Message;
 import static org.opends.messages.QuickSetupMessages.*;
 
-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.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.messages.ToolMessages.*;
-import static org.opends.server.tools.ToolConstants.*;
 
 import java.io.File;
 
 /**
- * Launches a reversion operation.
+ * Launches a reversion operation.  This class just extends UpgradeLauncher
+ * which really contains all the smarts for launching reversion/upgrade
+ * operations.
  */
-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-";
+public class ReversionLauncher extends UpgradeLauncher {
 
   /**
    * Creates and launches a reversion operation.
@@ -80,140 +57,26 @@
     new ReversionLauncher(args).launch();
   }
 
-  private ArgumentParser argParser;
-
-  private BooleanArgument showUsage;
-  private FileBasedArgument dir;
-  private BooleanArgument mostRecent;
-  private BooleanArgument quiet;
-  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
+  public boolean isReversion() {
     return true;
   }
 
   /**
    * {@inheritDoc}
    */
-  protected Message 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(),
-        INFO_REVERT_LAUNCHER_USAGE_DESCRIPTION.get(), false);
-    try
-    {
-      dir = new FileBasedArgument("directory",
-              DIRECTORY_OPTION_SHORT,
-              DIRECTORY_OPTION_LONG,
-              false, false,
-              "{directory}",
-              null, null, INFO_REVERT_DESCRIPTION_DIRECTORY.get());
-      argParser.addArgument(dir);
-
-      mostRecent = new BooleanArgument("mostRecent",
-              MOST_RECENT_OPTION_SHORT,
-              MOST_RECENT_OPTION_LONG,
-              INFO_REVERT_DESCRIPTION_RECENT.get());
-      argParser.addArgument(mostRecent);
-
-      interactive = new BooleanArgument("interactive", 'i', "interactive",
-          INFO_REVERT_DESCRIPTION_INTERACTIVE.get());
-      argParser.addArgument(interactive);
-
-      quiet = new BooleanArgument("quiet",
-              OPTION_SHORT_QUIET,
-              OPTION_LONG_QUIET,
-              INFO_REVERT_DESCRIPTION_SILENT.get());
-      argParser.addArgument(quiet);
-
-      showUsage = new BooleanArgument("showusage", OPTION_SHORT_HELP,
-        OPTION_LONG_HELP,
-        INFO_DESCRIPTION_USAGE.get());
-      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
index ab4a4cd..9204e73 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/upgrader/ReversionProgressStep.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/upgrader/ReversionProgressStep.java
@@ -45,7 +45,9 @@
 
   REVERTING_FILESYSTEM(INFO_SUMMARY_REVERT_REVERTING_COMPONENTS.get(), 60),
 
-  VERIFYING(INFO_SUMMARY_REVERT_VERIFYING.get(), 80),
+  VERIFYING(INFO_SUMMARY_REVERT_VERIFYING.get(), 70),
+
+  STARTING_SERVER(INFO_SUMMARY_STARTING.get(), 80),
 
   RECORDING_HISTORY(INFO_SUMMARY_REVERT_HISTORY.get(), 90),
 
@@ -65,7 +67,7 @@
   private Message summaryMsg;
   private int progress;
 
-  private ReversionProgressStep(Message summaryMsgKey, int progress) {
+  private ReversionProgressStep(Message summaryMsg, int progress) {
     this.summaryMsg = summaryMsg;
     this.progress = progress;
   }
diff --git a/opends/src/quicksetup/org/opends/quicksetup/upgrader/Reverter.java b/opends/src/quicksetup/org/opends/quicksetup/upgrader/Reverter.java
index f935991..8c95ed4 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/upgrader/Reverter.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/upgrader/Reverter.java
@@ -31,7 +31,7 @@
 import org.opends.messages.MessageBuilder;
 import static org.opends.messages.QuickSetupMessages.*;
 
-import org.opends.quicksetup.ApplicationReturnCode;
+import org.opends.quicksetup.ReturnCode;
 import org.opends.quicksetup.CliApplication;
 import org.opends.quicksetup.UserData;
 import org.opends.quicksetup.UserDataException;
@@ -45,6 +45,7 @@
 import org.opends.quicksetup.Application;
 import org.opends.quicksetup.HistoricalRecord;
 import org.opends.quicksetup.UserInteraction;
+import org.opends.quicksetup.CliUserInteraction;
 import org.opends.quicksetup.event.ProgressUpdateListener;
 import org.opends.quicksetup.util.ProgressMessageFormatter;
 import org.opends.quicksetup.util.Utils;
@@ -59,8 +60,12 @@
 import java.util.Set;
 import java.util.HashSet;
 import java.util.EnumSet;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Date;
 import java.util.logging.Level;
 import java.util.logging.Logger;
+import java.text.DateFormat;
 
 /**
  * Reverts an installation from its current version to a prior version.
@@ -74,27 +79,141 @@
           ReversionProgressStep.NOT_STARTED;
 
   private ReverterUserData userData;
-  private ProgressMessageFormatter formatter;
   private ProgressUpdateListenerDelegate listenerDelegate;
   private ApplicationException runError;
   private ApplicationException runWarning;
   private Installation installation;
+  private Installation archiveInstallation;
   private File tempBackupDir;
   private long historicalOperationId;
   private BuildInformation fromBuildInfo;
-  private BuildInformation toBuildInfo;
+  private BuildInformation archiveBuildInfo;
   private boolean abort = false;
+  private boolean restartServer = false;
 
   /**
    * {@inheritDoc}
    */
   public UserData createUserData(Launcher launcher) throws UserDataException {
     ReverterUserData ud = null;
-    if (launcher instanceof ReversionLauncher) {
+
+    if (launcher instanceof UpgradeLauncher) {
       ud = new ReverterUserData();
-      ReversionLauncher rl = (ReversionLauncher)launcher;
+      UpgradeLauncher rl = (UpgradeLauncher)launcher;
       File filesDir = null;
-      if (rl.useMostRecentUpgrade()) {
+      if (rl.isInteractive()) {
+        if (rl.isNoPrompt()) {
+          StringBuilder sb = new StringBuilder()
+                  .append("-")
+                  .append(UpgradeLauncher.REVERT_ARCHIVE_OPTION_SHORT)
+                  .append("/--")
+                  .append(ReversionLauncher.REVERT_ARCHIVE_OPTION_LONG)
+                  .append(", -")
+                  .append(ReversionLauncher.REVERT_MOST_RECENT_OPTION_SHORT)
+                  .append("/--")
+                  .append(ReversionLauncher.REVERT_MOST_RECENT_OPTION_LONG);
+          throw new UserDataException(null,
+                  INFO_REVERT_ERROR_NO_DIR.get(sb.toString()));
+        } else {
+          CliUserInteraction ui = new CliUserInteraction();
+          Message[] options = new Message[] {
+                  INFO_REVERSION_TYPE_PROMPT_RECENT.get(),
+                  INFO_REVERSION_TYPE_PROMPT_FILE.get()};
+          if (options[0].equals(ui.confirm(
+                  INFO_REVERT_CONFIRM_TITLE.get(),
+                  INFO_REVERSION_TYPE_PROMPT.get(),
+                  INFO_REVERT_CONFIRM_TITLE.get(),
+                  UserInteraction.MessageType.QUESTION,
+                  options, options[0])))
+          {
+            ud.setRevertMostRecent(true);
+          } else {
+            ud.setRevertMostRecent(false);
+
+            // Present a list of reversion archive choices to the user.
+            // In the future perhaps we might also allow them to type
+            // freehand.
+            File historyDir = getInstallation().getHistoryDirectory();
+            if (historyDir != null && historyDir.exists()) {
+
+              // Print a wait message, this could take a while
+              System.out.println(INFO_REVERSION_DIR_WAIT.get());
+
+              String[] historyChildren = historyDir.list();
+              Arrays.sort(historyChildren);
+              List<File> raDirList = new ArrayList<File>();
+              for (int i = historyChildren.length - 1; i >=0; i--) {
+                File raDirCandidate = new File(historyDir, historyChildren[i]);
+                if (isReversionFilesDirectory(raDirCandidate)) {
+                  raDirList.add(raDirCandidate);
+                }
+              }
+              File[] raDirs = raDirList.toArray(new File[raDirList.size()]);
+              List<Message> raDirChoiceList = new ArrayList<Message>();
+              for (File raDir : raDirs) {
+                String name = raDir.getName();
+                Message buildInfo = INFO_UPGRADE_BUILD_ID_UNKNOWN.get();
+                Message date = INFO_GENERAL_UNKNOWN.get();
+                try {
+                  Installation i =
+                          new Installation(appendFilesDirIfNeccessary(raDir));
+                  BuildInformation bi = i.getBuildInformation();
+                  buildInfo = Message.raw(bi.toString());
+                } catch (Exception e) {
+                  LOG.log(Level.INFO,
+                          "Error determining archive version for " + name);
+                }
+
+                try {
+                  Date d = new Date(Long.valueOf(name));
+                  DateFormat df = DateFormat.getInstance();
+                  date = Message.raw(df.format(d));
+                } catch (Exception e) {
+                  LOG.log(Level.INFO, "Error converting reversion archive " +
+                          "name " + name + " to date helper");
+                }
+                MessageBuilder mb = new MessageBuilder(name);
+                mb.append(" (");
+                mb.append(INFO_REVERSION_DIR_FROM_UPGRADE.get(buildInfo, date));
+                mb.append(")");
+                raDirChoiceList.add(mb.toMessage());
+              }
+              Message[] raDirChoices =
+                      raDirChoiceList.toArray(new Message[0]);
+              if (raDirChoices.length > 0) {
+                int resp = ui.promptOptions(
+                        INFO_REVERSION_DIR_PROMPT.get(),
+                        raDirChoices[0],
+                        raDirChoices);
+                File raDir = raDirs[resp];
+                raDir = appendFilesDirIfNeccessary(raDir);
+                try {
+                  ud.setReversionArchiveDirectory(
+                          validateReversionArchiveDirectory(raDir));
+                } catch (UserDataException ude) {
+                  System.err.println(ude.getMessageObject());
+                }
+              } else {
+                LOG.log(Level.INFO, "No archives in history dir");
+                throw new UserDataException(null,
+                        INFO_REVERT_ERROR_NO_HISTORY_DIR.get());
+              }
+            } else {
+              LOG.log(Level.INFO, "History dir does not exist");
+              throw new UserDataException(null,
+                      INFO_REVERT_ERROR_NO_HISTORY_DIR.get());
+            }
+          }
+        }
+      } else if (rl.isRevertMostRecent()) {
+        ud.setRevertMostRecent(true);
+      } else {
+        filesDir = rl.getReversionArchiveDirectory();
+        filesDir = appendFilesDirIfNeccessary(filesDir);
+        ud.setReversionArchiveDirectory(
+                validateReversionArchiveDirectory(filesDir));
+      }
+      if (ud.isRevertMostRecent()) {
         Installation install = getInstallation();
         File historyDir = install.getHistoryDirectory();
         if (historyDir.exists()) {
@@ -115,8 +234,8 @@
             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;
+              if (isReversionFilesDirectory(d)) {
+                ud.setReversionArchiveDirectory(d);
                 break;
               }
             }
@@ -129,33 +248,9 @@
           throw new UserDataException(null,
                   INFO_REVERT_ERROR_NO_HISTORY_DIR.get());
         }
-      } 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,
-                  INFO_REVERT_ERROR_NO_DIR.get(sb.toString()));
-        }
       }
-      if (validateFilesDirectory(filesDir)) {
-        ud.setFilesDirectory(filesDir);
-      }
+      ud.setQuiet(rl.isQuiet());
+      ud.setInteractive(!rl.isNoPrompt());
     }
     return ud;
   }
@@ -194,6 +289,13 @@
   /**
    * {@inheritDoc}
    */
+  public ReturnCode getReturnCode() {
+    return null;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
   public void addProgressUpdateListener(ProgressUpdateListener l) {
     listenerDelegate.addProgressUpdateListener(l);
   }
@@ -324,44 +426,95 @@
   public void run() {
 
     try {
-      initialize();
 
+      // Get the user to confirm if possible
       UserInteraction ui = userInteraction();
       if (ui != null) {
         Message cont = INFO_CONTINUE_BUTTON_LABEL.get();
         Message cancel = INFO_CANCEL_BUTTON_LABEL.get();
 
-        String toBuildString = null;
-        BuildInformation toBi = getToBuildInformation();
+        String toBuildString;
+        BuildInformation toBi = getArchiveBuildInformation();
         if (toBi != null) {
           toBuildString = toBi.toString();
         } else {
           toBuildString = INFO_UPGRADE_BUILD_ID_UNKNOWN.get().toString();
         }
-        if (cancel.equals(ui.confirm( // TODO: i18n
-                Message.raw("Confirm Reversion"),
-                Message.raw("This installation will be reverted to version " +
-                        toBuildString +
-                        " using the files in " + getFilesDirectory() + "."),
-                Message.raw("Confirm"),
+        if (cancel.equals(ui.confirm(
+                INFO_REVERT_CONFIRM_TITLE.get(),
+                INFO_REVERT_CONFIRM_PROMPT.get(
+                        toBuildString,
+                        Utils.getPath(getReversionFilesDirectory())),
+                INFO_REVERT_CONFIRM_TITLE.get(),
                 UserInteraction.MessageType.WARNING,
                 new Message[] { cont, cancel },
                 cont))) {
           throw new ApplicationException(
-              ApplicationReturnCode.ReturnCode.CANCELLED,
+              ReturnCode.CANCELLED,
               INFO_REVERSION_CANCELED.get(), null);
         }
       }
 
-      stopServer();
-      revertFiles();
+      // Stop the server if necessary.  Task note as to whether the server
+      // is running since we will leave it in that state when we are done.
+      Installation installation = getInstallation();
+      Status status = installation.getStatus();
+      ServerController sc = new ServerController(installation);
+      if (status.isServerRunning()) {
+        restartServer = true;
+        sc = new ServerController(installation);
+        try {
+          setCurrentProgressStep(ReversionProgressStep.STOPPING_SERVER);
+          LOG.log(Level.INFO, "Stopping server");
+          sc.stopServer(true);
+          notifyListeners(getFormattedDoneWithLineBreak());
+        } catch (ApplicationException ae) {
+          notifyListeners(getFormattedErrorWithLineBreak());
+        }
+      }
+
+      try {
+        setCurrentProgressStep(ReversionProgressStep.INITIALIZING);
+        initialize();
+        notifyListeners(getFormattedDoneWithLineBreak());
+      } catch (ApplicationException ae) {
+        LOG.log(Level.INFO, "Error initializing reversion", ae);
+        notifyListeners(getFormattedErrorWithLineBreak());
+        throw ae;
+      }
+
+      try {
+        LOG.log(Level.INFO, "Reverting components");
+        setCurrentProgressStep(ReversionProgressStep.REVERTING_FILESYSTEM);
+        revertComponents();
+        LOG.log(Level.INFO, "Finished reverting components");
+        notifyListeners(getFormattedDoneWithLineBreak());
+      } catch (ApplicationException ae) {
+        LOG.log(Level.INFO, "Error reverting components", ae);
+        notifyListeners(getFormattedErrorWithLineBreak());
+        throw ae;
+      }
+
+      if (restartServer) {
+        try {
+          LOG.log(Level.INFO, "Restarting server");
+          setCurrentProgressStep(ReversionProgressStep.STARTING_SERVER);
+          sc.startServer();
+          notifyListeners(getFormattedDoneWithLineBreak());
+        } catch (ApplicationException ae) {
+          notifyListeners(getFormattedErrorWithLineBreak());
+        }
+      }
+
     } catch (Throwable e) {
       if (!(e instanceof ApplicationException)) {
         runError = new ApplicationException(
-            ApplicationReturnCode.ReturnCode.BUG,
+            ReturnCode.BUG,
                 Message.raw(e.getLocalizedMessage()), e);
       } else {
         runError = (ApplicationException)e;
+        abort = ReturnCode.CANCELLED.equals(
+                ((ApplicationException)e).getType());
       }
     } finally {
       end();
@@ -379,25 +532,13 @@
     this.historicalOperationId =
       writeInitialHistoricalRecord(
               getFromBuildInformation(),
-              getToBuildInformation());
+              getArchiveBuildInformation());
+    insureRevertability();
+    backupCurrentInstallation();
   }
 
-  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 {
+  private void backupCurrentInstallation() throws ApplicationException {
+    LOG.log(Level.INFO, "Backing up filesystem");
     try {
       File filesBackupDirectory = getTempBackupDirectory();
       FileManager fm = new FileManager();
@@ -408,11 +549,14 @@
         //fm.copyRecursively(f, filesBackupDirectory,
         fm.move(f, filesBackupDirectory, filter);
       }
+      LOG.log(Level.INFO, "Finished backing up filesystem");
     } catch (ApplicationException ae) {
+      LOG.log(Level.INFO, "Error backing up filesystem", ae);
       throw ae;
     } catch (Exception e) {
+      LOG.log(Level.INFO, "Error backing up filesystem", e);
       throw new ApplicationException(
-          ApplicationReturnCode.ReturnCode.FILE_SYSTEM_ACCESS_ERROR,
+          ReturnCode.FILE_SYSTEM_ACCESS_ERROR,
               INFO_ERROR_BACKUP_FILESYSTEM.get(),
               e);
     }
@@ -420,7 +564,7 @@
 
   private void revertComponents() throws ApplicationException {
     try {
-      File stageDir = getFilesDirectory();
+      File stageDir = getReversionFilesDirectory();
       Installation installation = getInstallation();
       File root = installation.getRootDirectory();
       FileManager fm = new FileManager();
@@ -434,7 +578,7 @@
       // 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 " +
+      LOG.log(Level.INFO, "Reverted bits to " +
               installation.getBuildInformation(false));
 
     } catch (IOException e) {
@@ -443,12 +587,12 @@
     }
   }
 
-  private File getFilesDirectory()
+  private File getReversionFilesDirectory()
           throws ApplicationException, IOException {
-    return userData.getFilesDirectory();
+    return userData.getReversionArchiveDirectory();
   }
 
-  private boolean validateFilesDirectory(File filesDir)
+  private File validateReversionArchiveDirectory(File filesDir)
           throws UserDataException
   {
     if (filesDir == null) {
@@ -457,16 +601,17 @@
     } else if (!filesDir.isDirectory()) {
       throw new UserDataException(null,
               INFO_REVERT_ERROR_NOT_DIR_FILES_DIR.get());
-    } else if (!isFilesDirectory(filesDir)) {
+    } else if (!isReversionFilesDirectory(filesDir)) {
       throw new UserDataException(null,
               INFO_REVERT_ERROR_NOT_DIR_FILES_DIR.get());
     }
-    return true;
+    return filesDir;
   }
 
-  private boolean isFilesDirectory(File filesDir) {
+  private boolean isReversionFilesDirectory(File filesDir) {
+    filesDir = appendFilesDirIfNeccessary(filesDir);
     boolean isFilesDir = false;
-    if (filesDir != null && filesDir.isDirectory()) {
+    if (filesDir != null && filesDir.exists() && filesDir.isDirectory()) {
       String[] children = filesDir.list();
       Set<String> cs = new HashSet<String>(Arrays.asList(children));
 
@@ -483,6 +628,15 @@
       String note = null;
       if (runError == null && !abort) {
         status = HistoricalRecord.Status.SUCCESS;
+
+        // Since everything went OK, delete the archive
+        LOG.log(Level.INFO, "Cleaning up after reversion");
+        setCurrentProgressStep(ReversionProgressStep.CLEANUP);
+        deleteArchive();
+        deleteBackup();
+        notifyListeners(getFormattedDoneWithLineBreak());
+        LOG.log(Level.INFO, "Clean up complete");
+
       } else {
         if (abort) {
           status = HistoricalRecord.Status.CANCEL;
@@ -492,32 +646,29 @@
         }
 
         // Abort the reversion and put things back like we found it
-        LOG.log(Level.INFO, "canceling reversion");
+        LOG.log(Level.INFO, "Canceling reversion");
         ProgressStep lastProgressStep = currentProgressStep;
         setCurrentProgressStep(ReversionProgressStep.ABORT);
         abort(lastProgressStep);
         notifyListeners(getFormattedDoneWithLineBreak());
-        LOG.log(Level.INFO, "cancelation complete");
+        LOG.log(Level.INFO, "Cancelation complete");
       }
 
-      LOG.log(Level.INFO, "cleaning up after reversion");
-      setCurrentProgressStep(ReversionProgressStep.CLEANUP);
-      cleanup();
-      notifyListeners(getFormattedDoneWithLineBreak());
-      LOG.log(Level.INFO, "clean up complete");
-
+      // Remove the lib directory temporarily created by the
+      // launch script with which the program is running
+      deleteReversionLib();
 
       // Write a record in the log file indicating success/failure
-      LOG.log(Level.INFO, "recording history");
+      LOG.log(Level.INFO, "Recording history");
       setCurrentProgressStep(ReversionProgressStep.RECORDING_HISTORY);
       writeHistoricalRecord(historicalOperationId,
               getFromBuildInformation(),
-              getToBuildInformation(),
+              getArchiveBuildInformation(),
               status,
               note);
 
       notifyListeners(getFormattedDoneWithLineBreak());
-      LOG.log(Level.INFO, "history recorded");
+      LOG.log(Level.INFO, "History recorded");
       notifyListeners(
               new MessageBuilder(
                 INFO_GENERAL_SEE_FOR_HISTORY.get(
@@ -525,7 +676,7 @@
               .append(getLineBreak()).toMessage());
     } catch (ApplicationException e) {
       notifyListeners(getFormattedDoneWithLineBreak());
-      LOG.log(Level.INFO, "Error cleaning up after upgrade.", e);
+      LOG.log(Level.INFO, "Error cleaning up after reversion.", e);
     }
 
     // Decide final status based on presense of error
@@ -538,16 +689,16 @@
     // processing messages has finished.  Need to resolve these
     // issues.
     if (abort) {
-      LOG.log(Level.INFO, "upgrade canceled by user");
+      LOG.log(Level.INFO, "reversion canceled by user");
       setCurrentProgressStep(ReversionProgressStep.FINISHED_CANCELED);
     } else if (runError != null) {
-      LOG.log(Level.INFO, "upgrade completed with errors", runError);
+      LOG.log(Level.INFO, "reversion completed with errors", runError);
       notifyListeners(getFormattedErrorWithLineBreak(runError,true));
       notifyListeners(getLineBreak());
       setCurrentProgressStep(ReversionProgressStep.FINISHED_WITH_ERRORS);
       notifyListeners(getLineBreak());
     } else if (runWarning != null) {
-      LOG.log(Level.INFO, "upgrade completed with warnings");
+      LOG.log(Level.INFO, "reversion completed with warnings");
       Message warningText = runWarning.getMessageObject();
 
       // By design, the warnings are written as errors to the details section
@@ -615,12 +766,6 @@
           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);
       }
@@ -628,8 +773,45 @@
 
   }
 
-  private void cleanup() {
-    // TODO:
+  /**
+   * Deletes the archived backup to which we reverted.
+   */
+  private void deleteArchive() {
+    FileManager fm = new FileManager();
+    try {
+      fm.deleteRecursively(getReversionFilesDirectory());
+    } catch (Exception e) {
+      // ignore; this is best effort
+    }
+  }
+
+  /**
+   * Deletes the backup of the current installation.
+   */
+  private void deleteBackup() {
+    FileManager fm = new FileManager();
+    try {
+      fm.deleteRecursively(getTempBackupDirectory());
+    } catch (Exception e) {
+      // ignore; this is best effort
+    }
+  }
+
+  /**
+   * Delete the library with which this reversion is currently
+   * running.
+   */
+  private void deleteReversionLib() {
+    FileManager fm = new FileManager();
+    try {
+      File tmpDir = getInstallation().getTemporaryDirectory();
+      File revertLibDir = new File(tmpDir, "revert");
+      fm.deleteRecursively(
+              revertLibDir, null,
+              FileManager.DeletionPolicy.DELETE_ON_EXIT);
+    } catch (Exception e) {
+      // ignore; this is best effort
+    }
   }
 
   /**
@@ -638,6 +820,8 @@
    * is a problem with this reversion in which case they can be restored.
    *
    * @return File directory where the unreverted bits will be stored.
+   * @throws java.io.IOException if something goes wrong
+   * @throws org.opends.quicksetup.ApplicationException if something goes wrong
    */
   private File getTempBackupDirectory()
           throws IOException, ApplicationException
@@ -670,20 +854,29 @@
     return fromBuildInfo;
   }
 
-  private BuildInformation getToBuildInformation() {
-    if (toBuildInfo == null) {
+  private BuildInformation getArchiveBuildInformation() {
+    if (archiveBuildInfo == null) {
       if (currentProgressStep.ordinal() >
               ReversionProgressStep.REVERTING_FILESYSTEM.ordinal()) {
         try {
-          toBuildInfo = installation.getBuildInformation(false);
+          archiveBuildInfo = installation.getBuildInformation(false);
         } catch (ApplicationException e) {
-          LOG.log(Level.INFO, "Failed to obtain 'from' build information", e);
+          LOG.log(Level.INFO, "Failed to obtain archived build information " +
+                  "from reverted files", e);
         }
       } else {
-        // TODO: try to determine build info from backed up bits
+
+        Installation archiveInstall = null;
+        try {
+          archiveInstall = getArchiveInstallation();
+          archiveBuildInfo = archiveInstall.getBuildInformation();
+        } catch (Exception e) {
+          LOG.log(Level.INFO, "Failed to obtain archived build information " +
+                  "from archived files", e);
+        }
       }
     }
-    return toBuildInfo;
+    return archiveBuildInfo;
   }
 
   private Message getFinalSuccessMessage() {
@@ -706,5 +899,75 @@
     return txt;
   }
 
+  /**
+   * Given the current information, determines whether or not
+   * a reversion from the current version to the archived version
+   * is possible.  Reversion may not be possible due to 'flag
+   * day' types of changes to the codebase.
+   * @throws org.opends.quicksetup.ApplicationException if revertability
+   *         cannot be insured.
+   */
+  private void insureRevertability() throws ApplicationException {
+    BuildInformation currentVersion;
+    BuildInformation newVersion;
+    try {
+      currentVersion = getInstallation().getBuildInformation();
+    } catch (ApplicationException e) {
+      LOG.log(Level.INFO, "Error getting build information for " +
+              "current installation", e);
+      throw ApplicationException.createFileSystemException(
+              INFO_ERROR_DETERMINING_CURRENT_BUILD.get(), e);
+    }
+
+    try {
+      Installation revInstallation = getArchiveInstallation();
+      newVersion = revInstallation.getBuildInformation();
+    } catch (ApplicationException ae) {
+      throw ae;
+    } catch (Exception e) {
+      LOG.log(Level.INFO, "Error getting build information for " +
+              "staged installation", e);
+      throw ApplicationException.createFileSystemException(
+              INFO_ERROR_DETERMINING_REVERSION_BUILD.get(), e);
+    }
+
+    if (currentVersion != null && newVersion != null) {
+      ReversionIssueNotifier uo = new ReversionIssueNotifier(
+              userInteraction(), currentVersion, newVersion);
+      uo.notifyUser();
+      if (uo.noServerStartFollowingOperation()) {
+        // Some issue dicatates that we don't try and restart the server
+        // after this operation.  It may be that the databases are no
+        // longer readable after the reversion or something equally earth
+        // shattering.
+        getUserData().setStartServer(false);
+      }
+    } else {
+      LOG.log(Level.INFO, "Did not run reversion issue notifier due to " +
+              "incomplete build information");
+    }
+  }
+
+  private Installation getArchiveInstallation()
+          throws ApplicationException, IOException
+  {
+    if (archiveInstallation == null) {
+      File revFiles = getReversionFilesDirectory();
+      archiveInstallation = new Installation(revFiles);
+    }
+    return archiveInstallation;
+  }
+
+  private File appendFilesDirIfNeccessary(File archiveDir) {
+    if (archiveDir != null) {
+      // Automatically append the 'filesDir' subdirectory if necessary
+      if (!archiveDir.getName().
+              endsWith(Installation.HISTORY_BACKUP_FILES_DIR_NAME)) {
+        archiveDir = new File(archiveDir,
+                Installation.HISTORY_BACKUP_FILES_DIR_NAME);
+      }
+    }
+    return archiveDir;
+  }
 
 }
diff --git a/opends/src/quicksetup/org/opends/quicksetup/upgrader/ReverterUserData.java b/opends/src/quicksetup/org/opends/quicksetup/upgrader/ReverterUserData.java
index 9f26da1..363543e 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/upgrader/ReverterUserData.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/upgrader/ReverterUserData.java
@@ -36,22 +36,42 @@
  */
 class ReverterUserData extends UserData {
 
-  File filesDir = null;
+  /** Directory where the reversion archive lives. */
+  private File reversionArchiveDir = null;
+
+  /** Indicates that we are reverting to the most recent version. */
+  private boolean mostRecent;
 
   /**
    * Gets the directory where the files are stored for the reversion.
    * @return File where the reversion files are kept
    */
-  public File getFilesDirectory() {
-    return filesDir;
+  public File getReversionArchiveDirectory() {
+    return reversionArchiveDir;
   }
 
   /**
    * 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;
+  public void setReversionArchiveDirectory(File files) {
+    this.reversionArchiveDir = files;
+  }
+
+  /**
+   * Sets whether or not we will be reverting to the most recent version.
+   * @param mostRecent version or not
+   */
+  public void setRevertMostRecent(boolean mostRecent) {
+    this.mostRecent = mostRecent;
+  }
+
+  /**
+   * Indicates whether or not we will be reverting to the most recent version.
+   * @return boolean where true means revert to the most recent version
+   */
+  public boolean isRevertMostRecent() {
+    return this.mostRecent;
   }
 
 }
diff --git a/opends/src/quicksetup/org/opends/quicksetup/upgrader/UpgradeIssueNotifier.java b/opends/src/quicksetup/org/opends/quicksetup/upgrader/UpgradeIssueNotifier.java
index a9b61d6..c245ed7 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/upgrader/UpgradeIssueNotifier.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/upgrader/UpgradeIssueNotifier.java
@@ -30,7 +30,7 @@
 import org.opends.messages.Message;
 import org.opends.messages.MessageBuilder;
 
-import org.opends.quicksetup.ApplicationReturnCode;
+import org.opends.quicksetup.ReturnCode;
 import org.opends.quicksetup.BuildInformation;
 import org.opends.quicksetup.UserInteraction;
 import org.opends.quicksetup.ApplicationException;
@@ -83,7 +83,7 @@
           }
         }
         throw new ApplicationException(
-            ApplicationReturnCode.ReturnCode.APPLICATION_ERROR,
+            ReturnCode.APPLICATION_ERROR,
                 INFO_UPGRADE_ORACLE_UNSUPPORTED.get(
                         currentBuildInfo.toString(),
                         newBuildInfo.toString()),
@@ -147,13 +147,13 @@
                     new Message[]{cont, cancel},
                     defaultAction))) {
               throw new ApplicationException(
-                  ApplicationReturnCode.ReturnCode.CANCELLED,
+                  ReturnCode.CANCELLED,
                       INFO_UPGRADE_CANCELED.get(), null);
             }
           }
         } else {
           throw new ApplicationException(
-              ApplicationReturnCode.ReturnCode.APPLICATION_ERROR,
+              ReturnCode.APPLICATION_ERROR,
               INFO_ORACLE_NO_SILENT.get(), null);
         }
       }
diff --git a/opends/src/quicksetup/org/opends/quicksetup/upgrader/UpgradeLauncher.java b/opends/src/quicksetup/org/opends/quicksetup/upgrader/UpgradeLauncher.java
index 6e4aad4..4c6dd35 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/upgrader/UpgradeLauncher.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/upgrader/UpgradeLauncher.java
@@ -37,12 +37,14 @@
 import org.opends.quicksetup.CliApplication;
 import org.opends.quicksetup.Installation;
 import org.opends.quicksetup.QuickSetupLog;
+import org.opends.quicksetup.ReturnCode;
 
 import org.opends.quicksetup.util.Utils;
 import org.opends.server.util.ServerConstants;
 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.args.ArgumentException;
+import org.opends.server.util.args.StringArgument;
 
 import java.util.logging.Logger;
 import java.io.File;
@@ -65,6 +67,24 @@
   /** Long form of the option for specifying the installation package file. */
   static public final String FILE_OPTION_LONG = "file";
 
+  /** Short form of the option for specifying the reversion files directory. */
+  static public final Character REVERT_ARCHIVE_OPTION_SHORT = 'a';
+
+  /** Long form of the option for specifying the reversion files directory. */
+  static public final String REVERT_ARCHIVE_OPTION_LONG = "reversionArchive";
+
+  /** Short form of the option for specifying the 'most recent' option. */
+  static public final Character REVERT_MOST_RECENT_OPTION_SHORT = 'r';
+
+  /** Long form of the option for specifying the 'most recent' option. */
+  static public final String REVERT_MOST_RECENT_OPTION_LONG ="revertMostRecent";
+
+  /** Indicates that this operation is an upgrade as opposed to reversion. */
+  protected boolean isUpgrade;
+
+  /** Indicates that this operation is a reversion as opposed to an upgrade. */
+  protected boolean isReversion;
+
   /**
    * The main method which is called by the setup command lines.
    *
@@ -84,6 +104,14 @@
 
   private ArgumentParser argParser;
 
+  private BooleanArgument showUsage;
+  private StringArgument file;
+  private BooleanArgument quiet;
+  private BooleanArgument noPrompt;
+  private BooleanArgument revertMostRecent;
+  private StringArgument reversionArchive;
+
+
   /**
    * {@inheritDoc}
    */
@@ -158,6 +186,94 @@
   }
 
   /**
+   * Indicates whether or not this operation is silent.
+   * @return boolean where true indicates silence
+   */
+  public boolean isQuiet() {
+    return quiet.isPresent();
+  }
+
+  /**
+   * Indicates whether or not this operation is interactive.
+   * @return boolean where true indicates noninteractive
+   */
+  public boolean isNoPrompt() {
+    return noPrompt.isPresent();
+  }
+
+  /**
+   * Indicates whether this invocation is intended to upgrade the current
+   * build as opposed to revert.
+   * @return boolean where true indicates upgrade
+   */
+  public boolean isUpgrade() {
+    return isUpgrade;
+  }
+
+  /**
+   * Indicates whether this invocation is intended to revert the current
+   * build as opposed to upgrade.
+   * @return boolean where true indicates revert
+   */
+  public boolean isReversion() {
+    return isReversion;
+  }
+
+  /**
+   * Indicates that none of the options that indicate an upgrade
+   * or reversion where specified on the command line so we are going
+   * to have to prompt for the information or fail.
+   *
+   * @return boolean where true means this application needs to ask
+   *         the user which operation they would like to perform; false
+   *         means no further input is required
+   */
+  public boolean isInteractive() {
+    return !file.isPresent() &&
+            !reversionArchive.isPresent() &&
+            !revertMostRecent.isPresent();
+  }
+
+  /**
+   * Gets the name of the file to be used for upgrade.
+   * @return name of the upgrade file
+   */
+  public String getUpgradeFileName() {
+    return file.getValue();
+  }
+
+  /**
+   * Gets the name of the directory to be used for reversion.
+   * @return name of the reversion directory
+   */
+  public String getReversionArchiveDirectoryName() {
+    return reversionArchive.getValue();
+  }
+
+
+  /**
+   * Gets the file's directory if specified on the command line.
+   * @return File representing the directory where the reversion files are
+   * stored.
+   */
+  public File getReversionArchiveDirectory() {
+    File f = null;
+    String s = reversionArchive.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 isRevertMostRecent() {
+    return revertMostRecent.isPresent();
+  }
+
+  /**
    * Creates an instance.
    *
    * @param args specified on command line
@@ -175,37 +291,86 @@
 
     argParser = new ArgumentParser(getClass().getName(),
         INFO_UPGRADE_LAUNCHER_USAGE_DESCRIPTION.get(), false);
-    BooleanArgument showUsage;
-    FileBasedArgument file;
-    BooleanArgument quiet;
-    BooleanArgument noPrompt;
     try
     {
-      file = new FileBasedArgument(
-              "file",
+      file = new StringArgument(
+              FILE_OPTION_LONG,
               FILE_OPTION_SHORT,
               FILE_OPTION_LONG,
-              false, false,
+              false, false, true,
               "{file}",
               null, null, INFO_UPGRADE_DESCRIPTION_FILE.get());
       argParser.addArgument(file);
+
+      revertMostRecent = new BooleanArgument(
+              REVERT_MOST_RECENT_OPTION_LONG,
+              REVERT_MOST_RECENT_OPTION_SHORT,
+              REVERT_MOST_RECENT_OPTION_LONG,
+              INFO_REVERT_DESCRIPTION_RECENT.get());
+      argParser.addArgument(revertMostRecent);
+
+      reversionArchive = new StringArgument(
+              REVERT_ARCHIVE_OPTION_LONG,
+              REVERT_ARCHIVE_OPTION_SHORT,
+              REVERT_ARCHIVE_OPTION_LONG,
+              false, false, true,
+              "{directory}",
+              null, null, INFO_REVERT_DESCRIPTION_DIRECTORY.get());
+      argParser.addArgument(reversionArchive);
+
       noPrompt = new BooleanArgument(
-          OPTION_LONG_NO_PROMPT,
-          OPTION_SHORT_NO_PROMPT,
-          OPTION_LONG_NO_PROMPT,
-          INFO_UPGRADE_DESCRIPTION_NO_PROMPT.get());
+              OPTION_LONG_NO_PROMPT,
+              OPTION_SHORT_NO_PROMPT,
+              OPTION_LONG_NO_PROMPT,
+              INFO_UPGRADE_DESCRIPTION_NO_PROMPT.get());
       argParser.addArgument(noPrompt);
+
       quiet = new BooleanArgument(
-          OPTION_LONG_QUIET,
-          OPTION_SHORT_QUIET,
-          OPTION_LONG_QUIET,
-          INFO_UPGRADE_DESCRIPTION_SILENT.get());
+              OPTION_LONG_QUIET,
+              OPTION_SHORT_QUIET,
+              OPTION_LONG_QUIET,
+              INFO_UPGRADE_DESCRIPTION_SILENT.get());
       argParser.addArgument(quiet);
-      showUsage = new BooleanArgument("showusage", OPTION_SHORT_HELP,
-        OPTION_LONG_HELP,
-        INFO_DESCRIPTION_USAGE.get());
+
+      showUsage = new BooleanArgument(
+              "showusage",
+              OPTION_SHORT_HELP,
+              OPTION_LONG_HELP,
+              INFO_DESCRIPTION_USAGE.get());
       argParser.addArgument(showUsage);
       argParser.setUsageArgument(showUsage);
+
+      try {
+        argParser.parseArguments(args);
+
+        // Set fields indicating reversion or upgrade.  This may change
+        // later if interaction is required to make the determination.
+        isUpgrade = file.isPresent();
+        isReversion =
+                reversionArchive.isPresent() || revertMostRecent.isPresent();
+
+        if (showUsage.isPresent()) {
+          argParser.getUsage(System.out);
+          System.exit(ReturnCode.PRINT_USAGE.getReturnCode());
+        } else if (isUpgrade) {
+          if (reversionArchive.isPresent()) {
+            System.err.println(ERR_UPGRADE_INCOMPATIBLE_ARGS.get(
+                    file.getName(), reversionArchive.getName()));
+            System.exit(ReturnCode.
+                    APPLICATION_ERROR.getReturnCode());
+          } else if (revertMostRecent.isPresent()) {
+            System.err.println(ERR_UPGRADE_INCOMPATIBLE_ARGS.get(
+                    file.getName(), revertMostRecent.getName()));
+            System.exit(ReturnCode.
+                    APPLICATION_ERROR.getReturnCode());
+
+          }
+        }
+      } catch (ArgumentException ae) {
+        System.err.println(ae.getMessageObject());
+        System.exit(ReturnCode.
+                APPLICATION_ERROR.getReturnCode());
+      }
     }
     catch (Throwable t)
     {
diff --git a/opends/src/quicksetup/org/opends/quicksetup/upgrader/UpgradeUserData.java b/opends/src/quicksetup/org/opends/quicksetup/upgrader/UpgradeUserData.java
index aa2a7eb..0e50637 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/upgrader/UpgradeUserData.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/upgrader/UpgradeUserData.java
@@ -36,9 +36,14 @@
  */
 public class UpgradeUserData extends UserData {
 
-  File installPackage;
+  /** Describes upgrade operation type. */
+  public enum Operation { UPGRADE, REVERSION };
 
-  Build buildToDownload;
+  private File installPackage;
+
+  private Build buildToDownload;
+
+  private Operation operation;
 
   /**
    * Gets the OpenDS package (.zip) file whose contents will
@@ -87,4 +92,20 @@
     return false;
   }
 
+  /**
+   * Sets the operation the user would like to perform.
+   * @param operation upgrade or reversion
+   */
+  public void setOperation(Operation operation) {
+    this.operation = operation;
+  }
+
+  /**
+   * Gets the operation the user would like to perform.
+   * @return operation upgrade or reversion
+   */
+  public Operation getOperation() {
+    return this.operation;
+  }
+
 }
diff --git a/opends/src/quicksetup/org/opends/quicksetup/upgrader/Upgrader.java b/opends/src/quicksetup/org/opends/quicksetup/upgrader/Upgrader.java
index 549819d..d9d8a5a 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/upgrader/Upgrader.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/upgrader/Upgrader.java
@@ -33,7 +33,7 @@
 import org.opends.messages.Message;
 import org.opends.messages.MessageBuilder;
 
-import org.opends.quicksetup.ApplicationReturnCode;
+import org.opends.quicksetup.ReturnCode;
 import org.opends.quicksetup.WizardStep;
 import org.opends.quicksetup.ProgressStep;
 import org.opends.quicksetup.ApplicationException;
@@ -782,7 +782,7 @@
                   "Error starting server in order to apply custom" +
                           "schema and/or configuration", e);
           throw new ApplicationException(
-              ApplicationReturnCode.ReturnCode.APPLICATION_ERROR,
+              ReturnCode.APPLICATION_ERROR,
               INFO_ERROR_STARTING_SERVER.get(), e);
         }
 
@@ -833,7 +833,7 @@
           LOG.log(Level.INFO, "server stopped");
         } catch (Throwable t) {
           LOG.log(Level.INFO, "Error stopping server", t);
-          throw new ApplicationException(ApplicationReturnCode.ReturnCode.BUG,
+          throw new ApplicationException(ReturnCode.BUG,
                   INFO_ERROR_STOPPING_SERVER.get(), t);
         }
       }
@@ -850,12 +850,20 @@
                 null, INFO_ERROR_ARTIFICIAL.get(), null);
       }
 
-      LOG.log(Level.INFO, "verifying upgrade");
-      setCurrentProgressStep(UpgradeProgressStep.VERIFYING);
-      Installation installation = getInstallation();
-      ServerHealthChecker healthChecker = new ServerHealthChecker(installation);
-      healthChecker.checkServer();
-      List<Message> errors = healthChecker.getProblemMessages();
+      List<Message> errors;
+      try {
+        LOG.log(Level.INFO, "verifying upgrade");
+        setCurrentProgressStep(UpgradeProgressStep.VERIFYING);
+        Installation installation = getInstallation();
+        ServerHealthChecker healthChecker =
+                new ServerHealthChecker(installation);
+        healthChecker.checkServer();
+        errors = healthChecker.getProblemMessages();
+      } catch (Exception e) {
+        LOG.log(Level.INFO, "error performing server health check", e);
+        notifyListeners(getFormattedErrorWithLineBreak());
+        throw e;
+      }
 
       // For testing
       if ("true".equals(
@@ -873,7 +881,7 @@
                 Utils.listToMessage(errors,
                         Constants.LINE_SEPARATOR, /*bullet=*/"\u2022 ", "");
         ApplicationException ae = new ApplicationException(
-                ApplicationReturnCode.ReturnCode.APPLICATION_ERROR,
+                ReturnCode.APPLICATION_ERROR,
                 INFO_ERROR_UPGRADED_SERVER_STARTS_WITH_ERRORS.get(
                         Constants.LINE_SEPARATOR + formattedDetails), null);
         UserInteraction ui = userInteraction();
@@ -928,7 +936,7 @@
             int port = getInstallation().getCurrentConfiguration().getPort();
             if (port != -1 && !Utils.canUseAsPort(port)) {
               throw new ApplicationException(
-                  ApplicationReturnCode.ReturnCode.APPLICATION_ERROR,
+                  ReturnCode.APPLICATION_ERROR,
                       INFO_ERROR_PORT_IN_USE.get(Integer.toString(port)),
                       null);
             }
@@ -954,7 +962,7 @@
       } catch (IOException ioe) {
         LOG.log(Level.INFO, "error determining if server running");
         this.runWarning = new ApplicationException(
-            ApplicationReturnCode.ReturnCode.TOOL_ERROR,
+            ReturnCode.TOOL_ERROR,
                 INFO_ERROR_SERVER_STATUS.get(), ioe);
       }
 
@@ -962,7 +970,7 @@
 
       // We don't consider a  user cancelation exception
       // to be an error.
-      if (ae.getType() != ApplicationReturnCode.ReturnCode.CANCELLED) {
+      if (ae.getType() != ReturnCode.CANCELLED) {
         this.runError = ae;
       } else {
         this.abort = true;
@@ -970,7 +978,7 @@
 
     } catch (Throwable t) {
       this.runError =
-              new ApplicationException(ApplicationReturnCode.ReturnCode.BUG,
+              new ApplicationException(ReturnCode.BUG,
                       INFO_BUG_MSG.get(), t);
     } finally {
       try {
@@ -1087,7 +1095,7 @@
 
   private void checkAbort() throws ApplicationException {
     if (abort) throw new ApplicationException(
-        ApplicationReturnCode.ReturnCode.CANCELLED,
+        ReturnCode.CANCELLED,
             INFO_UPGRADE_CANCELED.get(), null);
   }
 
@@ -1222,7 +1230,7 @@
       throw ae;
     } catch (Exception e) {
       throw new ApplicationException(
-          ApplicationReturnCode.ReturnCode.FILE_SYSTEM_ACCESS_ERROR,
+          ReturnCode.FILE_SYSTEM_ACCESS_ERROR,
               INFO_ERROR_BACKUP_FILESYSTEM.get(),
               e);
     }
@@ -1235,7 +1243,7 @@
       int ret = output.getReturnCode();
       if (ret != 0) {
         throw new ApplicationException(
-            ApplicationReturnCode.ReturnCode.TOOL_ERROR,
+            ReturnCode.TOOL_ERROR,
                 INFO_ERROR_BACKUP_DB_TOOL_RETURN_CODE.get(
                         Integer.toString(ret)),
                 null);
@@ -1245,7 +1253,7 @@
       throw ae;
     } catch (Exception e) {
       throw new ApplicationException(
-          ApplicationReturnCode.ReturnCode.TOOL_ERROR,
+          ReturnCode.TOOL_ERROR,
               INFO_ERROR_BACKUP_DB.get(), e);
     }
   }
@@ -1292,7 +1300,7 @@
       throw ae;
     } catch (Exception e) {
       throw new ApplicationException(
-          ApplicationReturnCode.ReturnCode.FILE_SYSTEM_ACCESS_ERROR,
+          ReturnCode.FILE_SYSTEM_ACCESS_ERROR,
               INFO_ERROR_INITIALIZING_UPGRADE.get(), e);
     }
   }
@@ -1370,11 +1378,11 @@
 
   /**
    * {@inheritDoc}
-   * @param launcher
    */
   public UserData createUserData(Launcher launcher)
           throws UserDataException {
-    return getCliHelper().createUserData(launcher.getArguments());
+    return new UpgraderCliHelper((UpgradeLauncher) launcher).
+            createUserData(launcher.getArguments());
   }
 
   /**
@@ -1384,6 +1392,13 @@
     return runError;
   }
 
+  /**
+   * {@inheritDoc}
+   */
+  public ReturnCode getReturnCode() {
+    return null;
+  }
+
   private void setCurrentProgressStep(UpgradeProgressStep step) {
     this.currentProgressStep = step;
     int progress = step.getProgress();
@@ -1391,13 +1406,6 @@
     notifyListeners(progress, msg, getFormattedProgress(msg));
   }
 
-  private UpgraderCliHelper getCliHelper() {
-    if (cliHelper == null) {
-      cliHelper = new UpgraderCliHelper();
-    }
-    return cliHelper;
-  }
-
   private Message getFinalSuccessMessage() {
     Message txt;
     String installPath = Utils.getPath(getInstallation().getRootDirectory());
diff --git a/opends/src/quicksetup/org/opends/quicksetup/upgrader/UpgraderCliHelper.java b/opends/src/quicksetup/org/opends/quicksetup/upgrader/UpgraderCliHelper.java
index 1949ac8..20d8945 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/upgrader/UpgraderCliHelper.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/upgrader/UpgraderCliHelper.java
@@ -27,16 +27,9 @@
 
 package org.opends.quicksetup.upgrader;
 
-import org.opends.messages.Message;
-import static org.opends.messages.QuickSetupMessages.*;
-
 import org.opends.quicksetup.CliApplicationHelper;
 import org.opends.quicksetup.UserDataException;
-import org.opends.server.util.args.ArgumentParser;
-import org.opends.server.util.args.StringArgument;
-import org.opends.server.util.args.ArgumentException;
 
-import java.util.logging.Level;
 import java.util.logging.Logger;
 
 /**
@@ -47,14 +40,17 @@
   static private final Logger LOG =
           Logger.getLogger(UpgraderCliHelper.class.getName());
 
-  StringArgument localInstallPackFileNameArg = null;
+  /** Launcher for this CLI invocation. */
+  protected UpgradeLauncher launcher;
 
   /**
-   * Default constructor.
+   * Creates a parameterized instance.
+   * @param launcher for this CLI
    */
-  public UpgraderCliHelper()
+  public UpgraderCliHelper(UpgradeLauncher launcher)
   {
     super(System.out, System.err, System.in);
+    this.launcher = launcher;
   }
 
   /**
@@ -66,47 +62,14 @@
    */
   public UpgradeUserData createUserData(String[] args)
     throws UserDataException {
+    // It is assumed that if we got here that the build
+    // exptractor took care of extracting the file and
+    // putting it in tmp/upgrade for us.  So there's
+    // not too much to do at this point.
     UpgradeUserData uud = new UpgradeUserData();
-    ArgumentParser ap = createArgumentParser();
-    try {
-      ap.parseArguments(args);
-      uud.setQuiet(isQuiet());
-      uud.setInteractive(isInteractive());
-
-      // There is no need to check/validate the file argument
-      // since this is done by the BuildExtractor
-
-    } catch (ArgumentException e) {
-      throw new UserDataException(null, INFO_ERROR_PARSING_OPTIONS.get());
-    }
+    uud.setQuiet(launcher.isQuiet());
+    uud.setInteractive(!launcher.isNoPrompt());
     return uud;
   }
 
-  private ArgumentParser createArgumentParser() {
-
-    // TODO: get rid of this method and user launcher.getArgumentParser
-
-    Message toolDescription = INFO_UPGRADE_LAUNCHER_DESCRIPTION.get();
-    ArgumentParser argParser = createArgumentParser(
-            "org.opends.quicksetup.upgrader.Upgrader",
-            toolDescription,
-            false);
-
-    // Initialize all the app specific command-line argument types
-    // and register them with the parser.
-    try {
-      localInstallPackFileNameArg =
-              new StringArgument("install package file",
-                      UpgradeLauncher.FILE_OPTION_SHORT,
-                      UpgradeLauncher.FILE_OPTION_LONG,
-                      false, true, "{install package file}", null);
-      argParser.addArgument(localInstallPackFileNameArg);
-    } catch (ArgumentException e) {
-      LOG.log(Level.INFO, "error", e);
-    }
-
-    return argParser;
-  }
-
-
 }
diff --git a/opends/src/quicksetup/org/opends/quicksetup/util/FileManager.java b/opends/src/quicksetup/org/opends/quicksetup/util/FileManager.java
index ffdd099..8379c04 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/util/FileManager.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/util/FileManager.java
@@ -162,14 +162,14 @@
         if (target.exists()) {
           if (!target.delete()) {
             throw new ApplicationException(
-                    ApplicationReturnCode.ReturnCode.FILE_SYSTEM_ACCESS_ERROR,
+                    ReturnCode.FILE_SYSTEM_ACCESS_ERROR,
                     INFO_ERROR_DELETING_FILE.get(Utils.getPath(target)), null);
           }
         }
       }
       if (!fileToRename.renameTo(target)) {
         throw new ApplicationException(
-                ApplicationReturnCode.ReturnCode.FILE_SYSTEM_ACCESS_ERROR,
+                ReturnCode.FILE_SYSTEM_ACCESS_ERROR,
                 INFO_ERROR_RENAMING_FILE.get(Utils.getPath(fileToRename),
                         Utils.getPath(target)), null);
       }
@@ -525,7 +525,7 @@
                       objectFile.getAbsolutePath(),
                       destination.getAbsolutePath());
               throw new ApplicationException(
-                      ApplicationReturnCode.ReturnCode.FILE_SYSTEM_ACCESS_ERROR,
+                      ReturnCode.FILE_SYSTEM_ACCESS_ERROR,
                       errMsg, null);
             } finally {
               if (fis != null) {
@@ -548,7 +548,7 @@
                     objectFile.getAbsolutePath(),
                     destination.getAbsolutePath());
             throw new ApplicationException(
-                    ApplicationReturnCode.ReturnCode.FILE_SYSTEM_ACCESS_ERROR,
+                    ReturnCode.FILE_SYSTEM_ACCESS_ERROR,
                     errMsg, null);
           }
         } else {
@@ -654,7 +654,7 @@
           errMsg = INFO_ERROR_DELETING_DIRECTORY.get(file.getAbsolutePath());
         }
         throw new ApplicationException(
-                ApplicationReturnCode.ReturnCode.FILE_SYSTEM_ACCESS_ERROR,
+                ReturnCode.FILE_SYSTEM_ACCESS_ERROR,
                 errMsg, null);
       }
 
diff --git a/opends/src/quicksetup/org/opends/quicksetup/util/InProcessServerController.java b/opends/src/quicksetup/org/opends/quicksetup/util/InProcessServerController.java
index 23dcff7..565f1e1 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/util/InProcessServerController.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/util/InProcessServerController.java
@@ -60,10 +60,12 @@
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
 import org.opends.server.protocols.ldap.LDAPAttribute;
+import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.core.ModifyOperation;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.core.AddOperation;
 import org.opends.server.core.DeleteOperation;
+import org.opends.server.core.CompareOperation;
 import org.opends.server.config.ConfigException;
 
 import java.util.logging.Logger;
@@ -416,7 +418,7 @@
           // report the error to the user
           MessageBuilder error = op.getErrorMessage();
           throw new ApplicationException(
-              ApplicationReturnCode.ReturnCode.IMPORT_ERROR,
+              ReturnCode.IMPORT_ERROR,
                   INFO_ERROR_APPLY_LDIF_MODIFY.get(dnByteString.toString(),
                           error != null ? error.toString() : ""),
                   null);
@@ -435,6 +437,29 @@
         rc = addOp.getResultCode();
         if (rc.equals(ResultCode.SUCCESS)) {
           LOG.log(Level.INFO, "processed server add " + addOp.getEntryDN());
+        } else if (rc.equals(ResultCode.ENTRY_ALREADY_EXISTS)) {
+          // Compare the attributes with the existing entry to see if we
+          // can ignore this add.
+          boolean ignore = true;
+          for (RawAttribute attr : rawAttrs) {
+            ArrayList<ASN1OctetString> values = attr.getValues();
+            for (ASN1OctetString value : values) {
+              CompareOperation compOp =
+                cc.processCompare(dnByteString, attr.getAttributeType(), value);
+              if (ResultCode.ASSERTION_FAILED.equals(compOp.getResultCode())) {
+                ignore = false;
+                break;
+              }
+            }
+          }
+          if (!ignore) {
+            MessageBuilder error = addOp.getErrorMessage();
+            throw new ApplicationException(
+                ReturnCode.IMPORT_ERROR,
+                    INFO_ERROR_APPLY_LDIF_ADD.get(dnByteString.toString(),
+                            error != null ? error.toString() : ""),
+                    null);
+          }
         } else {
           boolean ignore = false;
 
@@ -471,7 +496,7 @@
           if (!ignore) {
             MessageBuilder error = addOp.getErrorMessage();
             throw new ApplicationException(
-                    ApplicationReturnCode.ReturnCode.IMPORT_ERROR,
+                    ReturnCode.IMPORT_ERROR,
                     INFO_ERROR_APPLY_LDIF_ADD.get(dnByteString.toString(),
                             error != null ? error.toString() : ""),
                     null);
@@ -489,7 +514,7 @@
           // report the error to the user
           MessageBuilder error = delOp.getErrorMessage();
           throw new ApplicationException(
-              ApplicationReturnCode.ReturnCode.IMPORT_ERROR,
+              ReturnCode.IMPORT_ERROR,
                   INFO_ERROR_APPLY_LDIF_DELETE.get(dnByteString.toString(),
                           error != null ? error.toString() : ""),
                   null);
@@ -497,7 +522,7 @@
         break;
       default:
         LOG.log(Level.SEVERE, "Unexpected record type " + cre.getClass());
-        throw new ApplicationException(ApplicationReturnCode.ReturnCode.BUG,
+        throw new ApplicationException(ReturnCode.BUG,
                 INFO_BUG_MSG.get(),
                 null);
     }
diff --git a/opends/src/quicksetup/org/opends/quicksetup/util/ServerController.java b/opends/src/quicksetup/org/opends/quicksetup/util/ServerController.java
index 1c80095..820a906 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/util/ServerController.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/util/ServerController.java
@@ -209,7 +209,7 @@
           * not be stopped.
           */
           throw new ApplicationException(
-              ApplicationReturnCode.ReturnCode.STOP_ERROR,
+              ReturnCode.STOP_ERROR,
                   INFO_ERROR_STOPPING_SERVER_CODE.get(
                           String.valueOf(returnValue)),
                   null);
@@ -223,7 +223,7 @@
 
       } catch (Exception e) {
         throw new ApplicationException(
-            ApplicationReturnCode.ReturnCode.STOP_ERROR, getThrowableMsg(
+            ReturnCode.STOP_ERROR, getThrowableMsg(
                 INFO_ERROR_STOPPING_SERVER.get(), e), e);
       }
     } finally {
@@ -442,7 +442,7 @@
           if (Utils.isWindows())
           {
             throw new ApplicationException(
-                ApplicationReturnCode.ReturnCode.START_ERROR,
+                ReturnCode.START_ERROR,
                     INFO_ERROR_STARTING_SERVER_IN_WINDOWS.get(
                             String.valueOf(port)),
                     null);
@@ -450,7 +450,7 @@
           else
           {
             throw new ApplicationException(
-                ApplicationReturnCode.ReturnCode.START_ERROR,
+                ReturnCode.START_ERROR,
                     INFO_ERROR_STARTING_SERVER_IN_UNIX.get(
                             String.valueOf(port)),
                     null);
@@ -461,7 +461,7 @@
     } catch (IOException ioe)
     {
       throw new ApplicationException(
-            ApplicationReturnCode.ReturnCode.START_ERROR,
+            ReturnCode.START_ERROR,
               getThrowableMsg(INFO_ERROR_STARTING_SERVER.get(), ioe), ioe);
     }
   } finally {
@@ -625,7 +625,7 @@
           } catch (Throwable t)
           {
             ex = new ApplicationException(
-                ApplicationReturnCode.ReturnCode.START_ERROR,
+                ReturnCode.START_ERROR,
                 getThrowableMsg(errorTag, t), t);
 
           }
diff --git a/opends/src/quicksetup/org/opends/quicksetup/util/ServerHealthChecker.java b/opends/src/quicksetup/org/opends/quicksetup/util/ServerHealthChecker.java
index 82bb817..2290b3c 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/util/ServerHealthChecker.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/util/ServerHealthChecker.java
@@ -29,7 +29,7 @@
 
 import org.opends.messages.Message;
 
-import org.opends.quicksetup.ApplicationReturnCode;
+import org.opends.quicksetup.ReturnCode;
 import org.opends.quicksetup.Installation;
 import org.opends.quicksetup.ApplicationException;
 
@@ -90,7 +90,7 @@
         throw (ApplicationException)e;
       } else {
         throw new ApplicationException(
-            ApplicationReturnCode.ReturnCode.APPLICATION_ERROR,
+            ReturnCode.APPLICATION_ERROR,
                 INFO_ERROR_SERVER_HEALTH_CHECK_FAILURE.get(), e);
       }
     } finally {
diff --git a/opends/src/quicksetup/org/opends/quicksetup/util/ZipExtractor.java b/opends/src/quicksetup/org/opends/quicksetup/util/ZipExtractor.java
index e13be3b..cb1f029 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/util/ZipExtractor.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/util/ZipExtractor.java
@@ -32,7 +32,7 @@
 
 import org.opends.quicksetup.ApplicationException;
 import org.opends.quicksetup.Application;
-import org.opends.quicksetup.ApplicationReturnCode;
+import org.opends.quicksetup.ReturnCode;
 
 import java.io.*;
 import java.util.zip.ZipInputStream;
@@ -210,7 +210,7 @@
                             INFO_ERROR_COPYING.get(entry.getName()), ioe);
 
             throw new ApplicationException(
-                ApplicationReturnCode.ReturnCode.FILE_SYSTEM_ACCESS_ERROR,
+                ReturnCode.FILE_SYSTEM_ACCESS_ERROR,
                     errorMsg, ioe);
           }
         }
@@ -246,7 +246,7 @@
               Utils.getThrowableMsg(
                       INFO_ERROR_ZIP_STREAM.get(zipFileName), ioe);
       throw new ApplicationException(
-          ApplicationReturnCode.ReturnCode.FILE_SYSTEM_ACCESS_ERROR,
+          ReturnCode.FILE_SYSTEM_ACCESS_ERROR,
           errorMsg, ioe);
     }
   }
diff --git a/opends/src/quicksetup/org/opends/quicksetup/webstart/WebStartDownloader.java b/opends/src/quicksetup/org/opends/quicksetup/webstart/WebStartDownloader.java
index e5ca041..71a4139 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/webstart/WebStartDownloader.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/webstart/WebStartDownloader.java
@@ -39,7 +39,7 @@
 
 
 import org.opends.quicksetup.ApplicationException;
-import org.opends.quicksetup.ApplicationReturnCode;
+import org.opends.quicksetup.ReturnCode;
 import org.opends.server.util.SetupUtils;
 
 import static org.opends.quicksetup.util.Utils.*;
@@ -138,7 +138,7 @@
         {
           // This is a bug
           ex =
-              new ApplicationException(ApplicationReturnCode.ReturnCode.BUG,
+              new ApplicationException(ReturnCode.BUG,
                       getThrowableMsg(INFO_BUG_MSG.get(),mfe), mfe);
         } catch (IOException ioe)
         {
@@ -154,14 +154,14 @@
           }
           ex =
               new ApplicationException(
-              ApplicationReturnCode.ReturnCode.DOWNLOAD_ERROR,
+              ReturnCode.DOWNLOAD_ERROR,
               getThrowableMsg(
                       INFO_DOWNLOADING_ERROR.get(buf.toString()), ioe), ioe);
         } catch (Throwable t)
         {
           // This is a bug
           ex =
-              new ApplicationException(ApplicationReturnCode.ReturnCode.BUG,
+              new ApplicationException(ReturnCode.BUG,
                       getThrowableMsg(INFO_BUG_MSG.get(), t), t);
         }
       }
@@ -366,7 +366,7 @@
   {
     ex =
         new ApplicationException(
-        ApplicationReturnCode.ReturnCode.DOWNLOAD_ERROR,
+        ReturnCode.DOWNLOAD_ERROR,
                 INFO_DOWNLOADING_ERROR.get(url.toString()), null);
   }
 

--
Gitblit v1.10.0