From 02093f726f7582e1ffd6ef12c16caf68451a833d Mon Sep 17 00:00:00 2001
From: kenneth_suter <kenneth_suter@localhost>
Date: Thu, 29 Mar 2007 15:09:14 +0000
Subject: [PATCH] These refactorings are essential in anticipation of a new quicksetup application for the upgrader feature (issue 598).  These changes were reviewed by Josu. 

---
 opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/event/ProgressUpdateListener.java          |    9 
 opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/Installer.java                   |  826 ----------
 opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/ProgressDescriptor.java                    |   14 
 opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/ui/QuickSetupStepPanel.java                |   22 
 opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/uninstaller/UninstallUserData.java         |   36 
 opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/webstart/WebStartDownloader.java |   36 
 opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/DataOptions.java                           |    9 
 opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/offline/OfflineInstaller.java    |   67 
 opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/InstallerHelper.java                       |   87 
 opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/ui/CurrentStepPanel.java                   |   32 
 opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/util/Utils.java                            |    2 
 opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/uninstaller/Uninstaller.java               |  490 +-----
 opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/ui/QuickSetupDialog.java                   |   54 
 opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/ui/LabelFieldDescriptor.java               |    6 
 opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/UserData.java                              |  104 
 opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/uninstaller/UninstallProgressStep.java     |   35 
 opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/util/HtmlProgressMessageFormatter.java     |   24 
 opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/ApplicationException.java                  |   24 
 opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/resources/Resources.properties             |    2 
 opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/Application.java                           |  887 ++++++++++++
 opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/QuickSetupException.java                   |   15 
 opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/ProgressStep.java                          |   27 
 opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/InstallLauncher.java             |    2 
 opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/SplashScreen.java                          |    2 
 opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/ui/DataOptionsPanel.java                   |   13 
 opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/uninstaller/UninstallCli.java              |   98 
 opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/ui/ReviewPanel.java                        |   13 
 opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/webstart/JnlpProperties.java               |    2 
 opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/event/ProgressNotifier.java                |   64 
 opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/uninstaller/UninstallLauncher.java         |    2 
 opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/QuickSetup.java                            |  433 ++---
 opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/util/ZipExtractor.java                     |  296 ++++
 /dev/null                                                                                         |   76 -
 opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/ui/ServerSettingsPanel.java                |   34 
 opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/webstart/WebStartInstaller.java  |  304 ---
 opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/ui/ProgressPanel.java                      |   62 
 opendj-sdk/opends/resource/webstart/create-webstart-standalone.sh                                 |    1 
 opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/InstallProgressStep.java         |   36 
 opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/UserDataException.java                     |   10 
 opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/event/ProgressUpdateEvent.java             |   17 
 40 files changed, 1,990 insertions(+), 2,283 deletions(-)

diff --git a/opendj-sdk/opends/resource/webstart/create-webstart-standalone.sh b/opendj-sdk/opends/resource/webstart/create-webstart-standalone.sh
index b9f0a74..c60ac37 100755
--- a/opendj-sdk/opends/resource/webstart/create-webstart-standalone.sh
+++ b/opendj-sdk/opends/resource/webstart/create-webstart-standalone.sh
@@ -176,6 +176,7 @@
     <jar href="lib/aspectjrt.jar" download="lazy"/>
     <jar href="lib/zipped.jar" download="lazy"/>
     <property name="org.opends.quicksetup.iswebstart" value="true" />
+    <property name="org.opends.quicksetup.Application.class" value="org.opends.quicksetup.installer.webstart.WebStartInstaller"/>
     <property name="org.opends.quicksetup.lazyjarurls" value="${INSTALLER_URI}/lib/OpenDS.jar ${INSTALLER_URI}/lib/zipped.jar ${INSTALLER_URI}/lib/je.jar ${INSTALLER_URI}/lib/aspectjrt.jar" />
     <property name="org.opends.quicksetup.zipfilename" value="${ZIP_FILENAME_BASE}.zip"/>
   </resources>
diff --git a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/Application.java b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/Application.java
new file mode 100644
index 0000000..635eab7
--- /dev/null
+++ b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/Application.java
@@ -0,0 +1,887 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying information:
+ *      Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ *      Portions Copyright 2007 Sun Microsystems, Inc.
+ */
+
+package org.opends.quicksetup;
+
+import org.opends.quicksetup.event.ProgressNotifier;
+import org.opends.quicksetup.event.ProgressUpdateListener;
+import org.opends.quicksetup.event.ProgressUpdateEvent;
+import org.opends.quicksetup.i18n.ResourceProvider;
+import org.opends.quicksetup.util.Utils;
+import org.opends.quicksetup.util.ProgressMessageFormatter;
+
+import javax.naming.NamingException;
+import java.io.*;
+import java.util.*;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * This class represents an application that can be run in the context
+ * of QuickSetup.  Examples of applications might be 'installer',
+ * 'uninstaller' and 'upgrader'.
+ */
+public abstract class Application implements ProgressNotifier, Runnable {
+
+  /**
+   * The path to the Configuration LDIF file.
+   */
+  static protected final String CONFIG_PATH_RELATIVE =
+      "config" + File.separator + "config.ldif";
+
+  static private final Logger LOG =
+          Logger.getLogger(Application.class.getName());
+
+  /**
+   * Creates an application by instantiating the Application class
+   * denoted by the System property
+   * <code>org.opends.quicksetup.Application.class</code>.
+   * @param formatter ProgressMessageFormatter that will be passed to the
+   *                  constructor of Application
+   * @return Application object that was newly instantiated
+   * @throws ApplicationException if there was a problem creating
+   *         the new Application object
+   */
+  static public Application create(ProgressMessageFormatter formatter)
+          throws ApplicationException {
+    Application app;
+    String appClassName =
+            System.getProperty("org.opends.quicksetup.Application.class");
+    if (appClassName != null) {
+      Class appClass = null;
+      try {
+        appClass = Class.forName(appClassName);
+        app = (Application) appClass.newInstance();
+      } catch (ClassNotFoundException e) {
+        LOG.log(Level.INFO, "error creating quicksetup application", e);
+        String msg = "Application class " + appClass + " not found";
+        throw new ApplicationException(ApplicationException.Type.BUG, msg, e);
+      } catch (IllegalAccessException e) {
+        LOG.log(Level.INFO, "error creating quicksetup application", e);
+        String msg = "Could not access class " + appClass;
+        throw new ApplicationException(ApplicationException.Type.BUG, msg, e);
+      } catch (InstantiationException e) {
+        LOG.log(Level.INFO, "error creating quicksetup application", e);
+        String msg = "Error instantiating class " + appClass;
+        throw new ApplicationException(ApplicationException.Type.BUG, msg, e);
+      } catch (ClassCastException e) {
+        String msg = "The class indicated by the system property " +
+                  "'org.opends.quicksetup.Application.class' must " +
+                  " must be of type Application";
+        throw new ApplicationException(ApplicationException.Type.BUG, msg, e);
+      }
+    } else {
+      String msg = "System property 'org.opends.quicksetup.Application.class'" +
+                " must specify class quicksetup application";
+      throw new ApplicationException(ApplicationException.Type.BUG, msg, null);
+    }
+    return app;
+  }
+
+  private HashSet<ProgressUpdateListener> listeners =
+      new HashSet<ProgressUpdateListener>();
+
+  private UserData userData;
+
+  /** Formats progress messages. */
+  protected ProgressMessageFormatter formatter;
+
+  /**
+   * Constructs an instance of an application.  Subclasses
+   * of this application must have a default constructor.
+   */
+  public Application() {
+    // do nothing;
+  }
+
+  /**
+   * Sets this instances user data.
+   * @param userData UserData this application will use
+   *        when executing
+   */
+  public void setUserData(UserData userData) {
+    this.userData = userData;
+  }
+
+  /**
+   * Creates a set of user data with default values.
+   * @return UserData empty set of UserData
+   */
+  public UserData createUserData() {
+    return new UserData();
+  }
+
+  /**
+   * Adds a ProgressUpdateListener that will be notified of updates in
+   * the install progress.
+   * @param l the ProgressUpdateListener to be added.
+   */
+  public void addProgressUpdateListener(ProgressUpdateListener l)
+  {
+    listeners.add(l);
+  }
+
+  /**
+   * Removes a ProgressUpdateListener.
+   * @param l the ProgressUpdateListener to be removed.
+   */
+  public void removeProgressUpdateListener(ProgressUpdateListener l)
+  {
+    listeners.remove(l);
+  }
+
+  /**
+   * Returns whether the installer has finished or not.
+   * @return <CODE>true</CODE> if the install is finished or <CODE>false
+   * </CODE> if not.
+   */
+  public boolean isFinished()
+  {
+    return getStatus().isLast();
+  }
+
+  /**
+   * Returns the UserData object representing the parameters provided by
+   * the user to do the installation.
+   *
+   * @return the UserData object representing the parameters provided
+   * by the user to do the installation.
+   */
+  protected UserData getUserData()
+  {
+    if (userData == null) {
+      userData = createUserData();
+    }
+    return userData;
+  }
+
+  /**
+   * This method notifies the ProgressUpdateListeners that there was an
+   * update in the installation progress.
+   * @param ratioWhenCompleted the integer that specifies which percentage of
+   * the whole installation has been completed.
+   */
+  public void notifyListenersDone(Integer ratioWhenCompleted) {
+    notifyListeners(ratioWhenCompleted,
+            getSummary(getStatus()),
+            formatter.getFormattedDone() + formatter.getLineBreak());
+  }
+
+  /**
+   * This method notifies the ProgressUpdateListeners that there was an
+   * update in the installation progress.
+   * @param ratio the integer that specifies which percentage of
+   * the whole installation has been completed.
+   * @param currentPhaseSummary the localized summary message for the
+   * current installation progress in formatted form.
+   * @param newLogDetail the new log messages that we have for the
+   * installation in formatted form.
+   */
+  public void notifyListeners(Integer ratio, String currentPhaseSummary,
+      String newLogDetail)
+  {
+    ProgressUpdateEvent ev =
+        new ProgressUpdateEvent(getStatus(), ratio, currentPhaseSummary,
+            newLogDetail);
+    for (ProgressUpdateListener l : listeners)
+    {
+      l.progressUpdate(ev);
+    }
+  }
+
+  /**
+   * This method notifies the ProgressUpdateListeners that there was an
+   * update in the installation progress.
+   * @param ratio the integer that specifies which percentage of
+   * the whole installation has been completed.
+   * @param currentPhaseSummary the localized summary message for the
+   * current installation progress in formatted form.
+   */
+  public void notifyListeners(Integer ratio, String currentPhaseSummary) {
+    notifyListeners(ratio, getSummary(getStatus()),
+        formatter.getFormattedWithPoints(currentPhaseSummary));
+  }
+
+  /**
+   * Returns a localized message for a key value.  In  the properties file we
+   * have something of type:
+   * key=value
+   *
+   * @see org.opends.quicksetup.i18n.ResourceProvider#getMsg(String)
+   * @param key the key in the properties file.
+   * @return the value associated to the key in the properties file.
+   * properties file.
+   */
+  protected String getMsg(String key)
+  {
+    return getI18n().getMsg(key);
+  }
+
+  /**
+   * Returns a localized message for a key value.  In  the properties file we
+   * have something of type:
+   * key=value
+   *
+   * For instance if we pass as key "mykey" and as arguments {"value1"} and
+   * in the properties file we have:
+   * mykey=value with argument {0}.
+   *
+   * This method will return "value with argument value1".
+   * @see org.opends.quicksetup.i18n.ResourceProvider#getMsg(String, String[])
+   * @param key the key in the properties file.
+   * @param args the arguments to be passed to generate the resulting value.
+   * @return the value associated to the key in the properties file.
+   */
+  protected String getMsg(String key, String[] args)
+  {
+    return getI18n().getMsg(key, args);
+  }
+
+  /**
+   * Returns a ResourceProvider instance.
+   * @return a ResourceProvider instance.
+   */
+  protected ResourceProvider getI18n()
+  {
+    return ResourceProvider.getInstance();
+  }
+
+  /**
+   * Returns a localized message for a given properties key and throwable.
+   * @param key the key of the message in the properties file.
+   * @param t the throwable for which we want to get a message.
+   * @return a localized message for a given properties key and throwable.
+   */
+  protected String getThrowableMsg(String key, Throwable t)
+  {
+    return getThrowableMsg(key, null, t);
+  }
+
+  /**
+   * Returns a localized message for a given properties key and throwable.
+   * @param key the key of the message in the properties file.
+   * @param args the arguments of the message in the properties file.
+   * @param t the throwable for which we want to get a message.
+   *
+   * @return a localized message for a given properties key and throwable.
+   */
+  protected String getThrowableMsg(String key, String[] args, Throwable t)
+  {
+    return Utils.getThrowableMsg(getI18n(), key, args, t);
+  }
+
+  /**
+   * Sets the formatter this instance should use to used
+   * to format progress messages.
+   * @param formatter ProgressMessageFormatter for formatting
+   * progress messages
+   */
+  public void setProgressMessageFormatter(ProgressMessageFormatter formatter) {
+    this.formatter = formatter;
+  }
+
+  /**
+   * Gets the formatter this instance is currently using.
+   * @return the progress message formatter currently used by this
+   * application
+   */
+  public ProgressMessageFormatter getProgressMessageFormatter() {
+    return formatter;
+  }
+
+  /**
+   * Returns the formatted representation of the text that is the summary of the
+   * installation process (the one that goes in the UI next to the progress
+   * bar).
+   * @param text the source text from which we want to get the formatted
+   * representation
+   * @return the formatted representation of an error for the given text.
+   */
+  protected String getFormattedSummary(String text)
+  {
+    return formatter.getFormattedSummary(text);
+  }
+
+  /**
+   * Returns the formatted representation of an error for a given text.
+   * @param text the source text from which we want to get the formatted
+   * representation
+   * @return the formatted representation of an error for the given text.
+   */
+  protected String getFormattedError(String text)
+  {
+    return formatter.getFormattedError(text, false);
+  }
+
+  /**
+   * Returns the formatted representation of an warning for a given text.
+   * @param text the source text from which we want to get the formatted
+   * representation
+   * @return the formatted representation of an warning for the given text.
+   */
+  protected String getFormattedWarning(String text)
+  {
+    return formatter.getFormattedWarning(text, false);
+  }
+
+  /**
+   * Returns the formatted representation of a success message for a given text.
+   * @param text the source text from which we want to get the formatted
+   * representation
+   * @return the formatted representation of an success message for the given
+   * text.
+   */
+  protected String getFormattedSuccess(String text)
+  {
+    return formatter.getFormattedSuccess(text);
+  }
+
+  /**
+   * Returns the formatted representation of a log error message for a given
+   * text.
+   * @param text the source text from which we want to get the formatted
+   * representation
+   * @return the formatted representation of a log error message for the given
+   * text.
+   */
+  protected String getFormattedLogError(String text)
+  {
+    return formatter.getFormattedLogError(text);
+  }
+
+  /**
+   * Returns the formatted representation of a log message for a given text.
+   * @param text the source text from which we want to get the formatted
+   * representation
+   * @return the formatted representation of a log message for the given text.
+   */
+  protected String getFormattedLog(String text)
+  {
+    return formatter.getFormattedLog(text);
+  }
+
+  /**
+   * Returns the formatted representation of the 'Done' text string.
+   * @return the formatted representation of the 'Done' text string.
+   */
+  protected String getFormattedDone()
+  {
+    return formatter.getFormattedDone();
+  }
+
+  /**
+   * Returns the formatted representation of the argument text to which we add
+   * points.  For instance if we pass as argument 'Configuring Server' the
+   * return value will be 'Configuring Server .....'.
+   * @param text the String to which add points.
+   * @return the formatted representation of the '.....' text string.
+   */
+  protected String getFormattedWithPoints(String text)
+  {
+    return formatter.getFormattedWithPoints(text);
+  }
+
+  /**
+   * Returns the formatted representation of a progress message for a given
+   * text.
+   * @param text the source text from which we want to get the formatted
+   * representation
+   * @return the formatted representation of a progress message for the given
+   * text.
+   */
+  protected String getFormattedProgress(String text)
+  {
+    return formatter.getFormattedProgress(text);
+  }
+
+  /**
+   * Returns the formatted representation of an error message for a given
+   * exception.
+   * This method applies a margin if the applyMargin parameter is
+   * <CODE>true</CODE>.
+   * @param ex the exception.
+   * @param applyMargin specifies whether we apply a margin or not to the
+   * resulting formatted text.
+   * @return the formatted representation of an error message for the given
+   * exception.
+   */
+  protected String getFormattedError(Exception ex, boolean applyMargin)
+  {
+    return formatter.getFormattedError(ex, applyMargin);
+  }
+
+  /**
+   * Returns the line break formatted.
+   * @return the line break formatted.
+   */
+  protected String getLineBreak()
+  {
+    return formatter.getLineBreak();
+  }
+
+  /**
+   * Returns the task separator formatted.
+   * @return the task separator formatted.
+   */
+  protected String getTaskSeparator()
+  {
+    return formatter.getTaskSeparator();
+  }
+
+  /**
+   * This method is called when a new log message has been received.  It will
+   * notify the ProgressUpdateListeners of this fact.
+   * @param newLogDetail the new log detail.
+   */
+  protected void notifyListeners(String newLogDetail)
+  {
+    Integer ratio = getRatio(getStatus());
+    String currentPhaseSummary = getSummary(getStatus());
+    notifyListeners(ratio, currentPhaseSummary, newLogDetail);
+  }
+
+  /**
+   * This methods starts the server.
+   * @throws org.opends.quicksetup.QuickSetupException if something goes wrong.
+   */
+  protected void startServer() throws QuickSetupException {
+    notifyListeners(getFormattedProgress(getMsg("progress-starting")) +
+        getLineBreak());
+
+    ArrayList<String> argList = new ArrayList<String>();
+
+    if (Utils.isWindows())
+    {
+      argList.add(Utils.getPath(getBinariesPath(),
+              Utils.getWindowsStartFileName()));
+    } else
+    {
+      argList.add(Utils.getPath(getBinariesPath(),
+              Utils.getUnixStartFileName()));
+    }
+
+    String[] args = new String[argList.size()];
+    argList.toArray(args);
+    ProcessBuilder pb = new ProcessBuilder(args);
+    Map<String, String> env = pb.environment();
+    env.put("JAVA_HOME", System.getProperty("java.home"));
+    /* Remove JAVA_BIN to be sure that we use the JVM running the installer
+     * JVM to start the server.
+     */
+    env.remove("JAVA_BIN");
+
+    try
+    {
+      String startedId = getStartedId();
+
+      Process process = pb.start();
+
+      BufferedReader err =
+          new BufferedReader(new InputStreamReader(process.getErrorStream()));
+      BufferedReader out =
+          new BufferedReader(new InputStreamReader(process.getInputStream()));
+
+      StartReader errReader = new StartReader(err, startedId, true);
+      StartReader outputReader = new StartReader(out, startedId, false);
+
+      while (!errReader.isFinished() && !outputReader.isFinished())
+      {
+        try
+        {
+          Thread.sleep(100);
+        } catch (InterruptedException ie)
+        {
+        }
+      }
+      // Check if something wrong occurred reading the starting of the server
+      QuickSetupException ex = errReader.getException();
+      if (ex == null)
+      {
+        ex = outputReader.getException();
+      }
+      if (ex != null)
+      {
+        throw ex;
+
+      } else
+      {
+        /*
+         * There are no exceptions from the readers and they are marked as
+         * finished. This means that the server has written in its output the
+         * message id informing that it started. So it seems that everything
+         * went fine.
+         *
+         * However we can have issues with the firewalls or do not have rights
+         * to connect.  Just check if we can connect to the server.
+         * Try 5 times with an interval of 1 second between try.
+         */
+        boolean connected = false;
+        for (int i=0; i<5 && !connected; i++)
+        {
+          String ldapUrl = "ldap://localhost:"+userData.getServerPort();
+          try
+          {
+            Utils.createLdapContext(
+                ldapUrl,
+                userData.getDirectoryManagerDn(),
+                userData.getDirectoryManagerPwd(), 3000, null);
+            connected = true;
+          }
+          catch (NamingException ne)
+          {
+          }
+          if (!connected)
+          {
+            try
+            {
+              Thread.sleep(1000);
+            }
+            catch (Throwable t)
+            {
+            }
+          }
+        }
+        if (!connected)
+        {
+          if (Utils.isWindows())
+          {
+            String[] arg = {String.valueOf(userData.getServerPort())};
+            throw new QuickSetupException(QuickSetupException.Type.START_ERROR,
+                getMsg("error-starting-server-in-windows", arg), null);
+          }
+          else
+          {
+            String[] arg = {String.valueOf(userData.getServerPort())};
+            throw new QuickSetupException(QuickSetupException.Type.START_ERROR,
+                getMsg("error-starting-server-in-unix", arg), null);
+          }
+        }
+      }
+
+    } catch (IOException ioe)
+    {
+      throw new QuickSetupException(QuickSetupException.Type.START_ERROR,
+          getThrowableMsg("error-starting-server", ioe), ioe);
+    }
+  }
+
+  /**
+   * Returns the installation path.
+   * @return the installation path.
+   */
+  protected abstract String getInstallationPath();
+
+  /**
+   * Returns the config file path.
+   * @return the config file path.
+   */
+  protected String getConfigFilePath()
+  {
+    return Utils.getPath(getInstallationPath(), CONFIG_PATH_RELATIVE);
+  }
+
+  /**
+   * Returns the path to the binaries.
+   * @return the path to the binaries.
+   */
+  protected abstract String getBinariesPath();
+
+  /**
+   * Returns the Message ID indicating that the server has started.
+   * @return the Message ID indicating that the server has started.
+   */
+  private String getStartedId()
+  {
+    InstallerHelper helper = new InstallerHelper();
+    return helper.getStartedId();
+  }
+
+  /**
+   * Returns the tab formatted.
+   * @return the tab formatted.
+   */
+  protected String getTab()
+  {
+    return formatter.getTab();
+  }
+
+  /**
+   * Returns the path to the libraries.
+   * @return the path to the libraries.
+   */
+  protected String getLibrariesPath()
+  {
+    return Utils.getPath(Utils.getInstallPathFromClasspath(),
+        Utils.getLibrariesRelativePath());
+  }
+
+  /**
+   * Gets the current step.
+   * @return ProgressStep representing the current step
+   */
+  public abstract ProgressStep getStatus();
+
+  /**
+   * Gets an integer representing the amount of processing
+   * this application still needs to perform as a ratio
+   * out of 100.
+   * @param step ProgressStop for which a summary is needed
+   * @return ProgressStep representing the current step
+   */
+  public abstract Integer getRatio(ProgressStep step);
+
+  /**
+   * Gets an i18n'd string representing the summary of
+   * a give ProgressStep.
+   * @param step ProgressStop for which a summary is needed
+   * @return String representing the summary
+   */
+  public abstract String getSummary(ProgressStep step);
+
+  /**
+   * This class is used to read the standard error and standard output of the
+   * Start process.
+   *
+   * When a new log message is found notifies the ProgressUpdateListeners
+   * of it. If an error occurs it also notifies the listeners.
+   *
+   */
+  private class StartReader
+  {
+    private QuickSetupException ex;
+
+    private boolean isFinished;
+
+    private boolean isFirstLine;
+
+    /**
+     * The protected constructor.
+     * @param reader the BufferedReader of the start process.
+     * @param startedId the message ID that this class can use to know whether
+     * the start is over or not.
+     * @param isError a boolean indicating whether the BufferedReader
+     * corresponds to the standard error or to the standard output.
+     */
+    public StartReader(final BufferedReader reader, final String startedId,
+        final boolean isError)
+    {
+      final String errorTag =
+          isError ? "error-reading-erroroutput" : "error-reading-output";
+
+      isFirstLine = true;
+
+      Thread t = new Thread(new Runnable()
+      {
+        public void run()
+        {
+          try
+          {
+            String line = reader.readLine();
+            while (line != null)
+            {
+              StringBuffer buf = new StringBuffer();
+              if (!isFirstLine)
+              {
+                buf.append(formatter.getLineBreak());
+              }
+              if (isError)
+              {
+                buf.append(getFormattedLogError(line));
+              } else
+              {
+                buf.append(getFormattedLog(line));
+              }
+              notifyListeners(buf.toString());
+              isFirstLine = false;
+
+              if (line.indexOf("id=" + startedId) != -1)
+              {
+                isFinished = true;
+              }
+              line = reader.readLine();
+            }
+          } catch (IOException ioe)
+          {
+            String errorMsg = getThrowableMsg(errorTag, ioe);
+            ex =
+                new QuickSetupException(QuickSetupException.Type.START_ERROR,
+                    errorMsg, ioe);
+
+          } catch (Throwable t)
+          {
+            String errorMsg = getThrowableMsg(errorTag, t);
+            ex =
+                new QuickSetupException(QuickSetupException.Type.START_ERROR,
+                    errorMsg, t);
+          }
+          isFinished = true;
+        }
+      });
+      t.start();
+    }
+
+    /**
+     * Returns the QuickSetupException that occurred reading the Start error and
+     * output or <CODE>null</CODE> if no exception occurred.
+     * @return the exception that occurred reading or <CODE>null</CODE> if
+     * no exception occurred.
+     */
+    public QuickSetupException getException()
+    {
+      return ex;
+    }
+
+    /**
+     * Returns <CODE>true</CODE> if the server starting process finished
+     * (successfully or not) and <CODE>false</CODE> otherwise.
+     * @return <CODE>true</CODE> if the server starting process finished
+     * (successfully or not) and <CODE>false</CODE> otherwise.
+     */
+    public boolean isFinished()
+    {
+      return isFinished;
+    }
+  }
+
+  /**
+   * This class is used to notify the ProgressUpdateListeners of events
+   * that are written to the standard error.  It is used in WebStartInstaller
+   * and in OfflineInstaller.  These classes just create a ErrorPrintStream and
+   * then they do a call to System.err with it.
+   *
+   * The class just reads what is written to the standard error, obtains an
+   * formatted representation of it and then notifies the
+   * ProgressUpdateListeners with the formatted messages.
+   *
+   */
+  protected class ErrorPrintStream extends PrintStream {
+    private boolean isFirstLine;
+
+    /**
+     * Default constructor.
+     *
+     */
+    public ErrorPrintStream()
+    {
+      super(new ByteArrayOutputStream(), true);
+      isFirstLine = true;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void println(String msg)
+    {
+      if (isFirstLine)
+      {
+        notifyListeners(getFormattedLogError(msg));
+      } else
+      {
+        notifyListeners(formatter.getLineBreak() + getFormattedLogError(msg));
+      }
+      isFirstLine = false;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void write(byte[] b, int off, int len)
+    {
+      if (b == null)
+      {
+        throw new NullPointerException("b is null");
+      }
+
+      if (off + len > b.length)
+      {
+        throw new IndexOutOfBoundsException(
+            "len + off are bigger than the length of the byte array");
+      }
+      println(new String(b, off, len));
+    }
+  }
+
+  /**
+   * This class is used to notify the ProgressUpdateListeners of events
+   * that are written to the standard output. It is used in WebStartInstaller
+   * and in OfflineInstaller. These classes just create a OutputPrintStream and
+   * then they do a call to System.out with it.
+   *
+   * The class just reads what is written to the standard output, obtains an
+   * formatted representation of it and then notifies the
+   * ProgressUpdateListeners with the formatted messages.
+   *
+   */
+  protected class OutputPrintStream extends PrintStream
+  {
+    private boolean isFirstLine;
+
+    /**
+     * Default constructor.
+     *
+     */
+    public OutputPrintStream()
+    {
+      super(new ByteArrayOutputStream(), true);
+      isFirstLine = true;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void println(String msg)
+    {
+      if (isFirstLine)
+      {
+        notifyListeners(getFormattedLog(msg));
+      } else
+      {
+        notifyListeners(formatter.getLineBreak() + getFormattedLog(msg));
+      }
+      isFirstLine = false;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void write(byte[] b, int off, int len)
+    {
+      if (b == null)
+      {
+        throw new NullPointerException("b is null");
+      }
+
+      if (off + len > b.length)
+      {
+        throw new IndexOutOfBoundsException(
+            "len + off are bigger than the length of the byte array");
+      }
+
+      println(new String(b, off, len));
+    }
+  }
+}
diff --git a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/InstallException.java b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/ApplicationException.java
similarity index 80%
copy from opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/InstallException.java
copy to opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/ApplicationException.java
index 772d9a9..75fbd42 100644
--- a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/InstallException.java
+++ b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/ApplicationException.java
@@ -25,23 +25,25 @@
  *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
  */
 
-package org.opends.quicksetup.installer;
+package org.opends.quicksetup;
 
 /**
  * This exception is used to encapsulate all the error that we might have
  * during the installation.
  *
- * @see Installer, WebStartInstaller, OfflineInstaller.
+ * @see org.opends.quicksetup.installer.Installer
+ * @see org.opends.quicksetup.installer.webstart.WebStartInstaller
+ * @see org.opends.quicksetup.installer.offline.OfflineInstaller
  *
  */
-public class InstallException extends Exception
+public class ApplicationException extends Exception
 {
   private static final long serialVersionUID = -3527273444231560341L;
 
   private Type type;
 
   /**
-   * This enum contains the different type of InstallException that we can
+   * This enum contains the different type of ApplicationException that we can
    * have.
    *
    */
@@ -70,23 +72,31 @@
      * Error starting the Open DS server.
      */
     START_ERROR,
+
+    /**
+     * Error stopping the Open DS server.
+     */
+    STOP_ERROR,
+
     /**
      * Error enabling the Windows service.
      */
     WINDOWS_SERVICE_ERROR,
+
     /**
      * A bug (for instance when we throw an IllegalStateException).
      */
     BUG
-  };
+  }
 
   /**
-   * The constructor of the InstallException.
+   * The constructor of the ApplicationException.
    * @param type the type of error we have.
    * @param localizedMsg a localized string describing the problem.
    * @param rootCause the root cause of this exception.
    */
-  public InstallException(Type type, String localizedMsg, Throwable rootCause)
+  public ApplicationException(Type type, String localizedMsg,
+                              Throwable rootCause)
   {
     super(localizedMsg, rootCause);
     this.type = type;
diff --git a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/DataOptions.java b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/DataOptions.java
similarity index 96%
rename from opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/DataOptions.java
rename to opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/DataOptions.java
index c907e15..b355705 100644
--- a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/DataOptions.java
+++ b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/DataOptions.java
@@ -26,7 +26,7 @@
  */
 
 
-package org.opends.quicksetup.installer;
+package org.opends.quicksetup;
 
 /**
  * This class is used to provide a data model for the Data Options panel of the
@@ -43,6 +43,11 @@
   public enum Type
   {
     /**
+     * Do nothing.
+     */
+    NOTHING,
+
+    /**
      * Create base entry.
      */
     CREATE_BASE_ENTRY,
@@ -60,7 +65,7 @@
     IMPORT_AUTOMATICALLY_GENERATED_DATA
   }
 
-  private Type type;
+  private Type type = Type.NOTHING;
 
   private String baseDn;
 
diff --git a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/InstallerHelper.java b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/InstallerHelper.java
similarity index 67%
rename from opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/InstallerHelper.java
rename to opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/InstallerHelper.java
index 94da554..8e5e68a 100644
--- a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/InstallerHelper.java
+++ b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/InstallerHelper.java
@@ -25,14 +25,15 @@
  *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
  */
 
-package org.opends.quicksetup.installer;
+package org.opends.quicksetup;
 
 import java.io.File;
 import java.io.IOException;
 
 import org.opends.quicksetup.i18n.ResourceProvider;
-import org.opends.quicksetup.installer.webstart.JnlpProperties;
+import org.opends.quicksetup.webstart.JnlpProperties;
 import org.opends.quicksetup.util.Utils;
+import org.opends.server.tools.ConfigureWindowsService;
 
 /**
  * This is the only class that uses classes in org.opends.server (excluding the
@@ -47,18 +48,16 @@
  * classes the required jar files are already loaded. However these jar files
  * are not necessarily loaded when we create this class.
  */
-class InstallerHelper implements JnlpProperties
-{
+public class InstallerHelper implements JnlpProperties {
 
   /**
    * Invokes the method ConfigureDS.configMain with the provided parameters.
    * @param args the arguments to be passed to ConfigureDS.configMain.
    * @return the return code of the ConfigureDS.configMain method.
-   * @throws InstallException if something goes wrong.
-   * @see org.opends.server.tools.ConfigureDS.configMain(args).
+   * @throws QuickSetupException if something goes wrong.
+   * @see org.opends.server.tools.ConfigureDS#configMain(String[]).
    */
-  public int invokeConfigureServer(String[] args) throws InstallException
-  {
+  public int invokeConfigureServer(String[] args) throws QuickSetupException {
     return org.opends.server.tools.ConfigureDS.configMain(args);
   }
 
@@ -66,11 +65,10 @@
    * Invokes the method ImportLDIF.mainImportLDIF with the provided parameters.
    * @param args the arguments to be passed to ImportLDIF.mainImportLDIF.
    * @return the return code of the ImportLDIF.mainImportLDIF method.
-   * @throws InstallException if something goes wrong.
-   * @see org.opends.server.tools.ImportLDIF.mainImportLDIF(args).
+   * @throws org.opends.quicksetup.QuickSetupException if something goes wrong.
+   * @see org.opends.server.tools.ImportLDIF#mainImportLDIF(String[]).
    */
-  public int invokeImportLDIF(String[] args) throws InstallException
-  {
+  public int invokeImportLDIF(String[] args) throws QuickSetupException {
     return org.opends.server.tools.ImportLDIF.mainImportLDIF(args);
   }
 
@@ -86,27 +84,24 @@
 
   /**
    * This methods enables this server as a Windows service.
-   * @throws InstallException if something goes wrong.
+   * @throws QuickSetupException if something goes wrong.
    */
-  protected void enableWindowsService() throws InstallException
-  {
+  public void enableWindowsService() throws QuickSetupException {
     int code = org.opends.server.tools.ConfigureWindowsService.enableService(
     System.out, System.err);
 
     String errorMessage = ResourceProvider.getInstance().getMsg(
     "error-enabling-windows-service");
 
-    switch (code)
-    {
-      case
-      org.opends.server.tools.ConfigureWindowsService.SERVICE_ENABLE_SUCCESS:
-      break;
-      case
-      org.opends.server.tools.ConfigureWindowsService.SERVICE_ALREADY_ENABLED:
-      break;
+    switch (code) {
+      case ConfigureWindowsService.SERVICE_ENABLE_SUCCESS:
+        break;
+      case ConfigureWindowsService.SERVICE_ALREADY_ENABLED:
+        break;
       default:
-      throw new InstallException(InstallException.Type.WINDOWS_SERVICE_ERROR,
-      errorMessage, null);
+        throw new QuickSetupException(
+                QuickSetupException.Type.WINDOWS_SERVICE_ERROR,
+                errorMessage, null);
     }
   }
 
@@ -126,11 +121,11 @@
    * baseDn.
    * @param baseDn the dn of the entry that will be created in the LDIF file.
    * @return the File object pointing to the created temporary file.
-   * @throws InstallException if something goes wrong.
+   * @throws QuickSetupException if something goes wrong.
    */
-  public File createBaseEntryTempFile(String baseDn) throws InstallException
-  {
-    File ldifFile = null;
+  public File createBaseEntryTempFile(String baseDn)
+          throws QuickSetupException {
+    File ldifFile;
     try
     {
       ldifFile = File.createTempFile("opends-base-entry", ".ldif");
@@ -138,7 +133,7 @@
     } catch (IOException ioe)
     {
       String failedMsg = getThrowableMsg("error-creating-temp-file", null, ioe);
-      throw new InstallException(InstallException.Type.FILE_SYSTEM_ERROR,
+      throw new QuickSetupException(QuickSetupException.Type.FILE_SYSTEM_ERROR,
           failedMsg, ioe);
     }
 
@@ -159,22 +154,22 @@
 
       writer.writeEntry(entry);
       writer.close();
-    } catch (org.opends.server.types.DirectoryException de)
-    {
-      throw new InstallException(InstallException.Type.CONFIGURATION_ERROR,
-          getThrowableMsg("error-importing-ldif", null, de), de);
-    } catch (org.opends.server.util.LDIFException le)
-    {
-      throw new InstallException(InstallException.Type.CONFIGURATION_ERROR,
-          getThrowableMsg("error-importing-ldif", null, le), le);
-    } catch (IOException ioe)
-    {
-      throw new InstallException(InstallException.Type.CONFIGURATION_ERROR,
-          getThrowableMsg("error-importing-ldif", null, ioe), ioe);
-    } catch (Throwable t)
-    {
-      throw new InstallException(InstallException.Type.BUG, getThrowableMsg(
-          "bug-msg", t), t);
+    } catch (org.opends.server.types.DirectoryException de) {
+      throw new QuickSetupException(
+              QuickSetupException.Type.CONFIGURATION_ERROR,
+              getThrowableMsg("error-importing-ldif", null, de), de);
+    } catch (org.opends.server.util.LDIFException le) {
+      throw new QuickSetupException(
+              QuickSetupException.Type.CONFIGURATION_ERROR,
+              getThrowableMsg("error-importing-ldif", null, le), le);
+    } catch (IOException ioe) {
+      throw new QuickSetupException(
+              QuickSetupException.Type.CONFIGURATION_ERROR,
+              getThrowableMsg("error-importing-ldif", null, ioe), ioe);
+    } catch (Throwable t) {
+      throw new QuickSetupException(
+              QuickSetupException.Type.BUG, getThrowableMsg(
+              "bug-msg", t), t);
     }
     return ldifFile;
   }
diff --git a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/InstallProgressDescriptor.java b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/ProgressDescriptor.java
similarity index 91%
rename from opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/InstallProgressDescriptor.java
rename to opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/ProgressDescriptor.java
index 9389874..b6a7f16 100644
--- a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/InstallProgressDescriptor.java
+++ b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/ProgressDescriptor.java
@@ -25,7 +25,7 @@
  *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
  */
 
-package org.opends.quicksetup.installer;
+package org.opends.quicksetup;
 
 /**
  * This class is used to describe the current state of the installation.
@@ -42,9 +42,9 @@
  * messages).
  *
  */
-public class InstallProgressDescriptor
-{
-  private InstallProgressStep step;
+public class ProgressDescriptor {
+
+  private ProgressStep step;
 
   private Integer progressBarRatio;
 
@@ -53,13 +53,13 @@
   private String detailsMsg;
 
   /**
-   * Constructor for the InstallProgressDescriptor.
+   * Constructor for the ProgressDescriptor.
    * @param step the current install step.
    * @param progressBarRatio the completed progress ratio (in percentage).
    * @param progressBarMsg the message to be displayed in the progress bar.
    * @param detailsMsg the logs.
    */
-  public InstallProgressDescriptor(InstallProgressStep step,
+  public ProgressDescriptor(ProgressStep step,
       Integer progressBarRatio, String progressBarMsg, String detailsMsg)
   {
     this.step = step;
@@ -101,7 +101,7 @@
    * Returns the step of the install on which we are.
    * @return the step of the install on which we are.
    */
-  public InstallProgressStep getProgressStep()
+  public ProgressStep getProgressStep()
   {
     return step;
   }
diff --git a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/event/UninstallProgressUpdateListener.java b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/ProgressStep.java
similarity index 67%
rename from opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/event/UninstallProgressUpdateListener.java
rename to opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/ProgressStep.java
index 39a41ee..8d2243c 100644
--- a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/event/UninstallProgressUpdateListener.java
+++ b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/ProgressStep.java
@@ -25,20 +25,25 @@
  *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
  */
 
-package org.opends.quicksetup.event;
+package org.opends.quicksetup;
 
 /**
- * Interface that implement the objects that want to receive notifications of
- * updates in the uninstallation progress.
- *
+ * Interface describing the different installation steps in which we can
+ * be.
  */
-public interface UninstallProgressUpdateListener
-{
+public interface ProgressStep {
+
   /**
-   * Method called when an update in the uninstallation progress occurs.
-   *
-   * @param ev the UninstallProgressUpdateEvent describing the update that
-   * occurred in the installation progress.
+   * Indicates whether this Progress step is a final step.
+   * @return true if this is a final step
    */
-  public void progressUpdate(UninstallProgressUpdateEvent ev);
+  boolean isLast();
+
+  /**
+   * Indicates whether this Progress step is arrived at
+   * through an error in the application.
+   * @return true if this is an error step
+   */
+  boolean isError();
+
 }
diff --git a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/QuickSetup.java b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/QuickSetup.java
index 3437ace..bd59f8e 100644
--- a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/QuickSetup.java
+++ b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/QuickSetup.java
@@ -27,45 +27,27 @@
 
 package org.opends.quicksetup;
 
-import java.io.File;
-import java.util.ArrayList;
-import java.util.EnumSet;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
-
-import javax.swing.SwingUtilities;
-
 import org.opends.quicksetup.event.ButtonActionListener;
 import org.opends.quicksetup.event.ButtonEvent;
-import org.opends.quicksetup.event.InstallProgressUpdateEvent;
-import org.opends.quicksetup.event.InstallProgressUpdateListener;
-import org.opends.quicksetup.event.UninstallProgressUpdateEvent;
-import org.opends.quicksetup.event.UninstallProgressUpdateListener;
+import org.opends.quicksetup.event.ProgressUpdateEvent;
+import org.opends.quicksetup.event.ProgressUpdateListener;
 import org.opends.quicksetup.i18n.ResourceProvider;
-import org.opends.quicksetup.installer.DataOptions;
 import org.opends.quicksetup.installer.FieldName;
-import org.opends.quicksetup.installer.InstallProgressDescriptor;
-import org.opends.quicksetup.installer.InstallProgressStep;
-import org.opends.quicksetup.installer.Installer;
-import org.opends.quicksetup.installer.UserInstallData;
-import org.opends.quicksetup.installer.UserInstallDataException;
-import org.opends.quicksetup.installer.offline.OfflineInstaller;
-import org.opends.quicksetup.installer.webstart.WebStartDownloader;
-import org.opends.quicksetup.installer.webstart.WebStartInstaller;
 import org.opends.quicksetup.ui.QuickSetupDialog;
 import org.opends.quicksetup.ui.UIFactory;
-import org.opends.quicksetup.uninstaller.UninstallProgressDescriptor;
-import org.opends.quicksetup.uninstaller.UninstallProgressStep;
-import org.opends.quicksetup.uninstaller.Uninstaller;
-import org.opends.quicksetup.uninstaller.UserUninstallData;
-import org.opends.quicksetup.uninstaller.UserUninstallDataException;
+import org.opends.quicksetup.uninstaller.UninstallUserData;
 import org.opends.quicksetup.util.BackgroundTask;
 import org.opends.quicksetup.util.ProgressMessageFormatter;
 import org.opends.quicksetup.util.Utils;
+import org.opends.quicksetup.util.HtmlProgressMessageFormatter;
 import org.opends.server.util.SetupUtils;
 
+import javax.swing.*;
+import java.io.File;
+import java.util.*;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
 /**
  * This class is responsible for doing the following:
  *
@@ -82,25 +64,17 @@
  * downloading of the jar files that are required to perform the installation
  * (OpenDS.jar, je.jar, etc.).  The global idea is to force the user to
  * download just one jar file (quicksetup.jar) to launch the Web Start
- * installer.  Then QuickSetup will call WebStartDownloader to download the jar
- * files.  Until this class is not finished the WebStart Installer will be on
- * the InstallProgressStep.DOWNLOADING step.
+ * installer.  Until this class is not finished the WebStart Installer will be
+ * on the ProgressStep.DOWNLOADING step.
  *
  */
-class QuickSetup implements ButtonActionListener, InstallProgressUpdateListener,
-UninstallProgressUpdateListener
+public class QuickSetup implements ButtonActionListener, ProgressUpdateListener
 {
-  // Contains the data provided by the user in the install
-  private UserInstallData userInstallData;
 
-  // Contains the data provided by the user in the uninstall
-  private UserUninstallData userUninstallData;
+  static private final Logger LOG =
+          Logger.getLogger(QuickSetup.class.getName());
 
-  private Installer installer;
-
-  private Uninstaller uninstaller;
-
-  private WebStartDownloader jnlpDownloader;
+  private Application application;
 
   private CurrentInstallStatus installStatus;
 
@@ -110,17 +84,11 @@
 
   private StringBuffer progressDetails = new StringBuffer();
 
-  private InstallProgressDescriptor lastInstallDescriptor;
+  private ProgressDescriptor lastDescriptor;
 
-  private InstallProgressDescriptor lastDisplayedInstallDescriptor;
+  private ProgressDescriptor lastDisplayedDescriptor;
 
-  private InstallProgressDescriptor installDescriptorToDisplay;
-
-  private UninstallProgressDescriptor lastUninstallDescriptor;
-
-  private UninstallProgressDescriptor lastDisplayedUninstallDescriptor;
-
-  private UninstallProgressDescriptor uninstallDescriptorToDisplay;
+  private ProgressDescriptor descriptorToDisplay;
 
   // Constants used to do checks
   private static final int MIN_DIRECTORY_MANAGER_PWD = 1;
@@ -147,10 +115,13 @@
    */
   public void initialize(String[] args)
   {
-    if (isWebStart())
-    {
-      jnlpDownloader = new WebStartDownloader();
-      jnlpDownloader.start(false);
+    ProgressMessageFormatter formatter = new HtmlProgressMessageFormatter();
+    try {
+      application = Application.create(formatter);
+      application.setProgressMessageFormatter(formatter);
+    } catch (ApplicationException e) {
+      LOG.log(Level.INFO, "error", e);
+      throw new RuntimeException("failed to create quicksetup application", e);
     }
     installStatus = new CurrentInstallStatus();
     initLookAndFeel();
@@ -164,6 +135,24 @@
     }
   }
 
+  private Application createApplication(ProgressMessageFormatter formatter) {
+    try {
+      application = Application.create(formatter);
+    } catch (ApplicationException e) {
+      LOG.log(Level.INFO, "error", e);
+    }
+    return application;
+  }
+
+  /**
+   * Gets the current installation status of the filesystem
+   * bits this quick setup is managing.
+   * @return CurrentInstallStatus indicating the install status
+   */
+  public CurrentInstallStatus getInstallStatus() {
+    return installStatus;
+  }
+
   /**
    * This method displays the setup dialog. This method must be called from the
    * event thread.
@@ -222,56 +211,26 @@
   }
 
   /**
-   * InstallProgressUpdateListener implementation. Here we take the
-   * InstallProgressUpdateEvent and create an InstallProgressDescriptor that
+   * ProgressUpdateListener implementation. Here we take the
+   * ProgressUpdateEvent and create an ProgressDescriptor that
    * will be used to update the progress dialog.
    *
-   * @param ev the InstallProgressUpdateEvent we receive.
+   * @param ev the ProgressUpdateEvent we receive.
    *
    * @see #runDisplayUpdater()
    */
-  public void progressUpdate(InstallProgressUpdateEvent ev)
+  public void progressUpdate(ProgressUpdateEvent ev)
   {
     synchronized (this)
     {
-      InstallProgressDescriptor desc = createInstallProgressDescriptor(ev);
-      boolean isLastDescriptor =
-          desc.getProgressStep() == InstallProgressStep.FINISHED_SUCCESSFULLY
-              || desc.getProgressStep() ==
-                InstallProgressStep.FINISHED_WITH_ERROR;
+      ProgressDescriptor desc = createInstallProgressDescriptor(ev);
+      boolean isLastDescriptor = desc.getProgressStep().isLast();
       if (isLastDescriptor)
       {
-        lastInstallDescriptor = desc;
+        lastDescriptor = desc;
       }
 
-      installDescriptorToDisplay = desc;
-    }
-  }
-
-  /**
-   * UninstallProgressUpdateListener implementation. Here we take the
-   * UninstallProgressUpdateEvent and create an UninstallProgressDescriptor that
-   * will be used to update the progress dialog.
-   *
-   * @param ev the UninstallProgressUpdateEvent we receive.
-   *
-   * @see #runDisplayUpdater()
-   */
-  public void progressUpdate(UninstallProgressUpdateEvent ev)
-  {
-    synchronized (this)
-    {
-      UninstallProgressDescriptor desc = createUninstallProgressDescriptor(ev);
-      boolean isLastDescriptor =
-          desc.getProgressStep() == UninstallProgressStep.FINISHED_SUCCESSFULLY
-              || desc.getProgressStep() ==
-                UninstallProgressStep.FINISHED_WITH_ERROR;
-      if (isLastDescriptor)
-      {
-        lastUninstallDescriptor = desc;
-      }
-
-      uninstallDescriptorToDisplay = desc;
+      descriptorToDisplay = desc;
     }
   }
 
@@ -284,9 +243,7 @@
    * of flickering. So the idea here is to have a minimal time between 2 updates
    * of the progress dialog (specified by UPDATE_PERIOD).
    *
-   * @see #progressUpdate(InstallProgressUpdateEvent ev)
-   * @see #progressUpdate(UninstallProgressUpdateEvent ev)
-   *
+   * @see #progressUpdate(ProgressUpdateEvent)
    */
   private void runDisplayUpdater()
   {
@@ -303,12 +260,12 @@
       {
         if (Utils.isUninstall())
         {
-          final UninstallProgressDescriptor desc = uninstallDescriptorToDisplay;
+          final ProgressDescriptor desc = descriptorToDisplay;
           if (desc != null)
           {
-            if (desc != lastDisplayedUninstallDescriptor)
+            if (desc != lastDisplayedDescriptor)
             {
-              lastDisplayedUninstallDescriptor = desc;
+              lastDisplayedDescriptor = desc;
 
               SwingUtilities.invokeLater(new Runnable()
               {
@@ -318,17 +275,17 @@
                 }
               });
             }
-            doPool = desc != lastUninstallDescriptor;
+            doPool = desc != lastDescriptor;
           }
         }
         else
         {
-          final InstallProgressDescriptor desc = installDescriptorToDisplay;
+          final ProgressDescriptor desc = descriptorToDisplay;
           if (desc != null)
           {
-            if (desc != lastDisplayedInstallDescriptor)
+            if (desc != lastDisplayedDescriptor)
             {
-              lastDisplayedInstallDescriptor = desc;
+              lastDisplayedDescriptor = desc;
 
               SwingUtilities.invokeLater(new Runnable()
               {
@@ -338,7 +295,7 @@
                 }
               });
             }
-            doPool = desc != lastInstallDescriptor;
+            doPool = desc != lastDescriptor;
           }
         }
       }
@@ -364,19 +321,18 @@
     default:
       BackgroundTask worker = new BackgroundTask()
       {
-        public Object processBackgroundTask() throws UserInstallDataException
-        {
+        public Object processBackgroundTask() throws UserDataException {
           try
           {
-            updateUserInstallData(cStep);
+            updateUserData(cStep);
           }
-          catch (UserInstallDataException uide)
+          catch (UserDataException uide)
           {
             throw uide;
           }
           catch (Throwable t)
           {
-            throw new UserInstallDataException(cStep,
+            throw new UserDataException(cStep,
                 getThrowableMsg("bug-msg", t));
           }
           return null;
@@ -389,7 +345,7 @@
 
           if (throwable != null)
           {
-            UserInstallDataException ude = (UserInstallDataException)throwable;
+            UserDataException ude = (UserDataException)throwable;
             displayError(ude.getLocalizedMessage(), getMsg("error-title"));
           }
           else
@@ -421,21 +377,21 @@
     case CONFIRM_UNINSTALL:
       BackgroundTask worker = new BackgroundTask()
       {
-        public Object processBackgroundTask() throws UserUninstallDataException
+        public Object processBackgroundTask() throws UserDataException
         {
           try
           {
-            updateUserDataForConfirmUninstallPanel();
+            updateUserUninstallDataForConfirmUninstallPanel();
           }
-          catch (UserUninstallDataException uude)
+          catch (UserDataException uude)
           {
             throw uude;
           } catch (Throwable t)
           {
-            throw new UserUninstallDataException(cStep,
+            throw new UserDataException(cStep,
                 getThrowableMsg("bug-msg", t));
           }
-          return new Boolean(installStatus.isServerRunning());
+          return CurrentInstallStatus.isServerRunning();
         }
 
         public void backgroundTaskCompleted(Object returnValue,
@@ -444,15 +400,14 @@
           getDialog().workerFinished();
           if (throwable != null)
           {
-            UserUninstallDataException ude =
-              (UserUninstallDataException)throwable;
-            displayError(ude.getLocalizedMessage(), getMsg("error-title"));
+            displayError(throwable.getLocalizedMessage(),
+                    getMsg("error-title"));
           } else
           {
-            boolean serverRunning = ((Boolean)returnValue).booleanValue();
+            boolean serverRunning = (Boolean) returnValue;
             if (!serverRunning)
             {
-              getUserUninstallData().setStopServer(false);
+              application.getUserData().setStopServer(false);
               if (displayConfirmation(
                   getMsg("confirm-uninstall-server-not-running-msg"),
                   getMsg("confirm-uninstall-server-not-running-title")))
@@ -467,12 +422,12 @@
                       getMsg("confirm-uninstall-server-running-msg"),
                       getMsg("confirm-uninstall-server-running-title")))
               {
-                  getUserUninstallData().setStopServer(true);
+                  application.getUserData().setStopServer(true);
                   launchUninstallation();
                   setCurrentStep(nextStep(cStep));
               } else
               {
-                  getUserUninstallData().setStopServer(false);
+                  application.getUserData().setStopServer(false);
               }
             }
           }
@@ -571,7 +526,7 @@
     case PROGRESS:
       if (Utils.isUninstall())
       {
-        boolean finished = uninstaller.isFinished();
+        boolean finished = application.isFinished();
         if (finished
             || displayConfirmation(getMsg("confirm-close-uninstall-msg"),
                 getMsg("confirm-close-uninstall-title")))
@@ -580,7 +535,7 @@
         }
       } else
       {
-        boolean finished = installer.isFinished();
+        boolean finished = application.isFinished();
         if (finished
             || displayConfirmation(getMsg("confirm-close-install-msg"),
                 getMsg("confirm-close-install-title")))
@@ -619,8 +574,7 @@
   {
     BackgroundTask worker = new BackgroundTask()
     {
-      public Object processBackgroundTask() throws UserInstallDataException
-      {
+      public Object processBackgroundTask() throws UserDataException {
         try
         {
           String cmd = Utils.isWindows()?Utils.getWindowsStatusPanelFileName():
@@ -628,7 +582,7 @@
           String serverPath;
           if (Utils.isWebStart())
           {
-            serverPath = getUserInstallData().getServerLocation();
+            serverPath = application.getUserData().getServerLocation();
           }
           else
           {
@@ -636,7 +590,7 @@
           }
           cmd = Utils.getPath(serverPath, Utils.getBinariesRelativePath()+
                   File.separator+cmd);
-          ProcessBuilder pb = new ProcessBuilder(new String[]{cmd});
+          ProcessBuilder pb = new ProcessBuilder(cmd);
           Map<String, String> env = pb.environment();
           env.put("JAVA_HOME", System.getProperty("java.home"));
           /* Remove JAVA_BIN to be sure that we use the JVM running the
@@ -688,22 +642,20 @@
 
   /**
    * These methods validate the data provided by the user in the panels and
-   * update the UserInstallData object according to that content.
+   * update the userData object according to that content.
    *
    * @param cStep
    *          the current step of the wizard
    *
-   * @throws an
-   *           UserInstallDataException if the data provided by the user is not
+   * @throws UserDataException if the data provided by the user is not
    *           valid.
    *
    */
-  private void updateUserInstallData(Step cStep) throws UserInstallDataException
-  {
+  private void updateUserData(Step cStep) throws UserDataException {
     switch (cStep)
     {
     case SERVER_SETTINGS:
-      updateUserInstallDataForServerSettingsPanel();
+      updateUserDataForServerSettingsPanel();
       break;
 
     case DATA_OPTIONS:
@@ -718,16 +670,14 @@
 
   /**
    * Validate the data provided by the user in the server settings panel and
-   * update the UserInstallData object according to that content.
+   * update the userData object according to that content.
    *
-   * @throws an
-   *           UserInstallDataException if the data provided by the user is not
+   * @throws UserDataException if the data provided by the user is not
    *           valid.
    *
    */
-  private void updateUserInstallDataForServerSettingsPanel()
-      throws UserInstallDataException
-  {
+  private void updateUserDataForServerSettingsPanel()
+      throws UserDataException {
     ArrayList<String> errorMsgs = new ArrayList<String>();
 
     if (isWebStart())
@@ -775,7 +725,7 @@
 
       } else
       {
-        getUserInstallData().setServerLocation(serverLocation);
+        application.getUserData().setServerLocation(serverLocation);
         displayFieldInvalid(FieldName.SERVER_LOCATION, false);
       }
     }
@@ -806,7 +756,7 @@
 
       } else
       {
-        getUserInstallData().setServerPort(port);
+        application.getUserData().setServerPort(port);
         displayFieldInvalid(FieldName.SERVER_PORT, false);
       }
 
@@ -835,7 +785,7 @@
       displayFieldInvalid(FieldName.DIRECTORY_MANAGER_DN, true);
     } else
     {
-      getUserInstallData().setDirectoryManagerDn(dmDn);
+      application.getUserData().setDirectoryManagerDn(dmDn);
       displayFieldInvalid(FieldName.DIRECTORY_MANAGER_DN, false);
     }
 
@@ -869,7 +819,7 @@
 
     if (pwdValid)
     {
-      getUserInstallData().setDirectoryManagerPwd(pwd1);
+      application.getUserData().setDirectoryManagerPwd(pwd1);
       displayFieldInvalid(FieldName.DIRECTORY_MANAGER_PWD, false);
       displayFieldInvalid(FieldName.DIRECTORY_MANAGER_PWD_CONFIRM, false);
     }
@@ -877,28 +827,26 @@
     int defaultJMXPort = getDefaultJMXPort();
     if (defaultJMXPort != -1)
     {
-      getUserInstallData().setServerJMXPort(defaultJMXPort);
+      application.getUserData().setServerJMXPort(defaultJMXPort);
     }
 
     if (errorMsgs.size() > 0)
     {
-      throw new UserInstallDataException(Step.SERVER_SETTINGS,
+      throw new UserDataException(Step.SERVER_SETTINGS,
           Utils.getStringFromCollection(errorMsgs, "\n"));
     }
   }
 
   /**
    * Validate the data provided by the user in the data options panel and update
-   * the UserInstallData object according to that content.
+   * the userData object according to that content.
    *
-   * @throws an
-   *           UserInstallDataException if the data provided by the user is not
+   * @throws UserDataException if the data provided by the user is not
    *           valid.
    *
    */
   private void updateUserDataForDataOptionsPanel()
-      throws UserInstallDataException
-  {
+      throws UserDataException {
     ArrayList<String> errorMsgs = new ArrayList<String>();
 
     DataOptions dataOptions = null;
@@ -1000,46 +948,50 @@
 
     if (dataOptions != null)
     {
-      getUserInstallData().setDataOptions(dataOptions);
+      application.getUserData().setDataOptions(dataOptions);
     }
 
     if (errorMsgs.size() > 0)
     {
-      throw new UserInstallDataException(Step.DATA_OPTIONS,
+      throw new UserDataException(Step.DATA_OPTIONS,
           Utils.getStringFromCollection(errorMsgs, "\n"));
     }
   }
 
   /**
-   * Update the UserInstallData object according to the content of the review
+   * Update the userData object according to the content of the review
    * panel.
    *
    */
   private void updateUserDataForReviewPanel()
   {
     Boolean b = (Boolean) getFieldValue(FieldName.SERVER_START);
-    getUserInstallData().setStartServer(b.booleanValue());
+    application.getUserData().setStartServer(b.booleanValue());
   }
 
   /**
-   * Update the UserUninstallData object according to the content of the review
+   * Update the UserData object according to the content of the review
    * panel.
    *
    */
-  private void updateUserDataForConfirmUninstallPanel()
-  throws UserUninstallDataException
+  private void updateUserUninstallDataForConfirmUninstallPanel()
+  throws UserDataException
   {
-    getUserUninstallData().setRemoveLibrariesAndTools(
+
+    // TODO:  move this to the Uninstall application
+
+    UninstallUserData uud = (UninstallUserData)application.getUserData();
+    uud.setRemoveLibrariesAndTools(
         (Boolean)getFieldValue(FieldName.REMOVE_LIBRARIES_AND_TOOLS));
-    getUserUninstallData().setRemoveDatabases(
+    uud.setRemoveDatabases(
         (Boolean)getFieldValue(FieldName.REMOVE_DATABASES));
-    getUserUninstallData().setRemoveConfigurationAndSchema(
+    uud.setRemoveConfigurationAndSchema(
         (Boolean)getFieldValue(FieldName.REMOVE_CONFIGURATION_AND_SCHEMA));
-    getUserUninstallData().setRemoveBackups(
+    uud.setRemoveBackups(
         (Boolean)getFieldValue(FieldName.REMOVE_BACKUPS));
-    getUserUninstallData().setRemoveLDIFs(
+    uud.setRemoveLDIFs(
         (Boolean)getFieldValue(FieldName.REMOVE_LDIFS));
-    getUserUninstallData().setRemoveLogs(
+    uud.setRemoveLogs(
         (Boolean)getFieldValue(FieldName.REMOVE_LOGS));
 
     Set<String> dbs = new HashSet<String>();
@@ -1056,19 +1008,19 @@
       logs.add((String)v);
     }
 
-    getUserUninstallData().setExternalDbsToRemove(dbs);
-    getUserUninstallData().setExternalLogsToRemove(logs);
+    uud.setExternalDbsToRemove(dbs);
+    uud.setExternalLogsToRemove(logs);
 
     if ((dbs.size() == 0) &&
         (logs.size() == 0) &&
-        !getUserUninstallData().getRemoveLibrariesAndTools() &&
-        !getUserUninstallData().getRemoveDatabases() &&
-        !getUserUninstallData().getRemoveConfigurationAndSchema() &&
-        !getUserUninstallData().getRemoveBackups() &&
-        !getUserUninstallData().getRemoveLDIFs() &&
-        !getUserUninstallData().getRemoveLogs())
+        !uud.getRemoveLibrariesAndTools() &&
+        !uud.getRemoveDatabases() &&
+        !uud.getRemoveConfigurationAndSchema() &&
+        !uud.getRemoveBackups() &&
+        !uud.getRemoveLDIFs() &&
+        !uud.getRemoveLogs())
     {
-      throw new UserUninstallDataException(Step.CONFIRM_UNINSTALL,
+      throw new UserDataException(Step.CONFIRM_UNINSTALL,
           getMsg("nothing-selected-to-uninstall"));
     }
   }
@@ -1081,16 +1033,9 @@
   private void launchInstallation()
   {
     ProgressMessageFormatter formatter = getDialog().getFormatter();
-    if (isWebStart())
-    {
-      installer = new WebStartInstaller(getUserInstallData(), jnlpDownloader,
-          formatter);
-    } else
-    {
-      installer = new OfflineInstaller(getUserInstallData(), formatter);
-    }
-    installer.addProgressUpdateListener(this);
-    installer.start();
+
+    application.addProgressUpdateListener(this);
+    new Thread(application).start();
     Thread t = new Thread(new Runnable()
     {
       public void run()
@@ -1107,10 +1052,8 @@
    */
   private void launchUninstallation()
   {
-    uninstaller = new Uninstaller(getUserUninstallData(),
-        getDialog().getFormatter());
-    uninstaller.addProgressUpdateListener(this);
-    uninstaller.start();
+    application.addProgressUpdateListener(this);
+    new Thread(application).start();
     Thread t = new Thread(new Runnable()
     {
       public void run()
@@ -1122,49 +1065,17 @@
   }
 
   /**
-   * Provides the object representing the data provided by the user in the
-   * install.
-   *
-   * @return the UserInstallData representing the data provided by the user in
-   *         the Install wizard.
-   */
-  private UserInstallData getUserInstallData()
-  {
-    if (userInstallData == null)
-    {
-      userInstallData = new UserInstallData();
-    }
-    return userInstallData;
-  }
-
-  /**
-   * Provides the object representing the data provided by the user in the
-   * uninstall.
-   *
-   * @return the UserUninstallData representing the data provided by the user in
-   *         the Uninstall wizard.
-   */
-  private UserUninstallData getUserUninstallData()
-  {
-    if (userUninstallData == null)
-    {
-      userUninstallData = new UserUninstallData();
-    }
-    return userUninstallData;
-  }
-
-  /**
    * Provides an object representing the default data/install parameters that
    * will be proposed to the user in the Installation wizard. This data includes
    * elements such as the default dn of the directory manager or the default
    * install location.
    *
-   * @return the UserInstallData representing the default data/parameters that
+   * @return the userData representing the default data/parameters that
    *         will be proposed to the user.
    */
-  private UserInstallData getDefaultUserData()
+  private UserData getDefaultUserData()
   {
-    UserInstallData defaultUserData = new UserInstallData();
+    UserData defaultUserData = application.createUserData();
 
     DataOptions defaultDataOptions = new DefaultDataOptions();
 
@@ -1187,17 +1098,33 @@
   /**
    * The following three methods are just commodity methods to get localized
    * messages.
+   * @param key String key
+   * @return String message
    */
   private String getMsg(String key)
   {
     return getI18n().getMsg(key);
   }
 
+  /**
+   * The following three methods are just commodity methods to get localized
+   * messages.
+   * @param key String key
+   * @param args String[] args
+   * @return String message
+   */
   private String getMsg(String key, String[] args)
   {
     return getI18n().getMsg(key, args);
   }
 
+  /**
+   * The following three methods are just commodity methods to get localized
+   * messages.
+   * @param key String key
+   * @param t Throwable throwable
+   * @return String message
+   */
   private String getThrowableMsg(String key, Throwable t)
   {
     return Utils.getThrowableMsg(getI18n(), key, null, t);
@@ -1223,29 +1150,25 @@
    * dialog to display the panel that corresponds to the step passed as
    * argument.
    *
-   * @param step.
-   *          The step to be displayed.
+   * @param step The step to be displayed.
    */
-  private void setCurrentStep(Step step)
+  public void setCurrentStep(Step step)
   {
     if (step == null)
     {
       throw new NullPointerException("step is null");
     }
     currentStep = step;
-    getDialog().setDisplayedStep(step, getUserInstallData());
+    getDialog().setDisplayedStep(step, application.getUserData());
   }
 
   /**
    * Gets the next step corresponding to the step passed as parameter.
    *
-   * @param step,
-   *          the step of which we want to get the new step.
+   * @param step the step of which we want to get the new step.
    * @return the next step for the current step.
-   * @throws IllegalArgumentException
-   *           if the current step has not a next step.
    */
-  private Step nextStep(Step step)
+  public Step nextStep(Step step)
   {
     Step nextStep;
     if (step == Step.CONFIRM_UNINSTALL)
@@ -1311,7 +1234,7 @@
    * @param title
    *          the title for the dialog.
    */
-  private void displayError(String msg, String title)
+  public void displayError(String msg, String title)
   {
     getDialog().displayError(msg, title);
   }
@@ -1326,7 +1249,7 @@
    * @return <CODE>true</CODE> if the user confirms the message, or
    * <CODE>false</CODE> if not.
    */
-  private boolean displayConfirmation(String msg, String title)
+  public boolean displayConfirmation(String msg, String title)
   {
     return getDialog().displayConfirmation(msg, title);
   }
@@ -1394,18 +1317,18 @@
   }
 
   /**
-   * A methods that creates an InstallProgressDescriptor based on the value of a
-   * InstallProgressUpdateEvent.
+   * A methods that creates an ProgressDescriptor based on the value of a
+   * ProgressUpdateEvent.
    *
    * @param ev
-   *          the InstallProgressUpdateEvent used to generate the
-   *          InstallProgressDescriptor.
-   * @return the InstallProgressDescriptor.
+   *          the ProgressUpdateEvent used to generate the
+   *          ProgressDescriptor.
+   * @return the ProgressDescriptor.
    */
-  private InstallProgressDescriptor createInstallProgressDescriptor(
-      InstallProgressUpdateEvent ev)
+  private ProgressDescriptor createInstallProgressDescriptor(
+      ProgressUpdateEvent ev)
   {
-    InstallProgressStep status = ev.getProgressStep();
+    ProgressStep status = ev.getProgressStep();
     String newProgressLabel = ev.getCurrentPhaseSummary();
     String additionalDetails = ev.getNewLogs();
     Integer ratio = ev.getProgressRatio();
@@ -1415,33 +1338,7 @@
       progressDetails.append(additionalDetails);
     }
 
-    return new InstallProgressDescriptor(status, ratio, newProgressLabel,
-        progressDetails.toString());
-  }
-
-  /**
-   * A methods that creates an UninstallProgressDescriptor based on the value of
-   * a UninstallProgressUpdateEvent.
-   *
-   * @param ev
-   *          the UninstallProgressUpdateEvent used to generate the
-   *          UninstallProgressDescriptor.
-   * @return the InstallProgressDescriptor.
-   */
-  private UninstallProgressDescriptor createUninstallProgressDescriptor(
-      UninstallProgressUpdateEvent ev)
-  {
-    UninstallProgressStep status = ev.getProgressStep();
-    String newProgressLabel = ev.getCurrentPhaseSummary();
-    String additionalDetails = ev.getNewLogs();
-    Integer ratio = ev.getProgressRatio();
-
-    if (additionalDetails != null)
-    {
-      progressDetails.append(additionalDetails);
-    }
-
-    return new UninstallProgressDescriptor(status, ratio, newProgressLabel,
+    return new ProgressDescriptor(status, ratio, newProgressLabel,
         progressDetails.toString());
   }
 
diff --git a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/InstallException.java b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/QuickSetupException.java
similarity index 87%
rename from opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/InstallException.java
rename to opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/QuickSetupException.java
index 772d9a9..49dc8fa 100644
--- a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/InstallException.java
+++ b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/QuickSetupException.java
@@ -25,23 +25,20 @@
  *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
  */
 
-package org.opends.quicksetup.installer;
+package org.opends.quicksetup;
 
 /**
  * This exception is used to encapsulate all the error that we might have
  * during the installation.
- *
- * @see Installer, WebStartInstaller, OfflineInstaller.
- *
  */
-public class InstallException extends Exception
+public class QuickSetupException extends Exception
 {
   private static final long serialVersionUID = -3527273444231560341L;
 
   private Type type;
 
   /**
-   * This enum contains the different type of InstallException that we can
+   * This enum contains the different type of QuickSetupException that we can
    * have.
    *
    */
@@ -81,12 +78,14 @@
   };
 
   /**
-   * The constructor of the InstallException.
+   * The constructor of the QuickSetupException.
    * @param type the type of error we have.
    * @param localizedMsg a localized string describing the problem.
    * @param rootCause the root cause of this exception.
    */
-  public InstallException(Type type, String localizedMsg, Throwable rootCause)
+  public QuickSetupException(Type type,
+                             String localizedMsg,
+                             Throwable rootCause)
   {
     super(localizedMsg, rootCause);
     this.type = type;
diff --git a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/SplashScreen.java b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/SplashScreen.java
index 47e7a3f..fd64e12 100644
--- a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/SplashScreen.java
+++ b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/SplashScreen.java
@@ -222,7 +222,7 @@
 
   /**
    * This method displays the QuickSetup dialog.
-   * @see QuickSetup.display.
+   * @see QuickSetup#display
    * This method assumes that is being called outside the event thread.
    * This method can be overwritten by subclasses to construct other objects
    * different than the Quick Setup.
diff --git a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/UserInstallData.java b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/UserData.java
similarity index 86%
rename from opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/UserInstallData.java
rename to opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/UserData.java
index 8057162..d47efa2 100644
--- a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/UserInstallData.java
+++ b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/UserData.java
@@ -22,33 +22,24 @@
  * CDDL HEADER END
  *
  *
- *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
+ *      Portions Copyright 2007 Sun Microsystems, Inc.
  */
 
-package org.opends.quicksetup.installer;
+package org.opends.quicksetup;
 
 /**
- * This class is used to provide a data model for the different parameters
- * that the user can provide in the installation wizard.
- *
- * @see DataOptions.
- *
+ * Represents user specified input data to an application.
  */
-public class UserInstallData
-{
+public class UserData {
+
   private String serverLocation;
-
   private int serverPort;
-
-  private int serverJMXPort;
-
   private String directoryManagerDn;
-
   private String directoryManagerPwd;
-
-  private boolean startServer;
-
   private DataOptions dataOptions;
+  private int serverJMXPort;
+  private boolean startServer;
+  private boolean stopServer;
 
   /**
    * Sets the location of the server (installation path).
@@ -87,24 +78,6 @@
   }
 
   /**
-   * Sets the server JMX port.
-   * @param serverJMXPort the new server JMX port.
-   */
-  public void setServerJMXPort(int serverJMXPort)
-  {
-    this.serverJMXPort = serverJMXPort;
-  }
-
-  /**
-   * Returns the server JMX port.
-   * @return the server JMX port.
-   */
-  public int getServerJMXPort()
-  {
-    return serverJMXPort;
-  }
-
-  /**
    * Returns the Directory Manager DN.
    * @return the Directory Manager DN.
    */
@@ -141,6 +114,46 @@
   }
 
   /**
+   * Returns the DataOptions object representing the data in the Data Options
+   * panel.
+   * @return the DataOptions object representing the data in the Data Options
+   * panel.
+   */
+  public DataOptions getDataOptions()
+  {
+    return dataOptions;
+  }
+
+  /**
+   * Sets the DataOptions object representing the data in the Data Options
+   * panel.
+   * @param dataOptions the DataOptions object representing the data in the Data
+   * Options panel.
+   */
+  public void setDataOptions(DataOptions dataOptions)
+  {
+    this.dataOptions = dataOptions;
+  }
+
+  /**
+   * Sets the server JMX port.
+   * @param serverJMXPort the new server JMX port.
+   */
+  public void setServerJMXPort(int serverJMXPort)
+  {
+    this.serverJMXPort = serverJMXPort;
+  }
+
+  /**
+   * Returns the server JMX port.
+   * @return the server JMX port.
+   */
+  public int getServerJMXPort()
+  {
+    return serverJMXPort;
+  }
+
+  /**
    * Returns <CODE>true</CODE> if the server must be started once the
    * installation is finished, <CODE>false</CODE> if not.
    * @return <CODE>true</CODE> if the server must be started once the
@@ -163,24 +176,21 @@
   }
 
   /**
-   * Returns the DataOptions object representing the data in the Data Options
-   * panel.
-   * @return the DataOptions object representing the data in the Data Options
-   * panel.
+   * Sets whether to stop the server or not.
+   * @param stopServer stop the server or not.
    */
-  public DataOptions getDataOptions()
+  public void setStopServer(boolean stopServer)
   {
-    return dataOptions;
+    this.stopServer = stopServer;
   }
 
   /**
-   * Sets the DataOptions object representing the data in the Data Options
-   * panel.
-   * @param dataOptions the DataOptions object representing the data in the Data
-   * Options panel.
+   * Returns whether the user wants to stop the server or not.
+   * @return <CODE>true</CODE> if the user wants to stop the server and <CODE>\
+   * false</CODE> otherwise.
    */
-  public void setDataOptions(DataOptions dataOptions)
+  public boolean getStopServer()
   {
-    this.dataOptions = dataOptions;
+    return stopServer;
   }
 }
diff --git a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/UserInstallDataException.java b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/UserDataException.java
similarity index 88%
rename from opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/UserInstallDataException.java
rename to opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/UserDataException.java
index 96d4a51..2fcf813 100644
--- a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/UserInstallDataException.java
+++ b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/UserDataException.java
@@ -25,9 +25,7 @@
  *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
  */
 
-package org.opends.quicksetup.installer;
-
-import org.opends.quicksetup.Step;
+package org.opends.quicksetup;
 
 /**
  * This exception is used when there is an error with the data provided by
@@ -35,7 +33,7 @@
  * the user data (QuickSetup).
  *
  */
-public class UserInstallDataException extends Exception
+public class UserDataException extends Exception
 {
   private static final long serialVersionUID = 1798143194655443132L;
 
@@ -44,11 +42,11 @@
   private String localizedMessage;
 
   /**
-   * Constructor for UserInstallDataException.
+   * Constructor for UserDataException.
    * @param step the step in the wizard where the exception occurred.
    * @param localizedMessage the localized message describing the error.
    */
-  public UserInstallDataException(Step step, String localizedMessage)
+  public UserDataException(Step step, String localizedMessage)
   {
     super(localizedMessage);
     this.step = step;
diff --git a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/event/ProgressNotifier.java b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/event/ProgressNotifier.java
new file mode 100644
index 0000000..ea3609a
--- /dev/null
+++ b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/event/ProgressNotifier.java
@@ -0,0 +1,64 @@
+/*
+ * 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.event;
+
+/**
+ * Inteface for applications that advertise status to interested
+ * listeners.
+ */
+public interface ProgressNotifier {
+
+  /**
+   * Adds a listener to the list of those that are
+   * notified about the progress state change of
+   * an application.
+   * @param l ProgressUpdateListener
+   */
+  void addProgressUpdateListener(ProgressUpdateListener l);
+
+  /**
+   * Removes a listener from this list of those that
+   * are notified about a progress state change.
+   * @param l ProgressUpdateListener
+   */
+  void removeProgressUpdateListener(ProgressUpdateListener l);
+
+  /**
+   * Notifies all registered listeners about a change
+   * in progress state.
+   * @param ratio Integer specifying the percentage of the whole
+   *        process that has been completed
+   * @param currentPhaseSummary localized summary message for
+   *        the current installation progress in formatted
+   *        form
+   * @param newLogDetail new log messages in formatted form
+   */
+  void notifyListeners(Integer ratio, String currentPhaseSummary,
+      String newLogDetail);
+
+}
diff --git a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/event/InstallProgressUpdateEvent.java b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/event/ProgressUpdateEvent.java
similarity index 86%
rename from opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/event/InstallProgressUpdateEvent.java
rename to opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/event/ProgressUpdateEvent.java
index 8bc0f32..2db1393 100644
--- a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/event/InstallProgressUpdateEvent.java
+++ b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/event/ProgressUpdateEvent.java
@@ -27,7 +27,7 @@
 
 package org.opends.quicksetup.event;
 
-import org.opends.quicksetup.installer.InstallProgressStep;
+import org.opends.quicksetup.ProgressStep;
 
 /**
  * The event that is generated when there is a change during the installation
@@ -36,12 +36,11 @@
  *
  * In the current implementation this events are generated by the Installer
  * objects and are notified to the objects implementing
- * InstallProgressUpdateListener (QuickSetup object).
+ * ProgressUpdateListener (QuickSetup object).
  *
  */
-public class InstallProgressUpdateEvent
-{
-  private InstallProgressStep step;
+public class ProgressUpdateEvent {
+  private ProgressStep step;
 
   private Integer progressRatio;
 
@@ -50,8 +49,8 @@
   private String newLogs;
 
   /**
-   * Constructor of the InstallProgressUpdateEvent.
-   * @param step the InstallProgressStep object describing in which step
+   * Constructor of the ProgressUpdateEvent.
+   * @param step the ProgressStep object describing in which step
    * of the installation we are (configuring server, starting server, etc.)
    * @param progressRatio the integer that specifies which percentage of
    * the whole installation has been completed.
@@ -59,7 +58,7 @@
    * current installation progress.
    * @param newLogs the new log messages that we have for the installation.
    */
-  public InstallProgressUpdateEvent(InstallProgressStep step,
+  public ProgressUpdateEvent(ProgressStep step,
       Integer progressRatio, String currentPhaseSummary, String newLogs)
   {
     this.step = step;
@@ -100,7 +99,7 @@
    * Gets the current progress step.
    * @return the current progress step.
    */
-  public InstallProgressStep getProgressStep()
+  public ProgressStep getProgressStep()
   {
     return step;
   }
diff --git a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/event/InstallProgressUpdateListener.java b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/event/ProgressUpdateListener.java
similarity index 87%
rename from opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/event/InstallProgressUpdateListener.java
rename to opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/event/ProgressUpdateListener.java
index c255090..334f7e1 100644
--- a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/event/InstallProgressUpdateListener.java
+++ b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/event/ProgressUpdateListener.java
@@ -32,13 +32,14 @@
  * updates in the installation progress.
  *
  */
-public interface InstallProgressUpdateListener
-{
+public interface ProgressUpdateListener {
+
   /**
    * Method called when an update in the installation progress occurs.
    *
-   * @param ev the InstallProgressUpdateEvent describing the update that
+   * @param ev the ProgressUpdateEvent describing the update that
    * occurred in the installation progress.
    */
-  public void progressUpdate(InstallProgressUpdateEvent ev);
+  public void progressUpdate(ProgressUpdateEvent ev);
+
 }
diff --git a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/event/UninstallProgressUpdateEvent.java b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/event/UninstallProgressUpdateEvent.java
deleted file mode 100644
index 83df122..0000000
--- a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/event/UninstallProgressUpdateEvent.java
+++ /dev/null
@@ -1,107 +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 2006-2007 Sun Microsystems, Inc.
- */
-
-package org.opends.quicksetup.event;
-
-import org.opends.quicksetup.uninstaller.UninstallProgressStep;
-
-/**
- * The event that is generated when there is a change during the uninstallation
- * process (we get a new log message when starting the server, or we finished
- * configuring the server for instance).
- *
- * In the current implementation this events are generated by the Uninstaller
- * object and are notified to the objects implementing
- * UninstallProgressUpdateListener (QuickSetup object).
- *
- */
-public class UninstallProgressUpdateEvent
-{
-  private UninstallProgressStep step;
-
-  private Integer progressRatio;
-
-  private String currentPhaseSummary;
-
-  private String newLogs;
-
-  /**
-   * Constructor of the UninstallProgressUpdateEvent.
-   * @param step the UninstallProgressStep object describing in which step
-   * of the installation we are (configuring server, starting server, etc.)
-   * @param progressRatio the integer that specifies which percentage of
-   * the whole installation has been completed.
-   * @param currentPhaseSummary the localized summary message for the
-   * current installation progress.
-   * @param newLogs the new log messages that we have for the installation.
-   */
-  public UninstallProgressUpdateEvent(UninstallProgressStep step,
-      Integer progressRatio, String currentPhaseSummary, String newLogs)
-  {
-    this.step = step;
-    this.progressRatio = progressRatio;
-    this.currentPhaseSummary = currentPhaseSummary;
-    this.newLogs = newLogs;
-  }
-
-  /**
-   * Gets a localized message summary describing the install progress
-   * status.
-   * @return the localized message summary describing the progress status.
-   */
-  public String getCurrentPhaseSummary()
-  {
-    return currentPhaseSummary;
-  }
-
-  /**
-   * Gets the new logs for the install progress.
-   * @return the new logs for the current install progress.
-   */
-  public String getNewLogs()
-  {
-    return newLogs;
-  }
-
-  /**
-   * Gets the progress ratio for the install progress.
-   * @return the progress ratio for the install progress.
-   */
-  public Integer getProgressRatio()
-  {
-    return progressRatio;
-  }
-
-  /**
-   * Gets the current progress step.
-   * @return the current progress step.
-   */
-  public UninstallProgressStep getProgressStep()
-  {
-    return step;
-  }
-}
diff --git a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/InstallLauncher.java b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/InstallLauncher.java
index 165edc2..a9da5e9 100644
--- a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/InstallLauncher.java
+++ b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/InstallLauncher.java
@@ -120,6 +120,8 @@
       }
     } else
     {
+      System.setProperty("org.opends.quicksetup.Application.class",
+              "org.opends.quicksetup.installer.offline.OfflineInstaller");
       int exitCode = launchGuiSetup(args);
       if (exitCode != 0)
       {
diff --git a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/InstallProgressStep.java b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/InstallProgressStep.java
index df25583..e9637d0 100644
--- a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/InstallProgressStep.java
+++ b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/InstallProgressStep.java
@@ -27,56 +27,82 @@
 
 package org.opends.quicksetup.installer;
 
+import org.opends.quicksetup.ProgressStep;
+
 /**
- * This enumeration describes the different installation steps in which we can
- * be.
+ * Enumeration of installation steps.
  */
-public enum InstallProgressStep
-{
+public enum InstallProgressStep implements ProgressStep {
+
   /**
    * Install not started.
    */
   NOT_STARTED,
+
   /**
    * Downloading the remote jar files (this step is specific to the Web Start
    * installation).
    */
   DOWNLOADING,
+
   /**
    * Extracting the zip file (this step is specific to the Web Start
    * installation).
    */
   EXTRACTING,
+
   /**
    * Configuring server.
    */
   CONFIGURING_SERVER,
+
   /**
    * Creating base entry for the suffix.
    */
   CREATING_BASE_ENTRY,
+
   /**
    * Importing the contents of an LDIF file into the suffix.
    */
   IMPORTING_LDIF,
+
   /**
    * Importing generated data into the suffix.
    */
   IMPORTING_AUTOMATICALLY_GENERATED,
+
   /**
    * Starting Open DS server.
    */
   STARTING_SERVER,
+
   /**
    * Enabling Windows service.
    */
   ENABLING_WINDOWS_SERVICE,
+
   /**
    * Installation finished successfully.
    */
   FINISHED_SUCCESSFULLY,
+
   /**
    * Installation finished with an error.
    */
-  FINISHED_WITH_ERROR
+  FINISHED_WITH_ERROR;
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean isLast() {
+    return this == FINISHED_SUCCESSFULLY ||
+    this == FINISHED_WITH_ERROR;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean isError() {
+    return this.equals(FINISHED_WITH_ERROR);
+  }
 }
diff --git a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/Installer.java b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/Installer.java
index c972175..d4a66e1 100644
--- a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/Installer.java
+++ b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/Installer.java
@@ -26,24 +26,14 @@
  */
 package org.opends.quicksetup.installer;
 
-import java.io.BufferedReader;
-import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.PrintStream;
 import java.util.ArrayList;
-import java.util.HashSet;
 import java.util.Map;
 
-import javax.naming.NamingException;
-
-import org.opends.quicksetup.event.InstallProgressUpdateEvent;
-import org.opends.quicksetup.event.InstallProgressUpdateListener;
-import org.opends.quicksetup.i18n.ResourceProvider;
 import org.opends.quicksetup.ui.UIFactory;
-import org.opends.quicksetup.util.ProgressMessageFormatter;
 import org.opends.quicksetup.util.Utils;
+import org.opends.quicksetup.*;
 import org.opends.server.util.SetupUtils;
 
 
@@ -51,11 +41,11 @@
  * This is an abstract class that is in charge of actually performing the
  * installation.
  *
- * It just takes a UserInstallData object and based on that installs OpenDS.
+ * It just takes a UserData object and based on that installs OpenDS.
  *
  * When there is an update during the installation it will notify the
- * InstallProgressUpdateListener objects that have been added to it.  The
- * notification will send a InstallProgressUpdateEvent.
+ * ProgressUpdateListener objects that have been added to it.  The
+ * notification will send a ProgressUpdateEvent.
  *
  * This class is supposed to be fully independent of the graphical layout.
  *
@@ -63,70 +53,7 @@
  * it is included in quicksetup.jar.
  *
  */
-public abstract class Installer
-{
-  /**
-   * The path to the Configuration LDIF file.
-   */
-  protected static final String CONFIG_PATH_RELATIVE =
-      "config" + File.separator + "config.ldif";
-
-  private HashSet<InstallProgressUpdateListener> listeners =
-      new HashSet<InstallProgressUpdateListener>();
-
-  private UserInstallData userData;
-
-  private ProgressMessageFormatter formatter;
-
-  /**
-   * Constructor to be used by the subclasses.
-   * @param userData the user data definining the parameters of the
-   * installation.
-   * @param formatter the message formatter to be used to generate the text of
-   * the InstallProgressUpdateEvent
-   */
-  protected Installer(UserInstallData userData,
-      ProgressMessageFormatter formatter)
-  {
-    this.userData = userData;
-    this.formatter = formatter;
-  }
-
-  /**
-   * Adds a InstallProgressUpdateListener that will be notified of updates in
-   * the install progress.
-   * @param l the InstallProgressUpdateListener to be added.
-   */
-  public void addProgressUpdateListener(InstallProgressUpdateListener l)
-  {
-    listeners.add(l);
-  }
-
-  /**
-   * Removes a InstallProgressUpdateListener.
-   * @param l the InstallProgressUpdateListener to be removed.
-   */
-  public void removeProgressUpdateListener(InstallProgressUpdateListener l)
-  {
-    listeners.remove(l);
-  }
-
-  /**
-   * Returns whether the installer has finished or not.
-   * @return <CODE>true</CODE> if the install is finished or <CODE>false
-   * </CODE> if not.
-   */
-  public boolean isFinished()
-  {
-    return getStatus() == InstallProgressStep.FINISHED_SUCCESSFULLY
-        || getStatus() == InstallProgressStep.FINISHED_WITH_ERROR;
-  }
-
-  /**
-   * Start the installation process.  This method will not block the thread on
-   * which is invoked.
-   */
-  public abstract void start();
+public abstract class Installer extends Application {
 
   /**
    * An static String that contains the class name of ConfigFileHandler.
@@ -134,246 +61,16 @@
   protected static final String CONFIG_CLASS_NAME =
       "org.opends.server.extensions.ConfigFileHandler";
 
+  /** Indicates the current progress step. */
+  protected InstallProgressStep status =
+          InstallProgressStep.NOT_STARTED;
 
   /**
-   * Returns the UserInstallData object representing the parameters provided by
-   * the user to do the installation.
-   *
-   * @return the UserInstallData object representing the parameters provided
-   * by the user to do the installation.
+   * {@inheritDoc}
    */
-  protected UserInstallData getUserData()
+  public ProgressStep getStatus()
   {
-    return userData;
-  }
-
-  /**
-   * This method notifies the InstallProgressUpdateListeners that there was an
-   * update in the installation progress.
-   * @param ratio the integer that specifies which percentage of
-   * the whole installation has been completed.
-   * @param currentPhaseSummary the localized summary message for the
-   * current installation progress in formatted form.
-   * @param newLogDetail the new log messages that we have for the
-   * installation in formatted form.
-   */
-  protected void notifyListeners(Integer ratio, String currentPhaseSummary,
-      String newLogDetail)
-  {
-    InstallProgressUpdateEvent ev =
-        new InstallProgressUpdateEvent(getStatus(), ratio, currentPhaseSummary,
-            newLogDetail);
-    for (InstallProgressUpdateListener l : listeners)
-    {
-      l.progressUpdate(ev);
-    }
-  }
-
-  /**
-   * Returns a localized message for a key value.  In  the properties file we
-   * have something of type:
-   * key=value
-   *
-   * @see ResourceProvider.getMsg(String key)
-   * @param key the key in the properties file.
-   * @return the value associated to the key in the properties file.
-   * properties file.
-   */
-  protected String getMsg(String key)
-  {
-    return getI18n().getMsg(key);
-  }
-
-  /**
-   * Returns a localized message for a key value.  In  the properties file we
-   * have something of type:
-   * key=value
-   *
-   * For instance if we pass as key "mykey" and as arguments {"value1"} and
-   * in the properties file we have:
-   * mykey=value with argument {0}.
-   *
-   * This method will return "value with argument value1".
-   * @see ResourceProvider.getMsg(String key, String[] args)
-   * @param key the key in the properties file.
-   * @param args the arguments to be passed to generate the resulting value.
-   * @return the value associated to the key in the properties file.
-   */
-  protected String getMsg(String key, String[] args)
-  {
-    return getI18n().getMsg(key, args);
-  }
-
-  /**
-   * Returns a ResourceProvider instance.
-   * @return a ResourceProvider instance.
-   */
-  protected ResourceProvider getI18n()
-  {
-    return ResourceProvider.getInstance();
-  }
-
-  /**
-   * Returns a localized message for a given properties key and throwable.
-   * @param key the key of the message in the properties file.
-   * @param t the throwable for which we want to get a message.
-   * @return a localized message for a given properties key and throwable.
-   */
-  protected String getThrowableMsg(String key, Throwable t)
-  {
-    return getThrowableMsg(key, null, t);
-  }
-
-  /**
-   * Returns a localized message for a given properties key and throwable.
-   * @param key the key of the message in the properties file.
-   * @param args the arguments of the message in the properties file.
-   * @param t the throwable for which we want to get a message.
-   *
-   * @return a localized message for a given properties key and throwable.
-   */
-  protected String getThrowableMsg(String key, String[] args, Throwable t)
-  {
-    return Utils.getThrowableMsg(getI18n(), key, args, t);
-  }
-
-  /**
-   * Returns the formatted representation of the text that is the summary of the
-   * installation process (the one that goes in the UI next to the progress
-   * bar).
-   * @param text the source text from which we want to get the formatted
-   * representation
-   * @return the formatted representation of an error for the given text.
-   */
-  protected String getFormattedSummary(String text)
-  {
-    return formatter.getFormattedSummary(text);
-  }
-
-  /**
-   * Returns the formatted representation of an error for a given text.
-   * @param text the source text from which we want to get the formatted
-   * representation
-   * @return the formatted representation of an error for the given text.
-   */
-  protected String getFormattedError(String text)
-  {
-    return formatter.getFormattedError(text, false);
-  }
-
-  /**
-   * Returns the formatted representation of an warning for a given text.
-   * @param text the source text from which we want to get the formatted
-   * representation
-   * @return the formatted representation of an warning for the given text.
-   */
-  protected String getFormattedWarning(String text)
-  {
-    return formatter.getFormattedWarning(text, false);
-  }
-
-  /**
-   * Returns the formatted representation of a success message for a given text.
-   * @param text the source text from which we want to get the formatted
-   * representation
-   * @return the formatted representation of an success message for the given
-   * text.
-   */
-  protected String getFormattedSuccess(String text)
-  {
-    return formatter.getFormattedSuccess(text);
-  }
-
-  /**
-   * Returns the formatted representation of a log error message for a given
-   * text.
-   * @param text the source text from which we want to get the formatted
-   * representation
-   * @return the formatted representation of a log error message for the given
-   * text.
-   */
-  protected String getFormattedLogError(String text)
-  {
-    return formatter.getFormattedLogError(text);
-  }
-
-  /**
-   * Returns the formatted representation of a log message for a given text.
-   * @param text the source text from which we want to get the formatted
-   * representation
-   * @return the formatted representation of a log message for the given text.
-   */
-  protected String getFormattedLog(String text)
-  {
-    return formatter.getFormattedLog(text);
-  }
-
-  /**
-   * Returns the formatted representation of the 'Done' text string.
-   * @return the formatted representation of the 'Done' text string.
-   */
-  protected String getFormattedDone()
-  {
-    return formatter.getFormattedDone();
-  }
-
-  /**
-   * Returns the formatted representation of the argument text to which we add
-   * points.  For instance if we pass as argument 'Configuring Server' the
-   * return value will be 'Configuring Server .....'.
-   * @param text the String to which add points.
-   * @return the formatted representation of the '.....' text string.
-   */
-  protected String getFormattedWithPoints(String text)
-  {
-    return formatter.getFormattedWithPoints(text);
-  }
-
-  /**
-   * Returns the formatted representation of a progress message for a given
-   * text.
-   * @param text the source text from which we want to get the formatted
-   * representation
-   * @return the formatted representation of a progress message for the given
-   * text.
-   */
-  protected String getFormattedProgress(String text)
-  {
-    return formatter.getFormattedProgress(text);
-  }
-
-  /**
-   * Returns the formatted representation of an error message for a given
-   * exception.
-   * This method applies a margin if the applyMargin parameter is
-   * <CODE>true</CODE>.
-   * @param ex the exception.
-   * @param applyMargin specifies whether we apply a margin or not to the
-   * resulting formatted text.
-   * @return the formatted representation of an error message for the given
-   * exception.
-   */
-  protected String getFormattedError(Exception ex, boolean applyMargin)
-  {
-    return formatter.getFormattedError(ex, applyMargin);
-  }
-
-  /**
-   * Returns the line break formatted.
-   * @return the line break formatted.
-   */
-  protected String getLineBreak()
-  {
-    return formatter.getLineBreak();
-  }
-
-  /**
-   * Returns the task separator formatted.
-   * @return the task separator formatted.
-   */
-  protected String getTaskSeparator()
-  {
-    return formatter.getTaskSeparator();
+    return status;
   }
 
   /**
@@ -383,10 +80,9 @@
    * the base dn and the number of entries to be generated.
    *
    * @return the file object pointing to the create template file.
-   * @throws InstallException if an error occurs.
+   * @throws QuickSetupException if an error occurs.
    */
-  protected File createTemplateFile() throws InstallException
-  {
+  protected File createTemplateFile() throws QuickSetupException {
     try
     {
       return SetupUtils.createTemplateFile(
@@ -396,278 +92,17 @@
     catch (IOException ioe)
     {
       String failedMsg = getThrowableMsg("error-creating-temp-file", null, ioe);
-      throw new InstallException(InstallException.Type.FILE_SYSTEM_ERROR,
+      throw new QuickSetupException(QuickSetupException.Type.FILE_SYSTEM_ERROR,
           failedMsg, ioe);
     }
   }
 
   /**
-   * This method is called when a new log message has been received.  It will
-   * notify the InstallProgressUpdateListeners of this fact.
-   * @param newLogDetail the new log detail.
-   */
-  protected void notifyListeners(String newLogDetail)
-  {
-    Integer ratio = getRatio(getStatus());
-    String currentPhaseSummary = getSummary(getStatus());
-    notifyListeners(ratio, currentPhaseSummary, newLogDetail);
-  }
-
-  /**
-   * Returns the current InstallProgressStep of the installation process.
-   * @return the current InstallProgressStep of the installation process.
-   */
-  protected abstract InstallProgressStep getStatus();
-
-  /**
-   * Returns an integer that specifies which percentage of the whole
-   * installation has been completed.
-   * @param step the InstallProgressStep for which we want to get the ratio.
-   * @return an integer that specifies which percentage of the whole
-   * installation has been completed.
-   */
-  protected abstract Integer getRatio(InstallProgressStep step);
-
-  /**
-   * Returns an formatted representation of the summary for the specified
-   * InstallProgressStep.
-   * @param step the InstallProgressStep for which we want to get the summary
-   * @return an formatted representation of the summary for the specified
-   * InstallProgressStep.
-   */
-  protected abstract String getSummary(InstallProgressStep step);
-
-  /**
-   * This class is used to read the standard error and standard output of the
-   * Start process.
-   *
-   * When a new log message is found notifies the InstallProgressUpdateListeners
-   * of it. If an error occurs it also notifies the listeners.
-   *
-   */
-  private class StartReader
-  {
-    private InstallException ex;
-
-    private boolean isFinished;
-
-    private boolean isFirstLine;
-
-    /**
-     * The protected constructor.
-     * @param reader the BufferedReader of the start process.
-     * @param startedId the message ID that this class can use to know whether
-     * the start is over or not.
-     * @param isError a boolean indicating whether the BufferedReader
-     * corresponds to the standard error or to the standard output.
-     */
-    public StartReader(final BufferedReader reader, final String startedId,
-        final boolean isError)
-    {
-      final String errorTag =
-          isError ? "error-reading-erroroutput" : "error-reading-output";
-
-      isFirstLine = true;
-
-      Thread t = new Thread(new Runnable()
-      {
-        public void run()
-        {
-          try
-          {
-            String line = reader.readLine();
-            while (line != null)
-            {
-              StringBuffer buf = new StringBuffer();
-              if (!isFirstLine)
-              {
-                buf.append(formatter.getLineBreak());
-              }
-              if (isError)
-              {
-                buf.append(getFormattedLogError(line));
-              } else
-              {
-                buf.append(getFormattedLog(line));
-              }
-              notifyListeners(buf.toString());
-              isFirstLine = false;
-
-              if (line.indexOf("id=" + startedId) != -1)
-              {
-                isFinished = true;
-              }
-              line = reader.readLine();
-            }
-          } catch (IOException ioe)
-          {
-            String errorMsg = getThrowableMsg(errorTag, ioe);
-            ex =
-                new InstallException(InstallException.Type.START_ERROR,
-                    errorMsg, ioe);
-
-          } catch (Throwable t)
-          {
-            String errorMsg = getThrowableMsg(errorTag, t);
-            ex =
-                new InstallException(InstallException.Type.START_ERROR,
-                    errorMsg, t);
-          }
-          isFinished = true;
-        }
-      });
-      t.start();
-    }
-
-    /**
-     * Returns the InstallException that occurred reading the Start error and
-     * output or <CODE>null</CODE> if no exception occurred.
-     * @return the exception that occurred reading or <CODE>null</CODE> if
-     * no exception occurred.
-     */
-    public InstallException getException()
-    {
-      return ex;
-    }
-
-    /**
-     * Returns <CODE>true</CODE> if the server starting process finished
-     * (successfully or not) and <CODE>false</CODE> otherwise.
-     * @return <CODE>true</CODE> if the server starting process finished
-     * (successfully or not) and <CODE>false</CODE> otherwise.
-     */
-    public boolean isFinished()
-    {
-      return isFinished;
-    }
-  }
-
-  /**
-   * This class is used to notify the InstallProgressUpdateListeners of events
-   * that are written to the standard error.  It is used in WebStartInstaller
-   * and in OfflineInstaller.  These classes just create a ErrorPrintStream and
-   * then they do a call to System.err with it.
-   *
-   * The class just reads what is written to the standard error, obtains an
-   * formatted representation of it and then notifies the
-   * InstallProgressUpdateListeners with the formatted messages.
-   *
-   */
-  protected class ErrorPrintStream extends PrintStream
-  {
-    private boolean isFirstLine;
-
-    /**
-     * Default constructor.
-     *
-     */
-    public ErrorPrintStream()
-    {
-      super(new ByteArrayOutputStream(), true);
-      isFirstLine = true;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public void println(String msg)
-    {
-      if (isFirstLine)
-      {
-        notifyListeners(getFormattedLogError(msg));
-      } else
-      {
-        notifyListeners(formatter.getLineBreak() + getFormattedLogError(msg));
-      }
-      isFirstLine = false;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public void write(byte[] b, int off, int len)
-    {
-      if (b == null)
-      {
-        throw new NullPointerException("b is null");
-      }
-
-      if (off + len > b.length)
-      {
-        throw new IndexOutOfBoundsException(
-            "len + off are bigger than the length of the byte array");
-      }
-      println(new String(b, off, len));
-    }
-  }
-
-  /**
-   * This class is used to notify the InstallProgressUpdateListeners of events
-   * that are written to the standard output. It is used in WebStartInstaller
-   * and in OfflineInstaller. These classes just create a OutputPrintStream and
-   * then they do a call to System.out with it.
-   *
-   * The class just reads what is written to the standard output, obtains an
-   * formatted representation of it and then notifies the
-   * InstallProgressUpdateListeners with the formatted messages.
-   *
-   */
-  protected class OutputPrintStream extends PrintStream
-  {
-    private boolean isFirstLine;
-
-    /**
-     * Default constructor.
-     *
-     */
-    public OutputPrintStream()
-    {
-      super(new ByteArrayOutputStream(), true);
-      isFirstLine = true;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public void println(String msg)
-    {
-      if (isFirstLine)
-      {
-        notifyListeners(getFormattedLog(msg));
-      } else
-      {
-        notifyListeners(formatter.getLineBreak() + getFormattedLog(msg));
-      }
-      isFirstLine = false;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public void write(byte[] b, int off, int len)
-    {
-      if (b == null)
-      {
-        throw new NullPointerException("b is null");
-      }
-
-      if (off + len > b.length)
-      {
-        throw new IndexOutOfBoundsException(
-            "len + off are bigger than the length of the byte array");
-      }
-
-      println(new String(b, off, len));
-    }
-  }
-
-  /**
    * This methods configures the server based on the contents of the UserData
    * object provided in the constructor.
-   * @throws InstallException if something goes wrong.
+   * @throws QuickSetupException if something goes wrong.
    */
-  protected void configureServer() throws InstallException
-  {
+  protected void configureServer() throws QuickSetupException {
     notifyListeners(getFormattedWithPoints(getMsg("progress-configuring")));
 
     ArrayList<String> argList = new ArrayList<String>();
@@ -699,14 +134,14 @@
 
       if (result != 0)
       {
-        throw new InstallException(
-            InstallException.Type.CONFIGURATION_ERROR,
+        throw new QuickSetupException(
+            QuickSetupException.Type.CONFIGURATION_ERROR,
             getMsg("error-configuring"), null);
       }
     } catch (Throwable t)
     {
-      throw new InstallException(
-          InstallException.Type.CONFIGURATION_ERROR,
+      throw new QuickSetupException(
+          QuickSetupException.Type.CONFIGURATION_ERROR,
           getThrowableMsg("error-configuring", null, t), t);
     }
   }
@@ -714,10 +149,9 @@
   /**
    * This methods creates the base entry for the suffix based on the contents of
    * the UserData object provided in the constructor.
-   * @throws InstallException if something goes wrong.
+   * @throws QuickSetupException if something goes wrong.
    */
-  protected void createBaseEntry() throws InstallException
-  {
+  protected void createBaseEntry() throws QuickSetupException {
     String[] arg =
       { getUserData().getDataOptions().getBaseDn() };
     notifyListeners(getFormattedWithPoints(
@@ -751,14 +185,14 @@
 
       if (result != 0)
       {
-        throw new InstallException(
-            InstallException.Type.CONFIGURATION_ERROR,
+        throw new QuickSetupException(
+            QuickSetupException.Type.CONFIGURATION_ERROR,
             getMsg("error-creating-base-entry"), null);
       }
     } catch (Throwable t)
     {
-      throw new InstallException(
-          InstallException.Type.CONFIGURATION_ERROR,
+      throw new QuickSetupException(
+          QuickSetupException.Type.CONFIGURATION_ERROR,
           getThrowableMsg("error-creating-base-entry", null, t), t);
     }
 
@@ -768,10 +202,9 @@
   /**
    * This methods imports the contents of an LDIF file based on the contents of
    * the UserData object provided in the constructor.
-   * @throws InstallException if something goes wrong.
+   * @throws QuickSetupException if something goes wrong.
    */
-  protected void importLDIF() throws InstallException
-  {
+  protected void importLDIF() throws QuickSetupException {
     String[] arg =
       { getUserData().getDataOptions().getLDIFPath() };
     notifyListeners(getFormattedProgress(getMsg("progress-importing-ldif", arg))
@@ -798,14 +231,14 @@
 
       if (result != 0)
       {
-        throw new InstallException(
-            InstallException.Type.CONFIGURATION_ERROR,
+        throw new QuickSetupException(
+            QuickSetupException.Type.CONFIGURATION_ERROR,
             getMsg("error-importing-ldif"), null);
       }
     } catch (Throwable t)
     {
-      throw new InstallException(
-          InstallException.Type.CONFIGURATION_ERROR,
+      throw new QuickSetupException(
+          QuickSetupException.Type.CONFIGURATION_ERROR,
           getThrowableMsg("error-importing-ldif", null, t), t);
     }
   }
@@ -813,10 +246,9 @@
   /**
    * This methods imports automatically generated data based on the contents
    * of the UserData object provided in the constructor.
-   * @throws InstallException if something goes wrong.
+   * @throws QuickSetupException if something goes wrong.
    */
-  protected void importAutomaticallyGenerated() throws InstallException
-  {
+  protected void importAutomaticallyGenerated() throws QuickSetupException {
     File templatePath = createTemplateFile();
     int nEntries = getUserData().getDataOptions().getNumberEntries();
     String[] arg =
@@ -848,24 +280,23 @@
 
       if (result != 0)
       {
-        throw new InstallException(
-            InstallException.Type.CONFIGURATION_ERROR,
+        throw new QuickSetupException(
+            QuickSetupException.Type.CONFIGURATION_ERROR,
             getMsg("error-import-automatically-generated"), null);
       }
     } catch (Throwable t)
     {
-      throw new InstallException(
-          InstallException.Type.CONFIGURATION_ERROR,
+      throw new QuickSetupException(
+          QuickSetupException.Type.CONFIGURATION_ERROR,
           getThrowableMsg("error-import-automatically-generated", null, t), t);
     }
   }
 
   /**
    * This methods enables this server as a Windows service.
-   * @throws InstallException if something goes wrong.
+   * @throws QuickSetupException if something goes wrong.
    */
-  protected void enableWindowsService() throws InstallException
-  {
+  protected void enableWindowsService() throws QuickSetupException {
       notifyListeners(getFormattedProgress(
         getMsg("progress-enabling-windows-service")));
       InstallerHelper helper = new InstallerHelper();
@@ -873,164 +304,6 @@
   }
 
   /**
-   * This methods starts the server.
-   * @throws InstallException if something goes wrong.
-   */
-  protected void startServer() throws InstallException
-  {
-    notifyListeners(getFormattedProgress(getMsg("progress-starting")) +
-        getLineBreak());
-
-    ArrayList<String> argList = new ArrayList<String>();
-
-    if (Utils.isWindows())
-    {
-      argList.add(Utils.getPath(getBinariesPath(),
-              Utils.getWindowsStartFileName()));
-    } else
-    {
-      argList.add(Utils.getPath(getBinariesPath(),
-              Utils.getUnixStartFileName()));
-    }
-
-    String[] args = new String[argList.size()];
-    argList.toArray(args);
-    ProcessBuilder pb = new ProcessBuilder(args);
-    Map<String, String> env = pb.environment();
-    env.put("JAVA_HOME", System.getProperty("java.home"));
-    /* Remove JAVA_BIN to be sure that we use the JVM running the installer
-     * JVM to start the server.
-     */
-    env.remove("JAVA_BIN");
-
-    try
-    {
-      String startedId = getStartedId();
-
-      Process process = pb.start();
-
-      BufferedReader err =
-          new BufferedReader(new InputStreamReader(process.getErrorStream()));
-      BufferedReader out =
-          new BufferedReader(new InputStreamReader(process.getInputStream()));
-
-      StartReader errReader = new StartReader(err, startedId, true);
-      StartReader outputReader = new StartReader(out, startedId, false);
-
-      while (!errReader.isFinished() && !outputReader.isFinished())
-      {
-        try
-        {
-          Thread.sleep(100);
-        } catch (InterruptedException ie)
-        {
-        }
-      }
-      // Check if something wrong occurred reading the starting of the server
-      InstallException ex = errReader.getException();
-      if (ex == null)
-      {
-        ex = outputReader.getException();
-      }
-      if (ex != null)
-      {
-        throw ex;
-
-      } else
-      {
-        /*
-         * There are no exceptions from the readers and they are marked as
-         * finished. This means that the server has written in its output the
-         * message id informing that it started. So it seems that everything
-         * went fine.
-         *
-         * However we can have issues with the firewalls or do not have rights
-         * to connect.  Just check if we can connect to the server.
-         * Try 5 times with an interval of 1 second between try.
-         */
-        boolean connected = false;
-        for (int i=0; i<5 && !connected; i++)
-        {
-          String ldapUrl = "ldap://localhost:"+userData.getServerPort();
-          try
-          {
-            Utils.createLdapContext(
-                ldapUrl,
-                userData.getDirectoryManagerDn(),
-                userData.getDirectoryManagerPwd(), 3000, null);
-            connected = true;
-          }
-          catch (NamingException ne)
-          {
-          }
-          if (!connected)
-          {
-            try
-            {
-              Thread.sleep(1000);
-            }
-            catch (Throwable t)
-            {
-            }
-          }
-        }
-        if (!connected)
-        {
-          if (Utils.isWindows())
-          {
-            String[] arg = {String.valueOf(userData.getServerPort())};
-            throw new InstallException(InstallException.Type.START_ERROR,
-                getMsg("error-starting-server-in-windows", arg), null);
-          }
-          else
-          {
-            String[] arg = {String.valueOf(userData.getServerPort())};
-            throw new InstallException(InstallException.Type.START_ERROR,
-                getMsg("error-starting-server-in-unix", arg), null);
-          }
-        }
-      }
-
-    } catch (IOException ioe)
-    {
-      throw new InstallException(InstallException.Type.START_ERROR,
-          getThrowableMsg("error-starting-server", ioe), ioe);
-    }
-  }
-
-  /**
-   * Returns the class path (using the class path separator which is platform
-   * dependent) required to run Open DS server.
-   * @return the class path required to run Open DS server.
-   */
-  protected abstract String getOpenDSClassPath();
-
-  /**
-   * Returns the installation path.
-   * @return the installation path.
-   */
-  protected abstract String getInstallationPath();
-
-  /**
-   * Returns the config file path.
-   * @return the config file path.
-   */
-  protected String getConfigFilePath()
-  {
-    return Utils.getPath(getInstallationPath(), CONFIG_PATH_RELATIVE);
-  }
-
-  /**
-   * Returns the path to the binaries.
-   * @return the path to the binaries.
-   */
-  protected String getBinariesPath()
-  {
-    return Utils.getPath(getInstallationPath(),
-        Utils.getBinariesRelativePath());
-  }
-
-  /**
    * Updates the contents of the provided map with the localized summary
    * strings.
    * @param hmSummary the Map to be updated.
@@ -1096,16 +369,6 @@
   }
 
   /**
-   * Returns the Message ID indicating that the server has started.
-   * @return the Message ID indicating that the server has started.
-   */
-  private String getStartedId()
-  {
-    InstallerHelper helper = new InstallerHelper();
-    return helper.getStartedId();
-  }
-
-  /**
    * Returns the default backend name (the one that will be created).
    * @return the default backend name (the one that will be created).
    */
@@ -1113,4 +376,13 @@
   {
     return "userRoot";
   }
+
+  /**
+   * {@inheritDoc}
+   */
+  protected String getBinariesPath()
+  {
+    return Utils.getPath(getInstallationPath(),
+        Utils.getBinariesRelativePath());
+  }
 }
diff --git a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/offline/OfflineInstaller.java b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/offline/OfflineInstaller.java
index f0b4bf8..58e63c2 100644
--- a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/offline/OfflineInstaller.java
+++ b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/offline/OfflineInstaller.java
@@ -31,11 +31,10 @@
 import java.util.ArrayList;
 import java.util.HashMap;
 
-import org.opends.quicksetup.installer.InstallException;
-import org.opends.quicksetup.installer.InstallProgressStep;
+import org.opends.quicksetup.QuickSetupException;
+import org.opends.quicksetup.ProgressStep;
 import org.opends.quicksetup.installer.Installer;
-import org.opends.quicksetup.installer.UserInstallData;
-import org.opends.quicksetup.util.ProgressMessageFormatter;
+import org.opends.quicksetup.installer.InstallProgressStep;
 import org.opends.quicksetup.util.Utils;
 
 /**
@@ -43,7 +42,7 @@
  * the Directory Server from a zip file.  The installer assumes that the zip
  * file contents have been unzipped.
  *
- * It just takes a UserInstallData object and based on that installs OpenDS.
+ * It just takes a UserData object and based on that installs OpenDS.
  *
  * When there is an update during the installation it will notify the
  * ProgressUpdateListener objects that have been added to it.  The notification
@@ -62,53 +61,13 @@
   private HashMap<InstallProgressStep, String> hmSummary =
       new HashMap<InstallProgressStep, String>();
 
-  private InstallProgressStep status;
-
-  /**
-   * OfflineInstaller constructor.
-   * @param userData the UserInstallData with the parameters provided by the
-   * user.
-   * @param formatter the message formatter to be used to generate the text of
-   * the ProgressUpdateEvent.
-   *
-   */
-  public OfflineInstaller(UserInstallData userData,
-      ProgressMessageFormatter formatter)
-  {
-    super(userData, formatter);
-    initMaps();
-    status = InstallProgressStep.NOT_STARTED;
-  }
-
-  /**
-   * {@inheritDoc}
-   */
-  public void start()
-  {
-    Thread t = new Thread(new Runnable()
-    {
-      public void run()
-      {
-        doInstall();
-      }
-    });
-    t.start();
-  }
-
-  /**
-   * {@inheritDoc}
-   */
-  protected InstallProgressStep getStatus()
-  {
-    return status;
-  }
-
   /**
    * Actually performs the install in this thread.  The thread is blocked.
    *
    */
-  private void doInstall()
+  public void run()
   {
+    initMaps();
     PrintStream origErr = System.err;
     PrintStream origOut = System.out;
     try
@@ -159,7 +118,7 @@
       status = InstallProgressStep.FINISHED_SUCCESSFULLY;
       notifyListeners(null);
 
-    } catch (InstallException ex)
+    } catch (QuickSetupException ex)
     {
       if (ex.getCause() != null)
       {
@@ -172,8 +131,8 @@
     catch (Throwable t)
     {
       status = InstallProgressStep.FINISHED_WITH_ERROR;
-      InstallException ex = new InstallException(
-          InstallException.Type.BUG, getThrowableMsg("bug-msg", t), t);
+      QuickSetupException ex = new QuickSetupException(
+          QuickSetupException.Type.BUG, getThrowableMsg("bug-msg", t), t);
       String msg = getFormattedError(ex, true);
       notifyListeners(msg);
     }
@@ -184,7 +143,7 @@
   /**
    * {@inheritDoc}
    */
-  protected Integer getRatio(InstallProgressStep status)
+  public Integer getRatio(ProgressStep status)
   {
     return hmRatio.get(status);
   }
@@ -192,7 +151,7 @@
   /**
    * {@inheritDoc}
    */
-  protected String getSummary(InstallProgressStep status)
+  public String getSummary(ProgressStep status)
   {
     return hmSummary.get(status);
   }
@@ -211,8 +170,8 @@
      * extracting, the value for downloading will be the double of the value for
      * extracting.
      */
-    HashMap<InstallProgressStep, Integer> hmTime =
-        new HashMap<InstallProgressStep, Integer>();
+    HashMap<ProgressStep, Integer> hmTime =
+        new HashMap<ProgressStep, Integer>();
     hmTime.put(InstallProgressStep.CONFIGURING_SERVER, 5);
     hmTime.put(InstallProgressStep.CREATING_BASE_ENTRY, 10);
     hmTime.put(InstallProgressStep.IMPORTING_LDIF, 20);
diff --git a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/webstart/WebStartDownloader.java b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/webstart/WebStartDownloader.java
index 9d46da2..9e9b706 100644
--- a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/webstart/WebStartDownloader.java
+++ b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/webstart/WebStartDownloader.java
@@ -37,7 +37,8 @@
 import javax.jnlp.UnavailableServiceException;
 
 import org.opends.quicksetup.i18n.ResourceProvider;
-import org.opends.quicksetup.installer.InstallException;
+import org.opends.quicksetup.QuickSetupException;
+import org.opends.quicksetup.webstart.JnlpProperties;
 import org.opends.quicksetup.util.Utils;
 
 /**
@@ -48,12 +49,11 @@
  * (quicksetup.jar) to display the Web Start installer dialog.  Then QuickSetup
  * will call this class and it will download the jar files.  Until this class is
  * not finished the WebStartInstaller will be on the
- * InstallProgressStep.DOWNLOADING step.
+ * ProgressStep.DOWNLOADING step.
  */
 public class WebStartDownloader implements DownloadServiceListener,
-    JnlpProperties
-{
-  private InstallException ex;
+        JnlpProperties {
+  private QuickSetupException ex;
 
   private boolean isFinished;
 
@@ -88,7 +88,7 @@
      * Upgrading a jar file.
      */
     UPGRADING
-    };
+    }
 
   /**
    * Starts the downloading of the jar files.  If forceDownload is set to
@@ -113,7 +113,8 @@
         {
           // This is a bug
           ex =
-              new InstallException(InstallException.Type.BUG, getExceptionMsg(
+              new QuickSetupException(QuickSetupException.Type.BUG,
+                      getExceptionMsg(
                   "bug-msg", mfe), mfe);
         } catch (IOException ioe)
         {
@@ -130,13 +131,14 @@
           String[] arg =
             { buf.toString() };
           ex =
-              new InstallException(InstallException.Type.DOWNLOAD_ERROR,
+              new QuickSetupException(QuickSetupException.Type.DOWNLOAD_ERROR,
                   getExceptionMsg("downloading-error", arg, ioe), ioe);
         } catch (Throwable t)
         {
           // This is a bug
           ex =
-              new InstallException(InstallException.Type.BUG, getExceptionMsg(
+              new QuickSetupException(QuickSetupException.Type.BUG,
+                      getExceptionMsg(
                   "bug-msg", t), t);
         }
       }
@@ -202,9 +204,9 @@
    * @throws IOException if a network problem occurs.
    */
   private void startDownload(boolean forceDownload)
-      throws MalformedURLException, IOException
+      throws IOException
   {
-    DownloadService ds = null;
+    DownloadService ds;
     try
     {
       ds =
@@ -308,12 +310,12 @@
   }
 
   /**
-   * Returns the InstallException that has occurred during the download or
+   * Returns the QuickSetupException that has occurred during the download or
    * <CODE>null</CODE> if no exception occurred.
-   * @return the InstallException that has occurred during the download or
+   * @return the QuickSetupException that has occurred during the download or
    * <CODE>null</CODE> if no exception occurred.
    */
-  public InstallException getException()
+  public QuickSetupException getException()
   {
     return ex;
   }
@@ -324,7 +326,7 @@
   public void downloadFailed(URL url, String version)
   {
     ex =
-        new InstallException(InstallException.Type.DOWNLOAD_ERROR, getMsg(
+        new QuickSetupException(QuickSetupException.Type.DOWNLOAD_ERROR, getMsg(
             "downloading-error", new String[]
               { url.toString() }), null);
   }
@@ -390,10 +392,8 @@
    */
   private int getPercentage(int currentJarRatio)
   {
-    int perc =
-        currentPercMin
+    return currentPercMin
             + (currentJarRatio * (currentPercMax - currentPercMin) / 100);
-    return perc;
   }
 
   /**
diff --git a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/webstart/WebStartInstaller.java b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/webstart/WebStartInstaller.java
index e926c2e..d7cd0c9 100644
--- a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/webstart/WebStartInstaller.java
+++ b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/webstart/WebStartInstaller.java
@@ -28,39 +28,36 @@
 package org.opends.quicksetup.installer.webstart;
 
 import java.io.File;
-import java.io.IOException;
 import java.io.InputStream;
 import java.io.PrintStream;
 import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.Map;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipInputStream;
 
-import org.opends.quicksetup.installer.InstallException;
-import org.opends.quicksetup.installer.InstallProgressStep;
+import org.opends.quicksetup.QuickSetupException;
+import org.opends.quicksetup.ProgressStep;
+import org.opends.quicksetup.webstart.JnlpProperties;
 import org.opends.quicksetup.installer.Installer;
-import org.opends.quicksetup.installer.UserInstallData;
-import org.opends.quicksetup.util.ProgressMessageFormatter;
+import org.opends.quicksetup.installer.InstallProgressStep;
 import org.opends.quicksetup.util.Utils;
+import org.opends.quicksetup.util.ZipExtractor;
 
 /**
  * This is an implementation of the Installer class that is used to install
  * the Directory Server using Web Start.
  *
- * It just takes a UserInstallData object and based on that installs OpenDS.
+ * It just takes a UserData object and based on that installs OpenDS.
  *
  *
  * This object has as parameter a WebStartDownloader object that is downloading
  * some jar files.  Until the WebStartDownloader has not finished downloading
- * the jar files will be on the InstallProgressStep.DOWNLOADING step because
+ * the jar files will be on the ProgressStep.DOWNLOADING step because
  * we require all the jar files to be downloaded in order to install and
  * configure the Directory Server.
  *
  * Based on the Java properties set through the QuickSetup.jnlp file this
  * class will retrieve the zip file containing the install, unzip it and extract
  * it in the path specified by the user and that is contained in the
- * UserInstallData object.
+ * UserData object.
  *
  *
  * When there is an update during the installation it will notify the
@@ -70,65 +67,32 @@
  * This class is supposed to be fully independent of the graphical layout.
  *
  */
-public class WebStartInstaller extends Installer implements JnlpProperties
-{
+public class WebStartInstaller extends Installer implements JnlpProperties {
   private HashMap<InstallProgressStep, Integer> hmRatio =
       new HashMap<InstallProgressStep, Integer>();
 
   private HashMap<InstallProgressStep, String> hmSummary =
       new HashMap<InstallProgressStep, String>();
 
-  private InstallProgressStep status;
-
   private WebStartDownloader loader;
 
   /**
    * WebStartInstaller constructor.
-   * @param userData the UserInstallData with the parameters provided by the
-   * user.
-   * @param loader the WebStartLoader that is used to download the remote jar
-   * files.
-   * @param formatter the message formatter to be used to generate the text of
-   * the ProgressUpdateEvent
    */
-  public WebStartInstaller(UserInstallData userData,
-      WebStartDownloader loader, ProgressMessageFormatter formatter)
+  public WebStartInstaller()
   {
-    super(userData, formatter);
-    this.loader = loader;
-    initMaps();
+    loader = new WebStartDownloader();
+    loader.start(false);
     status = InstallProgressStep.NOT_STARTED;
   }
 
   /**
-   * {@inheritDoc}
-   */
-  public void start()
-  {
-    Thread t = new Thread(new Runnable()
-    {
-      public void run()
-      {
-        doInstall();
-      }
-    });
-    t.start();
-  }
-
-  /**
-   * {@inheritDoc}
-   */
-  protected InstallProgressStep getStatus()
-  {
-    return status;
-  }
-
-  /**
    * Actually performs the install in this thread.  The thread is blocked.
    *
    */
-  private void doInstall()
+  public void run()
   {
+    initMaps();
     PrintStream origErr = System.err;
     PrintStream origOut = System.out;
     try
@@ -190,7 +154,7 @@
       status = InstallProgressStep.FINISHED_SUCCESSFULLY;
       notifyListeners(null);
 
-    } catch (InstallException ex)
+    } catch (QuickSetupException ex)
     {
       status = InstallProgressStep.FINISHED_WITH_ERROR;
       String html = getFormattedError(ex, true);
@@ -199,8 +163,8 @@
     catch (Throwable t)
     {
       status = InstallProgressStep.FINISHED_WITH_ERROR;
-      InstallException ex = new InstallException(
-          InstallException.Type.BUG, getThrowableMsg("bug-msg", t), t);
+      QuickSetupException ex = new QuickSetupException(
+          QuickSetupException.Type.BUG, getThrowableMsg("bug-msg", t), t);
       String msg = getFormattedError(ex, true);
       notifyListeners(msg);
     }
@@ -211,7 +175,7 @@
   /**
    * {@inheritDoc}
    */
-  protected Integer getRatio(InstallProgressStep status)
+  public Integer getRatio(ProgressStep status)
   {
     return hmRatio.get(status);
   }
@@ -219,7 +183,7 @@
   /**
    * {@inheritDoc}
    */
-  protected String getSummary(InstallProgressStep status)
+  public String getSummary(ProgressStep status)
   {
     return hmSummary.get(status);
   }
@@ -259,6 +223,7 @@
     steps.add(InstallProgressStep.EXTRACTING);
     totalTime += hmTime.get(InstallProgressStep.CONFIGURING_SERVER);
     steps.add(InstallProgressStep.CONFIGURING_SERVER);
+
     switch (getUserData().getDataOptions().getType())
     {
     case CREATE_BASE_ENTRY:
@@ -302,20 +267,20 @@
   }
 
   private InputStream getZipInputStream(Integer maxRatio)
-      throws InstallException
-  {
+      throws QuickSetupException {
     notifyListeners(getFormattedWithPoints(getMsg("progress-downloading")));
     InputStream in = null;
 
     waitForLoader(maxRatio);
 
+    String zipName = getZipFileName();
     in =
-      Installer.class.getClassLoader().getResourceAsStream(getZipFileName());
+      Installer.class.getClassLoader().getResourceAsStream(zipName);
 
     if (in == null)
     {
-      throw new InstallException(InstallException.Type.DOWNLOAD_ERROR,
-          getMsg("error-zipinputstreamnull"), null);
+      throw new QuickSetupException(QuickSetupException.Type.DOWNLOAD_ERROR,
+          getMsg("error-zipinputstreamnull", new String[] {zipName}), null);
     }
 
 
@@ -334,10 +299,10 @@
    * process, then maxRatio will be 25.  When the download is complete this
    * method will send a notification to the ProgressUpdateListeners with a ratio
    * of 25 %.
+   * @throws QuickSetupException if something goes wrong
    *
    */
-  private void waitForLoader(Integer maxRatio) throws InstallException
-  {
+  private void waitForLoader(Integer maxRatio) throws QuickSetupException {
     int lastPercentage = -1;
     WebStartDownloader.Status lastStatus =
       WebStartDownloader.Status.DOWNLOADING;
@@ -399,164 +364,17 @@
    * @param maxRatio the value of the ratio in the installation that corresponds
    * to the moment where we finished extracting the last zip file.  Used to
    * update properly the install progress ratio.
-   * @throws InstallException if an error occurs.
+   * @throws QuickSetupException if an error occurs.
    */
   private void extractZipFiles(InputStream is, int minRatio, int maxRatio)
-      throws InstallException
-  {
-    ZipInputStream zipIn = new ZipInputStream(is);
-    String basePath = getUserData().getServerLocation();
-
-    int nEntries = 1;
-
-    /* This map is updated in the copyZipEntry method with the permissions
-     * of the files that have been copied.  Once all the files have
-     * been copied to the file system we will update the file permissions of
-     * these files.  This is done this way to group the number of calls to
-     * Runtime.exec (which is required to update the file system permissions).
-     */
-    Map<String, ArrayList<String>> permissions =
-        new HashMap<String, ArrayList<String>>();
-
-    String zipFirstPath = null;
-    try
-    {
-      ZipEntry entry = zipIn.getNextEntry();
-      while (entry != null)
-      {
-        int ratioBeforeCompleted = minRatio
-        + ((nEntries - 1) * (maxRatio - minRatio) / getNumberZipEntries());
-        int ratioWhenCompleted =
-          minRatio + (nEntries * (maxRatio - minRatio) / getNumberZipEntries());
-
-        if (nEntries == 1)
-        {
-          zipFirstPath = entry.getName();
-        } else
-        {
-          try
-          {
-            copyZipEntry(entry, basePath, zipFirstPath, zipIn,
-            ratioBeforeCompleted, ratioWhenCompleted, permissions);
-
-          } catch (IOException ioe)
-          {
-            String[] arg =
-              { entry.getName() };
-            String errorMsg = getThrowableMsg("error-copying", arg, ioe);
-
-            throw new InstallException(InstallException.Type.FILE_SYSTEM_ERROR,
-                errorMsg, ioe);
-          }
-        }
-
-        zipIn.closeEntry();
-        entry = zipIn.getNextEntry();
-        nEntries++;
-      }
-
-      if (Utils.isUnix())
-      {
-        // Change the permissions for UNIX systems
-        for (String perm : permissions.keySet())
-        {
-          ArrayList<String> paths = permissions.get(perm);
-          try
-          {
-            int result = Utils.setPermissionsUnix(paths, perm);
-            if (result != 0)
-            {
-              throw new IOException("Could not set permissions on files "
-                  + paths + ".  The chmod error code was: " + result);
-            }
-          } catch (InterruptedException ie)
-          {
-            IOException ioe =
-                new IOException("Could not set permissions on files " + paths
-                    + ".  The chmod call returned an InterruptedException.");
-            ioe.initCause(ie);
-            throw ioe;
-          }
-        }
-      }
-
-    } catch (IOException ioe)
-    {
-      String[] arg =
-        { getZipFileName() };
-      String errorMsg = getThrowableMsg("error-zip-stream", arg, ioe);
-      throw new InstallException(InstallException.Type.FILE_SYSTEM_ERROR,
-          errorMsg, ioe);
-    }
-  }
-
-  /**
-   * Copies a zip entry in the file system.
-   * @param entry the ZipEntry object.
-   * @param basePath the basePath (the installation path)
-   * @param zipFirstPath the first zip file path.  This is required because the
-   * zip file contain a directory of type
-   * 'OpenDS-(major version).(minor version)' that we want to get rid of.  The
-   * first zip file path corresponds to this path.
-   * @param is the ZipInputStream that contains the contents to be copied.
-   * @param ratioBeforeCompleted the progress ratio before the zip file is
-   * copied.
-   * @param ratioWhenCompleted the progress ratio after the zip file is
-   * copied.
-   * @param permissions an ArrayList with permissions whose contents will be
-   * updated.
-   * @throws IOException if an error occurs.
-   */
-  private void copyZipEntry(ZipEntry entry, String basePath,
-      String zipFirstPath, ZipInputStream is, int ratioBeforeCompleted,
-      int ratioWhenCompleted, Map<String, ArrayList<String>> permissions)
-      throws IOException
-  {
-    String entryName = entry.getName();
-    // Get rid of the zipFirstPath
-    if (entryName.startsWith(zipFirstPath))
-    {
-      entryName = entryName.substring(zipFirstPath.length());
-    }
-    String path = Utils.getPath(basePath, entryName);
-
-    notifyListeners(ratioBeforeCompleted, getSummary(getStatus()),
-        getFormattedWithPoints(getMsg("progress-extracting", new String[]
-          { path })));
-    if (Utils.createParentPath(path))
-    {
-      if (entry.isDirectory())
-      {
-        String perm = getDirectoryFileSystemPermissions(path);
-        ArrayList<String> list = permissions.get(perm);
-        if (list == null)
-        {
-          list = new ArrayList<String>();
-        }
-        list.add(path);
-        permissions.put(perm, list);
-
-        if (!Utils.createDirectory(path))
-        {
-          throw new IOException("Could not create path: " + path);
-        }
-      } else
-      {
-        String perm = getFileSystemPermissions(path);
-        ArrayList<String> list = permissions.get(perm);
-        if (list == null)
-        {
-          list = new ArrayList<String>();
-        }
-        list.add(path);
-        Utils.createFile(path, is);
-      }
-    } else
-    {
-      throw new IOException("Could not create parent path: " + path);
-    }
-    notifyListeners(ratioWhenCompleted, getSummary(getStatus()),
-        getFormattedDone() + getLineBreak());
+      throws QuickSetupException {
+    ZipExtractor extractor =
+            new ZipExtractor(is, minRatio, maxRatio,
+            getUserData().getServerLocation(),
+            getNumberZipEntries(),
+            getZipFileName(),
+            this);
+    extractor.extract();
   }
 
   /**
@@ -605,56 +423,6 @@
   }
 
   /**
-   * Returns the file system permissions for a directory.
-   * @param path the directory for which we want the file permissions.
-   * @return the file system permissions for the directory.
-   */
-  private String getDirectoryFileSystemPermissions(String path)
-  {
-    // TODO We should get this dynamically during build?
-    return "755";
-  }
-
-  /**
-   * Returns the file system permissions for a file.
-   * @param path the file for which we want the file permissions.
-   * @return the file system permissions for the file.
-   */
-  private String getFileSystemPermissions(String path)
-  {
-    // TODO We should get this dynamically during build?
-    String perm;
-
-    File file = new File(path);
-    if (file.getParent().endsWith(
-        File.separator + Utils.getWindowsBinariesRelativePath()) ||
-        file.getParent().endsWith(
-        File.separator + Utils.getUNIXBinariesRelativePath()))
-    {
-      if (path.endsWith(".bat"))
-      {
-        perm = "644";
-      }
-      else
-      {
-        perm = "755";
-      }
-    }
-    else if (path.endsWith(".sh"))
-    {
-      perm = "755";
-    } else if (path.endsWith(Utils.getUnixSetupFileName()) ||
-            path.endsWith(Utils.getUnixUninstallFileName()))
-    {
-      perm = "755";
-    } else
-    {
-      perm = "644";
-    }
-    return perm;
-  }
-
-  /**
    * Returns the number of entries contained in the zip file.  This is used to
    * update properly the progress bar ratio.
    * @return the number of entries contained in the zip file.
diff --git a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/resources/Resources.properties b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/resources/Resources.properties
index 4c9d7eb..19be787 100644
--- a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/resources/Resources.properties
+++ b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/resources/Resources.properties
@@ -594,7 +594,7 @@
 error-zip-stream=An unexpected error occurred reading the zip file {0}.
 exception-details=Details: {0}
 downloading-error=An error occurred downloading remote file(s) {0}.
-error-zipinputstreamnull=Could not retrieve zip file.  The input stream \
+error-zipinputstreamnull=Could not retrieve zip file {0}.  The input stream \
 is null.
 bug-msg=An unexpected error occurred.
 error-configuring=An error occurred configuring the server.
diff --git a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/ui/CurrentStepPanel.java b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/ui/CurrentStepPanel.java
index 4ef7186..62404e3 100644
--- a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/ui/CurrentStepPanel.java
+++ b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/ui/CurrentStepPanel.java
@@ -36,9 +36,8 @@
 import org.opends.quicksetup.Step;
 import org.opends.quicksetup.event.ButtonActionListener;
 import org.opends.quicksetup.installer.FieldName;
-import org.opends.quicksetup.installer.InstallProgressDescriptor;
-import org.opends.quicksetup.installer.UserInstallData;
-import org.opends.quicksetup.uninstaller.UninstallProgressDescriptor;
+import org.opends.quicksetup.ProgressDescriptor;
+import org.opends.quicksetup.UserData;
 import org.opends.quicksetup.util.Utils;
 
 /**
@@ -56,7 +55,7 @@
  */
 class CurrentStepPanel extends QuickSetupPanel
 {
-  private UserInstallData defaultUserData;
+  private UserData defaultUserData;
 
   private CurrentInstallStatus installStatus;
 
@@ -72,7 +71,7 @@
    * @param installStatus the object describing the current installation status.
    * @param isUninstall boolean telling whether we are uninstalling or not.
    */
-  public CurrentStepPanel(UserInstallData defaultUserData,
+  public CurrentStepPanel(UserData defaultUserData,
       CurrentInstallStatus installStatus, boolean isUninstall)
   {
     this.defaultUserData = defaultUserData;
@@ -194,12 +193,12 @@
 
   /**
    * Displays the panel corresponding to the provided step.  The panel contents
-   * are updated with the contents of the UserInstallData object.
+   * are updated with the contents of the UserData object.
    * @param step the step that we want to display.
-   * @param userData the UserInstallData object that must be used to populate
+   * @param userData the UserData object that must be used to populate
    * the panels.
    */
-  public void setDisplayedStep(Step step, UserInstallData userData)
+  public void setDisplayedStep(Step step, UserData userData)
   {
     CardLayout cl = (CardLayout) (getLayout());
     getPanel(step).beginDisplay(userData);
@@ -208,24 +207,11 @@
   }
 
   /**
-   * Forwards the different panels the InstallProgressDescriptor so that they
-   * can update their contents accordingly.
-   * @param descriptor the descriptor of the Installation progress.
-   */
-  public void displayProgress(InstallProgressDescriptor descriptor)
-  {
-    for (Step s : hmPanels.keySet())
-    {
-      getPanel(s).displayProgress(descriptor);
-    }
-  }
-
-  /**
-   * Forwards the different panels the UninstallProgressDescriptor so that they
+   * Forwards the different panels the ProgressDescriptor so that they
    * can update their contents accordingly.
    * @param descriptor the descriptor of the Uninstallation progress.
    */
-  public void displayProgress(UninstallProgressDescriptor descriptor)
+  public void displayProgress(ProgressDescriptor descriptor)
   {
     for (Step s : hmPanels.keySet())
     {
diff --git a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/ui/DataOptionsPanel.java b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/ui/DataOptionsPanel.java
index 77cc909..21b1f5a 100644
--- a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/ui/DataOptionsPanel.java
+++ b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/ui/DataOptionsPanel.java
@@ -45,10 +45,9 @@
 import javax.swing.text.JTextComponent;
 
 import org.opends.quicksetup.event.BrowseActionListener;
-import org.opends.quicksetup.installer.DataOptions;
+import org.opends.quicksetup.DataOptions;
 import org.opends.quicksetup.installer.FieldName;
-import org.opends.quicksetup.installer.LabelFieldDescriptor;
-import org.opends.quicksetup.installer.UserInstallData;
+import org.opends.quicksetup.UserData;
 
 /**
  * This is the panel that contains the Data Options: the suffix dn, whether
@@ -61,7 +60,7 @@
 
   private static final long serialVersionUID = 1815782841921928118L;
 
-  private UserInstallData defaultUserData;
+  private UserData defaultUserData;
 
   private HashMap<FieldName, JLabel> hmLabels =
       new HashMap<FieldName, JLabel>();
@@ -79,7 +78,7 @@
    * @param defaultUserData the default values that must be used to initialize
    * the fields of the panel.
    */
-  public DataOptionsPanel(UserInstallData defaultUserData)
+  public DataOptionsPanel(UserData defaultUserData)
   {
     this.defaultUserData = defaultUserData;
     populateComponentMaps();
@@ -350,7 +349,7 @@
    */
   private Object getDefaultValue(FieldName fieldName)
   {
-    Object value = null;
+    Object value;
     switch (fieldName)
     {
     case DIRECTORY_BASE_DN:
@@ -366,7 +365,7 @@
       break;
 
     case NUMBER_ENTRIES:
-      value = new Integer(defaultUserData.getDataOptions().getNumberEntries());
+      value = defaultUserData.getDataOptions().getNumberEntries();
       break;
 
     default:
diff --git a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/LabelFieldDescriptor.java b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/ui/LabelFieldDescriptor.java
similarity index 98%
rename from opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/LabelFieldDescriptor.java
rename to opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/ui/LabelFieldDescriptor.java
index 4b9a12a..22077a9 100644
--- a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/LabelFieldDescriptor.java
+++ b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/ui/LabelFieldDescriptor.java
@@ -25,7 +25,7 @@
  *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
  */
 
-package org.opends.quicksetup.installer;
+package org.opends.quicksetup.ui;
 
 /**
  * This is a commodity class used to couple a label and a text component with
@@ -63,7 +63,7 @@
      * Secondary label.
      */
     SECONDARY
-  };
+  }
 
   /**
    * This enum contains the different type of fields that can be associated with
@@ -84,7 +84,7 @@
      * Read only field.
      */
     READ_ONLY
-  };
+  }
 
   /**
    * Constructor of this LabelFieldDescriptor.
diff --git a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/ui/ProgressPanel.java b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/ui/ProgressPanel.java
index 8c2ec72..b71c835 100644
--- a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/ui/ProgressPanel.java
+++ b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/ui/ProgressPanel.java
@@ -43,11 +43,9 @@
 import javax.swing.event.HyperlinkListener;
 
 import org.opends.quicksetup.ButtonName;
+import org.opends.quicksetup.ProgressStep;
 import org.opends.quicksetup.event.ButtonEvent;
-import org.opends.quicksetup.installer.InstallProgressDescriptor;
-import org.opends.quicksetup.installer.InstallProgressStep;
-import org.opends.quicksetup.uninstaller.UninstallProgressDescriptor;
-import org.opends.quicksetup.uninstaller.UninstallProgressStep;
+import org.opends.quicksetup.ProgressDescriptor;
 
 /**
  * This panel is used to show the progress of the install or the uninstall.
@@ -63,8 +61,6 @@
 
   private JEditorPane detailsTextArea;
 
-  private JScrollPane scroll;
-
   private String lastText;
 
   /**
@@ -123,7 +119,7 @@
     gbc.insets = UIFactory.getEmptyInsets();
     panel.add(l, gbc);
 
-    scroll = new JScrollPane();
+    JScrollPane scroll = new JScrollPane();
     detailsTextArea = UIFactory.makeProgressPane(scroll);
     detailsTextArea.setBackground(
         UIFactory.CURRENT_STEP_PANEL_BACKGROUND);
@@ -134,9 +130,8 @@
         if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED)
         {
           String url = e.getURL().toString();
-          String newText = getFormatter().getFormattedAfterUrlClick(url,
+          lastText = getFormatter().getFormattedAfterUrlClick(url,
               lastText);
-          lastText = newText;
           detailsTextArea.setText(lastText);
         }
       }
@@ -174,52 +169,21 @@
   /**
    * {@inheritDoc}
    */
-  public void displayProgress(InstallProgressDescriptor descriptor)
+  public void displayProgress(ProgressDescriptor descriptor)
   {
-    InstallProgressStep status = descriptor.getProgressStep();
+    ProgressStep status = descriptor.getProgressStep();
     String summaryText = UIFactory.applyFontToHtml(descriptor
         .getProgressBarMsg(), UIFactory.PROGRESS_FONT);
-    if (status == InstallProgressStep.FINISHED_SUCCESSFULLY)
-    {
-      summaryText = "<form>"+summaryText+"</form>";
+
+    if (status.isLast() && !status.isError()) {
+      progressBar.setVisible(false);
+      if (!status.isError()) {
+        summaryText = "<form>"+summaryText+"</form>";
+      }
     }
     progressBarLabel.setText(summaryText);
 
-    if ((status == InstallProgressStep.FINISHED_WITH_ERROR)
-        || (status == InstallProgressStep.FINISHED_SUCCESSFULLY))
-    {
-      progressBar.setVisible(false);
-    }
-    int v = descriptor.getProgressBarRatio().intValue();
-    if (v > 0)
-    {
-      progressBar.setIndeterminate(false);
-      progressBar.setValue(v);
-    }
-    lastText = descriptor.getDetailsMsg();
-    detailsTextArea.setText(lastText);
-  }
-
-  /**
-   * {@inheritDoc}
-   */
-  public void displayProgress(UninstallProgressDescriptor descriptor)
-  {
-    UninstallProgressStep status = descriptor.getProgressStep();
-    String summaryText = UIFactory.applyFontToHtml(descriptor
-        .getProgressBarMsg(), UIFactory.PROGRESS_FONT);
-    if (status == UninstallProgressStep.FINISHED_SUCCESSFULLY)
-    {
-      summaryText = "<form>"+summaryText+"</form>";
-    }
-    progressBarLabel.setText(summaryText);
-
-    if ((status == UninstallProgressStep.FINISHED_WITH_ERROR)
-        || (status == UninstallProgressStep.FINISHED_SUCCESSFULLY))
-    {
-      progressBar.setVisible(false);
-    }
-    int v = descriptor.getProgressBarRatio().intValue();
+    int v = descriptor.getProgressBarRatio();
     if (v > 0)
     {
       progressBar.setIndeterminate(false);
diff --git a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/ui/QuickSetupDialog.java b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/ui/QuickSetupDialog.java
index b2c7b3d..19494ba 100644
--- a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/ui/QuickSetupDialog.java
+++ b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/ui/QuickSetupDialog.java
@@ -38,19 +38,13 @@
 import javax.swing.SwingUtilities;
 import javax.swing.WindowConstants;
 
-import org.opends.quicksetup.ButtonName;
-import org.opends.quicksetup.CurrentInstallStatus;
-import org.opends.quicksetup.Step;
+import org.opends.quicksetup.*;
 import org.opends.quicksetup.event.ButtonActionListener;
 import org.opends.quicksetup.event.ButtonEvent;
 import org.opends.quicksetup.event.MinimumSizeComponentListener;
 import org.opends.quicksetup.i18n.ResourceProvider;
 import org.opends.quicksetup.installer.FieldName;
-import org.opends.quicksetup.installer.InstallProgressDescriptor;
-import org.opends.quicksetup.installer.InstallProgressStep;
-import org.opends.quicksetup.installer.UserInstallData;
-import org.opends.quicksetup.uninstaller.UninstallProgressDescriptor;
-import org.opends.quicksetup.uninstaller.UninstallProgressStep;
+import org.opends.quicksetup.ProgressDescriptor;
 import org.opends.quicksetup.util.ProgressMessageFormatter;
 import org.opends.quicksetup.util.Utils;
 
@@ -82,7 +76,7 @@
 
   private Step displayedStep;
 
-  private UserInstallData defaultUserData;
+  private UserData defaultUserData;
 
   private CurrentInstallStatus installStatus;
 
@@ -97,7 +91,7 @@
    * the wizard.
    * @param installStatus the current installation status.
    */
-  public QuickSetupDialog(UserInstallData defaultUserData,
+  public QuickSetupDialog(UserData defaultUserData,
       CurrentInstallStatus installStatus)
   {
     this.defaultUserData = defaultUserData;
@@ -210,11 +204,9 @@
     int minHeight = (int) frame.getPreferredSize().getHeight();
 
     ComponentListener[] listeners = frame.getComponentListeners();
-    for (int i=0; i<listeners.length; i++)
-    {
-      if (listeners[i] instanceof MinimumSizeComponentListener)
-      {
-        frame.removeComponentListener(listeners[i]);
+    for (ComponentListener listener : listeners) {
+      if (listener instanceof MinimumSizeComponentListener) {
+        frame.removeComponentListener(listener);
       }
     }
     frame.addComponentListener(new MinimumSizeComponentListener(frame,
@@ -223,12 +215,12 @@
 
   /**
    * Displays the panel corresponding to the provided step.  The panel contents
-   * are updated with the contents of the UserInstallData object.
+   * are updated with the contents of the UserData object.
    * @param step the step that we want to display.
-   * @param userData the UserInstallData object that must be used to populate
+   * @param userData the UserData object that must be used to populate
    * the panels.
    */
-  public void setDisplayedStep(Step step, UserInstallData userData)
+  public void setDisplayedStep(Step step, UserData userData)
   {
     displayedStep = step;
     if (isUninstall())
@@ -321,33 +313,15 @@
   }
 
   /**
-   * Forwards to the displayed panel the InstallProgressDescriptor so that they
+   * Forwards to the displayed panel the ProgressDescriptor so that they
    * can update their contents accordingly.
    * @param descriptor the descriptor of the Installation progress.
    */
-  public void displayProgress(InstallProgressDescriptor descriptor)
+  public void displayProgress(ProgressDescriptor descriptor)
   {
     getCurrentStepPanel().displayProgress(descriptor);
-    InstallProgressStep status = descriptor.getProgressStep();
-    if ((status == InstallProgressStep.FINISHED_SUCCESSFULLY)
-        || (status == InstallProgressStep.FINISHED_WITH_ERROR))
-    {
-      setButtonEnabled(ButtonName.CLOSE, true);
-    }
-  }
-
-  /**
-   * Forwards to the displayed panel the UninstallProgressDescriptor so that
-   * they can update their contents accordingly.
-   * @param descriptor the descriptor of the Uninstallation progress.
-   */
-  public void displayProgress(UninstallProgressDescriptor descriptor)
-  {
-    getCurrentStepPanel().displayProgress(descriptor);
-    UninstallProgressStep status = descriptor.getProgressStep();
-    if ((status == UninstallProgressStep.FINISHED_SUCCESSFULLY)
-        || (status == UninstallProgressStep.FINISHED_WITH_ERROR))
-    {
+    ProgressStep status = descriptor.getProgressStep();
+    if (status.isLast()) {
       setButtonEnabled(ButtonName.CLOSE, true);
     }
   }
diff --git a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/ui/QuickSetupStepPanel.java b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/ui/QuickSetupStepPanel.java
index 63854bd..ef04467 100644
--- a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/ui/QuickSetupStepPanel.java
+++ b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/ui/QuickSetupStepPanel.java
@@ -45,10 +45,8 @@
 import org.opends.quicksetup.event.ButtonActionListener;
 import org.opends.quicksetup.event.ButtonEvent;
 import org.opends.quicksetup.installer.FieldName;
-import org.opends.quicksetup.installer.InstallProgressDescriptor;
-import org.opends.quicksetup.installer.LabelFieldDescriptor;
-import org.opends.quicksetup.installer.UserInstallData;
-import org.opends.quicksetup.uninstaller.UninstallProgressDescriptor;
+import org.opends.quicksetup.ProgressDescriptor;
+import org.opends.quicksetup.UserData;
 import org.opends.quicksetup.util.HtmlProgressMessageFormatter;
 import org.opends.quicksetup.util.ProgressMessageFormatter;
 import org.opends.quicksetup.util.URLWorker;
@@ -83,7 +81,7 @@
    *
    * @param data the new user data.
    */
-  public void beginDisplay(UserInstallData data)
+  public void beginDisplay(UserData data)
   {
   }
 
@@ -99,16 +97,7 @@
    * ProgressPanel overwrites this method and for all the others it stays empty.
    * @param descriptor the descriptor of the Installation progress.
    */
-  public void displayProgress(InstallProgressDescriptor descriptor)
-  {
-  }
-
-  /**
-   * Called when a progress change must be reflected in the panels.  Only
-   * ProgressPanel overwrites this method and for all the others it stays empty.
-   * @param descriptor the descriptor of the Uninstallation progress.
-   */
-  public void displayProgress(UninstallProgressDescriptor descriptor)
+  public void displayProgress(ProgressDescriptor descriptor)
   {
   }
 
@@ -191,9 +180,8 @@
    */
   public int getMinimumHeight()
   {
-    int height = (int) getPreferredSize().getHeight();
 
-    return height;
+    return (int) getPreferredSize().getHeight();
   }
 
 
diff --git a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/ui/ReviewPanel.java b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/ui/ReviewPanel.java
index fcf78cd..0cfa0a5 100644
--- a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/ui/ReviewPanel.java
+++ b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/ui/ReviewPanel.java
@@ -37,10 +37,9 @@
 import javax.swing.JPanel;
 import javax.swing.text.JTextComponent;
 
-import org.opends.quicksetup.installer.DataOptions;
+import org.opends.quicksetup.DataOptions;
+import org.opends.quicksetup.UserData;
 import org.opends.quicksetup.installer.FieldName;
-import org.opends.quicksetup.installer.LabelFieldDescriptor;
-import org.opends.quicksetup.installer.UserInstallData;
 
 /**
  * This is the panel that contains the Review Panel.
@@ -52,7 +51,7 @@
 
   private boolean displayServerLocation;
 
-  private UserInstallData defaultUserData;
+  private UserData defaultUserData;
 
   private JCheckBox checkBox;
 
@@ -67,7 +66,7 @@
    * @param defaultUserData the default values that must be used to initialize
    * the fields of the panel.
    */
-  public ReviewPanel(UserInstallData defaultUserData)
+  public ReviewPanel(UserData defaultUserData)
   {
     this.defaultUserData = defaultUserData;
     this.displayServerLocation = isWebStart();
@@ -78,7 +77,7 @@
   /**
    * {@inheritDoc}
    */
-  public void beginDisplay(UserInstallData userData)
+  public void beginDisplay(UserData userData)
   {
     if (displayServerLocation)
     {
@@ -102,7 +101,7 @@
     Object value = null;
     if (fieldName == FieldName.SERVER_START)
     {
-      value = new Boolean(getCheckBox().isSelected());
+      value = getCheckBox().isSelected();
     }
     return value;
   }
diff --git a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/ui/ServerSettingsPanel.java b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/ui/ServerSettingsPanel.java
index 517b073..75eaec4 100644
--- a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/ui/ServerSettingsPanel.java
+++ b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/ui/ServerSettingsPanel.java
@@ -43,9 +43,8 @@
 
 import org.opends.quicksetup.event.BrowseActionListener;
 import org.opends.quicksetup.installer.FieldName;
-import org.opends.quicksetup.installer.LabelFieldDescriptor;
-import org.opends.quicksetup.installer.UserInstallData;
 import org.opends.quicksetup.util.Utils;
+import org.opends.quicksetup.UserData;
 
 /**
  * This is the panel that contains the Server Settings: the port, the Directory
@@ -54,7 +53,7 @@
  */
 class ServerSettingsPanel extends QuickSetupStepPanel
 {
-  private UserInstallData defaultUserData;
+  private UserData defaultUserData;
 
   private Component lastFocusComponent;
 
@@ -81,7 +80,7 @@
    * @param defaultUserData the default values that must be used to initialize
    * the fields of the panel.
    */
-  public ServerSettingsPanel(UserInstallData defaultUserData)
+  public ServerSettingsPanel(UserData defaultUserData)
   {
     this.defaultUserData = defaultUserData;
     this.displayServerLocation = isWebStart();
@@ -208,14 +207,13 @@
     }
 
     // Add the other widgets
-    for (int i = 0; i < fieldNames.length; i++)
-    {
+    for (FieldName fieldName : fieldNames) {
       gbc.gridwidth = GridBagConstraints.RELATIVE;
       gbc.weightx = 0.0;
       gbc.insets.top = UIFactory.TOP_INSET_PRIMARY_FIELD;
       gbc.insets.left = 0;
       gbc.anchor = GridBagConstraints.WEST;
-      panel.add(getLabel(fieldNames[i]), gbc);
+      panel.add(getLabel(fieldName), gbc);
 
       auxPanel = new JPanel(new GridBagLayout());
       auxPanel.setOpaque(false);
@@ -226,23 +224,20 @@
       gbc.gridwidth = GridBagConstraints.REMAINDER;
       panel.add(auxPanel, gbc);
 
-      boolean isPortField = fieldNames[i] == FieldName.SERVER_PORT;
+      boolean isPortField = fieldName == FieldName.SERVER_PORT;
       gbc.insets = UIFactory.getEmptyInsets();
-      if (isPortField)
-      {
+      if (isPortField) {
         gbc.gridwidth = 3;
-      } else
-      {
+      } else {
         gbc.gridwidth = GridBagConstraints.RELATIVE;
       }
       gbc.weightx = 0.0;
-      auxPanel.add(getField(fieldNames[i]), gbc);
-      if (isPortField)
-      {
+      auxPanel.add(getField(fieldName), gbc);
+      if (isPortField) {
         JLabel l =
-          UIFactory.makeJLabel(UIFactory.IconType.NO_ICON,
-              getPortHelpMessage(),
-              UIFactory.TextStyle.SECONDARY_FIELD_VALID);
+                UIFactory.makeJLabel(UIFactory.IconType.NO_ICON,
+                        getPortHelpMessage(),
+                        UIFactory.TextStyle.SECONDARY_FIELD_VALID);
         gbc.gridwidth = GridBagConstraints.RELATIVE;
         gbc.insets.left = UIFactory.LEFT_INSET_SECONDARY_FIELD;
         auxPanel.add(l, gbc);
@@ -298,7 +293,8 @@
    */
   private String getDefaultValue(FieldName fieldName)
   {
-    String value = null;
+    String value;
+    value = null;
     switch (fieldName)
     {
     case SERVER_LOCATION:
diff --git a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/uninstaller/UninstallCli.java b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/uninstaller/UninstallCli.java
index 1bb7875..3603d8e 100644
--- a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/uninstaller/UninstallCli.java
+++ b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/uninstaller/UninstallCli.java
@@ -34,11 +34,15 @@
 import java.util.Set;
 
 import org.opends.quicksetup.CurrentInstallStatus;
-import org.opends.quicksetup.event.UninstallProgressUpdateEvent;
-import org.opends.quicksetup.event.UninstallProgressUpdateListener;
+import org.opends.quicksetup.UserDataException;
+import org.opends.quicksetup.ApplicationException;
+import org.opends.quicksetup.UserData;
+import org.opends.quicksetup.event.ProgressUpdateListener;
+import org.opends.quicksetup.event.ProgressUpdateEvent;
 import org.opends.quicksetup.i18n.ResourceProvider;
 import org.opends.quicksetup.util.PlainTextProgressMessageFormatter;
 import org.opends.quicksetup.util.Utils;
+import org.opends.quicksetup.util.ProgressMessageFormatter;
 
 /**
  * The class used to provide some CLI interface in the uninstall.
@@ -106,27 +110,30 @@
     try
     {
       CurrentInstallStatus installStatus = new CurrentInstallStatus();
-      UserUninstallData userData = getUserUninstallData(args, installStatus);
+      UninstallUserData userData = getUserData(args, installStatus);
       if (userData != null)
       {
-        Uninstaller uninstaller = new Uninstaller(userData,
-            new PlainTextProgressMessageFormatter());
+        ProgressMessageFormatter formatter =
+                new PlainTextProgressMessageFormatter();
+        Uninstaller uninstaller = new Uninstaller();
+        uninstaller.setUserData(userData);
+        uninstaller.setProgressMessageFormatter(formatter);
         uninstaller.addProgressUpdateListener(
-            new UninstallProgressUpdateListener()
+            new ProgressUpdateListener()
             {
               /**
-               * UninstallProgressUpdateListener implementation.
-               * @param ev the UninstallProgressUpdateEvent we receive.
+               * ProgressUpdateListener implementation.
+               * @param ev the ProgressUpdateEvent we receive.
                *
                */
-              public void progressUpdate(UninstallProgressUpdateEvent ev)
+              public void progressUpdate(ProgressUpdateEvent ev)
               {
                 System.out.print(
                     org.opends.server.util.StaticUtils.wrapText(ev.getNewLogs(),
                         Utils.getCommandLineMaxLineWidth()));
               }
             });
-        uninstaller.start();
+        new Thread(uninstaller).start();
         while (!uninstaller.isFinished())
         {
           try
@@ -138,7 +145,7 @@
           }
         }
 
-        UninstallException ue = uninstaller.getException();
+        ApplicationException ue = uninstaller.getException();
         if (ue != null)
         {
           switch (ue.getType())
@@ -157,7 +164,7 @@
 
             default:
               throw new IllegalStateException(
-                  "Unknown UninstallException type: "+ue.getType());
+                  "Unknown ApplicationException type: "+ue.getType());
           }
         }
         else
@@ -171,7 +178,7 @@
         returnValue = CANCELLED;
       }
     }
-    catch (UserUninstallDataException uude)
+    catch (UserDataException uude)
     {
       System.err.println(LINE_SEPARATOR+uude.getLocalizedMessage()+
           LINE_SEPARATOR);
@@ -181,22 +188,22 @@
   }
 
   /**
-   * Creates a UserUninstallData based in the arguments provided.  It asks
+   * Creates a UserData based in the arguments provided.  It asks
    * user for additional information if what is provided in the arguments is not
    * enough.
    * @param args the arguments provided in the command line.
    * @param installStatus the current install status.
-   * @return the UserUninstallData object with what the user wants to uninstall
+   * @return the UserData object with what the user wants to uninstall
    * and null if the user cancels the uninstallation.
-   * @throws UserUninstallDataException if there is an error parsing the data
+   * @throws UserDataException if there is an error parsing the data
    * in the arguments.
    */
-  private UserUninstallData getUserUninstallData(String[] args,
-      CurrentInstallStatus installStatus) throws UserUninstallDataException
+  private UninstallUserData getUserData(String[] args,
+      CurrentInstallStatus installStatus) throws UserDataException
   {
-    UserUninstallData userData = new UserUninstallData();
+    UninstallUserData userData = new UninstallUserData();
 
-    boolean silentUninstall = false;
+    boolean silentUninstall;
     boolean isCancelled = false;
 
     /* Step 1: validate the arguments
@@ -288,8 +295,6 @@
     return response;
   }
 
-
-
   /**
    * Reads a line of text from standard input.
    *
@@ -365,18 +370,18 @@
 
   /**
    * Commodity method used to ask the user to confirm the deletion of certain
-   * parts of the server.  It updates the provided UserUninstallData object
+   * parts of the server.  It updates the provided UserData object
    * accordingly.  Returns <CODE>true</CODE> if the user cancels and <CODE>
    * false</CODE> otherwise.
-   * @param userData the UserUninstallData object to be updated.
+   * @param userData the UserData object to be updated.
    * @param outsideDbs the set of relative paths of databases located outside
    * the installation path of the server.
    * @param outsideLogs the set of relative paths of log files located outside
    * the installation path of the server.
-   * @returns <CODE>true</CODE> if the user cancels and <CODE>false</CODE>
+   * @return <CODE>true</CODE> if the user cancels and <CODE>false</CODE>
    * otherwise.
    */
-  private boolean askWhatToDelete(UserUninstallData userData,
+  private boolean askWhatToDelete(UninstallUserData userData,
       Set<String> outsideDbs, Set<String> outsideLogs)
   {
     boolean cancelled = false;
@@ -447,15 +452,9 @@
             answer = promptConfirm(msg, getMsg("cli-uninstall-yes-long"),
                 validValues);
 
-            if (getMsg("cli-uninstall-yes-long").equalsIgnoreCase(answer) ||
-                getMsg("cli-uninstall-yes-short").equalsIgnoreCase(answer))
-            {
-              answers[i] = true;
-            }
-            else
-            {
-              answers[i] = false;
-            }
+            answers[i] =
+                    getMsg("cli-uninstall-yes-long").equalsIgnoreCase(answer) ||
+                    getMsg("cli-uninstall-yes-short").equalsIgnoreCase(answer);
           }
           else
           {
@@ -533,20 +532,20 @@
    * Commodity method used to ask the user (when necessary) if the server must
    * be stopped or not.  If required it also asks the user authentication to
    * be able to shut down the server in Windows.
-   * @param userData the UserUninstallData object to be updated with the
+   * @param userData the UserData object to be updated with the
    * authentication of the user.
    * @param installStatus the CurrentInstallStatus object.
    * @param silentUninstall boolean telling whether this is a silent uninstall
    * or not.
    * @return <CODE>true</CODE> if the user wants to continue with uninstall and
    * <CODE>false</CODE> otherwise.
-   * @throws UserUninstallDataException if there is a problem with the data
+   * @throws UserDataException if there is a problem with the data
    * provided by the user (in the particular case where we are on silent
    * uninstall and some data is missing or not valid).
    */
-  private boolean askConfirmationToStop(UserUninstallData userData,
+  private boolean askConfirmationToStop(UserData userData,
       CurrentInstallStatus installStatus, boolean silentUninstall)
-  throws UserUninstallDataException
+  throws UserDataException
   {
     boolean cancelled = false;
 
@@ -600,14 +599,14 @@
 
   /**
    * Commodity method used to validate the arguments provided by the user in
-   * the command line and updating the UserUninstallData object accordingly.
-   * @param userData the UserUninstallData object to be updated.
+   * the command line and updating the UserData object accordingly.
+   * @param userData the UserData object to be updated.
    * @param args the arguments passed in the command line.
-   * @throws UserUninstallDataException if there is an error with the data
+   * @throws UserDataException if there is an error with the data
    * provided by the user.
    */
-  private void validateArguments(UserUninstallData userData,
-      String[] args) throws UserUninstallDataException
+  private void validateArguments(UserData userData,
+                                 String[] args) throws UserDataException
   {
     ArrayList<String> errors = new ArrayList<String>();
 
@@ -632,7 +631,7 @@
     {
       String msg = Utils.getStringFromCollection(errors,
           LINE_SEPARATOR+LINE_SEPARATOR);
-      throw new UserUninstallDataException(null, msg);
+      throw new UserDataException(null, msg);
     }
   }
 
@@ -691,6 +690,8 @@
   /**
    * The following three methods are just commodity methods to get localized
    * messages.
+   * @param key String key
+   * @return String message
    */
   private static String getMsg(String key)
   {
@@ -698,6 +699,13 @@
         Utils.getCommandLineMaxLineWidth());
   }
 
+  /**
+   * The following three methods are just commodity methods to get localized
+   * messages.
+   * @param key String key
+   * @param args String[] args
+   * @return String message
+   */
   private static String getMsg(String key, String[] args)
   {
     return org.opends.server.util.StaticUtils.wrapText(
diff --git a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/uninstaller/UninstallException.java b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/uninstaller/UninstallException.java
deleted file mode 100644
index 5b77db0..0000000
--- a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/uninstaller/UninstallException.java
+++ /dev/null
@@ -1,96 +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 2006-2007 Sun Microsystems, Inc.
- */
-
-package org.opends.quicksetup.uninstaller;
-
-/**
- * This exception is used to encapsulate all the error that we might have
- * during the uninstallation.
- *
- * @see Uninstaller.
- *
- */
-public class UninstallException extends Exception
-{
-  private static final long serialVersionUID = 5988129928117915261L;
-  private Type type;
-
-  /**
-   * This enum contains the different type of UninstallException that we can
-   * have.
-   *
-   */
-  public enum Type
-  {
-    /**
-     * Error related to file system error: IOException deleting files,
-     * permission errors, etc.
-     */
-    FILE_SYSTEM_ERROR,
-    /**
-     * Error stopping the Open DS server.
-     */
-    STOP_ERROR,
-    /**
-     * Error disabling the Windows service.
-     */
-    WINDOWS_SERVICE_ERROR,
-    /**
-     * A bug (for instance when we throw an IllegalStateException).
-     */
-    BUG
-  };
-
-  /**
-   * The constructor of the UninstallException.
-   * @param type the type of error we have.
-   * @param localizedMsg a localized string describing the problem.
-   * @param rootCause the root cause of this exception.
-   */
-  public UninstallException(Type type, String localizedMsg, Throwable rootCause)
-  {
-    super(localizedMsg, rootCause);
-    this.type = type;
-  }
-
-  /**
-   * Returns the Type of this exception.
-   * @return the Type of this exception.
-   */
-  public Type getType()
-  {
-    return type;
-  }
-
-  /**
-   * {@inheritDoc}
-   */
-  public String toString()
-  {
-    return getMessage();
-  }
-}
diff --git a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/uninstaller/UninstallLauncher.java b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/uninstaller/UninstallLauncher.java
index 15a5d40..1f21e61 100644
--- a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/uninstaller/UninstallLauncher.java
+++ b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/uninstaller/UninstallLauncher.java
@@ -88,6 +88,8 @@
     } else
     {
       System.setProperty("org.opends.quicksetup.uninstall", "true");
+      System.setProperty("org.opends.quicksetup.Application.class",
+              "org.opends.quicksetup.uninstaller.Uninstaller");
       int exitCode = launchGuiUninstall(args);
       if (exitCode != 0)
       {
diff --git a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/uninstaller/UninstallProgressDescriptor.java b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/uninstaller/UninstallProgressDescriptor.java
deleted file mode 100644
index e8eeeae..0000000
--- a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/uninstaller/UninstallProgressDescriptor.java
+++ /dev/null
@@ -1,108 +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 2006-2007 Sun Microsystems, Inc.
- */
-
-package org.opends.quicksetup.uninstaller;
-
-/**
- * This class is used to describe the current state of the uninstallation.
- * It contains the step in which the uninstallation is, the current progress
- * ratio, the progress bar message and the details message (the logs).
- *
- * This class is used directly by the ProgressPanel to update its content
- * and has been designed to match the layout of that panel.  However as it
- * does not contain any dependency in terms of code with any Swing or UI package
- * component it has been decided to leave it on the uninstaller package.
- *
- * In general the progress bar message and the details messages (log) are in
- * HTML form (but this class is independent of the format we use for the
- * messages).
- *
- */
-public class UninstallProgressDescriptor
-{
-  private UninstallProgressStep step;
-
-  private Integer progressBarRatio;
-
-  private String progressBarMsg;
-
-  private String detailsMsg;
-
-  /**
-   * Constructor for the UninstallProgressDescriptor.
-   * @param step the current uninstall step.
-   * @param progressBarRatio the completed progress ratio (in percentage).
-   * @param progressBarMsg the message to be displayed in the progress bar.
-   * @param detailsMsg the logs.
-   */
-  public UninstallProgressDescriptor(UninstallProgressStep step,
-      Integer progressBarRatio, String progressBarMsg, String detailsMsg)
-  {
-    this.step = step;
-    this.progressBarRatio = progressBarRatio;
-    this.progressBarMsg = progressBarMsg;
-    this.detailsMsg = detailsMsg;
-  }
-
-  /**
-   * Returns the details message (the log message) of the uninstall.
-   * @return the details message (the log message) of the uninstall.
-   */
-  public String getDetailsMsg()
-  {
-    return detailsMsg;
-  }
-
-  /**
-   * Returns the progress bar message.
-   * @return the progress bar message.
-   */
-  public String getProgressBarMsg()
-  {
-    return progressBarMsg;
-  }
-
-  /**
-   * Returns the progress bar ratio (the percentage of the uninstall that is
-   * completed).
-   * @return the progress bar ratio (the percentage of the uninstall that is
-   * completed).
-   */
-  public Integer getProgressBarRatio()
-  {
-    return progressBarRatio;
-  }
-
-  /**
-   * Returns the step of the uninstall on which we are.
-   * @return the step of the uninstall on which we are.
-   */
-  public UninstallProgressStep getProgressStep()
-  {
-    return step;
-  }
-}
diff --git a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/uninstaller/UninstallProgressStep.java b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/uninstaller/UninstallProgressStep.java
index 3fcd5a1..889286c 100644
--- a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/uninstaller/UninstallProgressStep.java
+++ b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/uninstaller/UninstallProgressStep.java
@@ -27,47 +27,70 @@
 
 package org.opends.quicksetup.uninstaller;
 
+import org.opends.quicksetup.ProgressStep;
+
 /**
- * This enumeration describes the different uninstallation steps in which we can
- * be.
- *
+ * Enumeration of steps for an uninstall process.
  */
-public enum UninstallProgressStep
-{
+public enum UninstallProgressStep implements ProgressStep {
+
   /**
    * Uninstall not started.
    */
   NOT_STARTED,
+
   /**
    * Stopping server.
    */
   STOPPING_SERVER,
+
   /**
    * Disabling Windows Service.
    */
   DISABLING_WINDOWS_SERVICE,
+
   /**
    * Removing External Database files.
    */
   DELETING_EXTERNAL_DATABASE_FILES,
+
   /**
    * Removing External Log files.
    */
   DELETING_EXTERNAL_LOG_FILES,
+
   /**
    * Removing external references.
    */
   REMOVING_EXTERNAL_REFERENCES,
+
   /**
    * Removing installation files.
    */
   DELETING_INSTALLATION_FILES,
+
   /**
    * Installation finished successfully.
    */
   FINISHED_SUCCESSFULLY,
+
   /**
    * Installation finished with an error.
    */
-  FINISHED_WITH_ERROR
+  FINISHED_WITH_ERROR;
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean isLast() {
+    return this == FINISHED_SUCCESSFULLY ||
+    this == FINISHED_WITH_ERROR;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean isError() {
+    return this.equals(FINISHED_WITH_ERROR);
+  }
 }
diff --git a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/uninstaller/UserUninstallData.java b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/uninstaller/UninstallUserData.java
similarity index 89%
rename from opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/uninstaller/UserUninstallData.java
rename to opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/uninstaller/UninstallUserData.java
index be80151..5e15eda 100644
--- a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/uninstaller/UserUninstallData.java
+++ b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/uninstaller/UninstallUserData.java
@@ -27,16 +27,16 @@
 
 package org.opends.quicksetup.uninstaller;
 
-import java.util.HashSet;
+import org.opends.quicksetup.UserData;
+
 import java.util.Set;
+import java.util.HashSet;
 
 /**
- * This class is used to provide a data model for the different parameters
- * that the user can provide in the uninstall wizard.
- *
+ * UserData with specific properties for Uninstall.
  */
-public class UserUninstallData
-{
+public class UninstallUserData extends UserData {
+
   private Set<String> externalDbsToRemove = new HashSet<String>();
   private Set<String> externalLogsToRemove = new HashSet<String>();
   private boolean removeDatabases;
@@ -46,8 +46,6 @@
   private boolean removeLDIFs;
   private boolean removeConfigurationAndSchema;
 
-  private boolean stopServer;
-
   /**
    * Sets the database directories located outside the installation which must
    * be removed.
@@ -80,6 +78,7 @@
     externalLogsToRemove.clear();
     externalLogsToRemove.addAll(logFiles);
   }
+
   /**
    * Returns the list of log files located outside the installation that must
    * be removed.
@@ -110,7 +109,6 @@
     this.removeLibrariesAndTools = removeLibrariesAndTools;
   }
 
-
   /**
    * Sets whether to remove databases or not.
    * @param removeDatabases remove databases or not.
@@ -208,24 +206,4 @@
   {
     return removeConfigurationAndSchema;
   }
-
-  /**
-   * Sets whether to stop the server or not.
-   * @param stopServer stop the server or not.
-   */
-  public void setStopServer(boolean stopServer)
-  {
-    this.stopServer = stopServer;
-  }
-
-  /**
-   * Returns whether the user wants to stop the server or not.
-   * @return <CODE>true</CODE> if the user wants to stop the server and <CODE>\
-   * false</CODE> otherwise.
-   */
-  public boolean getStopServer()
-  {
-    return stopServer;
-  }
 }
-
diff --git a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/uninstaller/Uninstaller.java b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/uninstaller/Uninstaller.java
index ba76a6e..8e70e59 100644
--- a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/uninstaller/Uninstaller.java
+++ b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/uninstaller/Uninstaller.java
@@ -27,120 +27,51 @@
 
 package org.opends.quicksetup.uninstaller;
 
-import java.io.BufferedReader;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileFilter;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.PrintStream;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
-
-import org.opends.quicksetup.CurrentInstallStatus;
-import org.opends.quicksetup.event.UninstallProgressUpdateEvent;
-import org.opends.quicksetup.event.UninstallProgressUpdateListener;
-import org.opends.quicksetup.i18n.ResourceProvider;
-import org.opends.quicksetup.util.ProgressMessageFormatter;
+import org.opends.quicksetup.*;
 import org.opends.quicksetup.util.Utils;
-
 import org.opends.server.tools.ConfigureWindowsService;
 
+import java.io.*;
+import java.util.*;
+
 /**
  * This class is in charge of performing the uninstallation of Open DS.
- *
  */
-public class Uninstaller
-{
-  private UserUninstallData userData;
-  private ProgressMessageFormatter formatter;
-  private UninstallProgressStep status;
-  private HashMap<UninstallProgressStep, Integer> hmRatio =
-    new HashMap<UninstallProgressStep, Integer>();
+public class Uninstaller extends Application {
 
-  private HashMap<UninstallProgressStep, String> hmSummary =
-    new HashMap<UninstallProgressStep, String>();
+  private ProgressStep status = UninstallProgressStep.NOT_STARTED;
 
-  private HashSet<UninstallProgressUpdateListener> listeners =
-    new HashSet<UninstallProgressUpdateListener>();
+  private HashMap<ProgressStep, Integer> hmRatio =
+    new HashMap<ProgressStep, Integer>();
 
-  private UninstallException ue;
+  private HashMap<ProgressStep, String> hmSummary =
+    new HashMap<ProgressStep, String>();
+
+  private ApplicationException ue;
 
   private Boolean isWindowsServiceEnabled;
 
   /**
-   * Uninstaller constructor.
-   * @param userData the object containing the information provided by the user
-   * in the uninstallation.
-   * @param formatter the message formatter to be used to generate the text of
-   * the UninstallProgressUpdateEvent.
+   * {@inheritDoc}
    */
-  public Uninstaller(UserUninstallData userData,
-      ProgressMessageFormatter formatter)
-  {
-    this.userData = userData;
-    this.formatter = formatter;
-    initMaps();
-    status = UninstallProgressStep.NOT_STARTED;
+  public UserData createUserData() {
+    return new UninstallUserData();
   }
 
   /**
-   * Start the uninstall process.  This method will not block the thread on
-   * which is invoked.
+   * {@inheritDoc}
    */
-  public void start()
-  {
-    Thread t = new Thread(new Runnable()
-    {
-      public void run()
-      {
-        doUninstall();
-      }
-    });
-    t.start();
+  protected String getInstallationPath() {
+    return null;
   }
 
   /**
-   * Returns whether the uninstaller has finished or not.
-   * @return <CODE>true</CODE> if the install is finished or <CODE>false
-   * </CODE> if not.
-   */
-  public boolean isFinished()
-  {
-    return getStatus() == UninstallProgressStep.FINISHED_SUCCESSFULLY
-    || getStatus() == UninstallProgressStep.FINISHED_WITH_ERROR;
-  }
-
-  /**
-   * Adds a UninstallProgressUpdateListener that will be notified of updates in
-   * the uninstall progress.
-   * @param l the UninstallProgressUpdateListener to be added.
-   */
-  public void addProgressUpdateListener(UninstallProgressUpdateListener l)
-  {
-    listeners.add(l);
-  }
-
-  /**
-   * Removes a UninstallProgressUpdateListener.
-   * @param l the UninstallProgressUpdateListener to be removed.
-   */
-  public void removeProgressUpdateListener(UninstallProgressUpdateListener l)
-  {
-    listeners.remove(l);
-  }
-
-  /**
-   * Returns the UninstallException that might occur during installation or
+   * Returns the ApplicationException that might occur during installation or
    * <CODE>null</CODE> if no exception occurred.
-   * @return the UninstallException that might occur during installation or
+   * @return the ApplicationException that might occur during installation or
    * <CODE>null</CODE> if no exception occurred.
    */
-  public UninstallException getException()
+  public ApplicationException getException()
   {
     return ue;
   }
@@ -169,7 +100,7 @@
     String successMsg;
     if (Utils.isCli())
     {
-      if (userData.getRemoveLibrariesAndTools())
+      if (getUninstallUserData().getRemoveLibrariesAndTools())
       {
         String[] arg = new String[1];
         if (Utils.isWindows())
@@ -192,7 +123,7 @@
     }
     else
     {
-      if (userData.getRemoveLibrariesAndTools())
+      if (getUninstallUserData().getRemoveLibrariesAndTools())
       {
         String[] arg = {getLibrariesPath()};
         successMsg = getMsg(
@@ -240,14 +171,14 @@
     totalTime += hmTime.get(UninstallProgressStep.DELETING_INSTALLATION_FILES);
     steps.add(UninstallProgressStep.DELETING_INSTALLATION_FILES);
 
-    if (getUserData().getExternalDbsToRemove().size() > 0)
+    if (getUninstallUserData().getExternalDbsToRemove().size() > 0)
     {
       totalTime += hmTime.get(
           UninstallProgressStep.DELETING_EXTERNAL_DATABASE_FILES);
       steps.add(UninstallProgressStep.DELETING_EXTERNAL_DATABASE_FILES);
     }
 
-    if (getUserData().getExternalLogsToRemove().size() > 0)
+    if (getUninstallUserData().getExternalLogsToRemove().size() > 0)
     {
       totalTime += hmTime.get(
           UninstallProgressStep.DELETING_EXTERNAL_LOG_FILES);
@@ -270,241 +201,12 @@
   }
 
   /**
-   * Returns a localized message for a key value.  In  the properties file we
-   * have something of type:
-   * key=value
-   *
-   * @see ResourceProvider.getMsg(String key)
-   * @param key the key in the properties file.
-   * @return the value associated to the key in the properties file.
-   * properties file.
-   */
-  private String getMsg(String key)
-  {
-    return getI18n().getMsg(key);
-  }
-
-  /**
-   * Returns a localized message for a key value.  In  the properties file we
-   * have something of type:
-   * key=value
-   *
-   * For instance if we pass as key "mykey" and as arguments {"value1"} and
-   * in the properties file we have:
-   * mykey=value with argument {0}.
-   *
-   * This method will return "value with argument value1".
-   * @see ResourceProvider.getMsg(String key, String[] args)
-   * @param key the key in the properties file.
-   * @param args the arguments to be passed to generate the resulting value.
-   * @return the value associated to the key in the properties file.
-   */
-  private String getMsg(String key, String[] args)
-  {
-    return getI18n().getMsg(key, args);
-  }
-
-  /**
-   * Returns a ResourceProvider instance.
-   * @return a ResourceProvider instance.
-   */
-  private ResourceProvider getI18n()
-  {
-    return ResourceProvider.getInstance();
-  }
-
-  /**
-   * Returns a localized message for a given properties key and throwable.
-   * @param key the key of the message in the properties file.
-   * @param t the throwable for which we want to get a message.
-   * @return a localized message for a given properties key and throwable.
-   */
-  private String getThrowableMsg(String key, Throwable t)
-  {
-    return getThrowableMsg(key, null, t);
-  }
-
-  /**
-   * Returns a localized message for a given properties key and throwable.
-   * @param key the key of the message in the properties file.
-   * @param args the arguments of the message in the properties file.
-   * @param t the throwable for which we want to get a message.
-   *
-   * @return a localized message for a given properties key and throwable.
-   */
-  private String getThrowableMsg(String key, String[] args, Throwable t)
-  {
-    return Utils.getThrowableMsg(getI18n(), key, args, t);
-  }
-
-  /**
-   * Returns the formatted representation of the text that is the summary of the
-   * installation process (the one that goes in the UI next to the progress
-   * bar).
-   * @param text the source text from which we want to get the formatted
-   * representation
-   * @return the formatted representation of an error for the given text.
-   */
-  private String getFormattedSummary(String text)
-  {
-    return formatter.getFormattedSummary(text);
-  }
-
-  /**
-   * Returns the formatted representation of a success message for a given text.
-   * @param text the source text from which we want to get the formatted
-   * representation
-   * @return the formatted representation of an success message for the given
-   * text.
-   */
-  private String getFormattedSuccess(String text)
-  {
-    return formatter.getFormattedSuccess(text);
-  }
-
-  /**
-   * Returns the formatted representation of an warning for a given text.
-   * @param text the source text from which we want to get the formatted
-   * representation
-   * @return the formatted representation of an warning for the given text.
-   */
-  private String getFormattedWarning(String text)
-  {
-    return formatter.getFormattedWarning(text, true);
-  }
-
-  /**
-   * Returns the formatted representation of an error for a given text.
-   * @param text the source text from which we want to get the formatted
-   * representation
-   * @return the formatted representation of an error for the given text.
-   */
-  private String getFormattedError(String text)
-  {
-    return formatter.getFormattedError(text, false);
-  }
-
-  /**
-   * Returns the formatted representation of a log error message for a given
-   * text.
-   * @param text the source text from which we want to get the formatted
-   * representation
-   * @return the formatted representation of a log error message for the given
-   * text.
-   */
-  private String getFormattedLogError(String text)
-  {
-    return formatter.getFormattedLogError(text);
-  }
-
-  /**
-   * Returns the formatted representation of a log message for a given text.
-   * @param text the source text from which we want to get the formatted
-   * representation
-   * @return the formatted representation of a log message for the given text.
-   */
-  private String getFormattedLog(String text)
-  {
-    return formatter.getFormattedLog(text);
-  }
-
-  /**
-   * Returns the formatted representation of the 'Done' text string.
-   * @return the formatted representation of the 'Done' text string.
-   */
-  private String getFormattedDone()
-  {
-    return formatter.getFormattedDone();
-  }
-
-  /**
-   * Returns the formatted representation of the argument text to which we add
-   * points.  For instance if we pass as argument 'Deleting file' the
-   * return value will be 'Deleting file .....'.
-   * @param text the String to which add points.
-   * @return the formatted representation of the '.....' text string.
-   */
-  private String getFormattedWithPoints(String text)
-  {
-    return formatter.getFormattedWithPoints(text);
-  }
-
-  /**
-   * Returns the formatted representation of an error message for a given
-   * exception.
-   * This method applies a margin if the applyMargin parameter is
-   * <CODE>true</CODE>.
-   * @param ex the exception.
-   * @param applyMargin specifies whether we apply a margin or not to the
-   * resulting formatted text.
-   * @return the formatted representation of an error message for the given
-   * exception.
-   */
-  private String getFormattedError(Exception ex, boolean applyMargin)
-  {
-    return formatter.getFormattedError(ex, applyMargin);
-  }
-
-  /**
-   * Returns the line break formatted.
-   * @return the line break formatted.
-   */
-  private String getLineBreak()
-  {
-    return formatter.getLineBreak();
-  }
-
-  /**
-   * Returns the tab formatted.
-   * @return the tab formatted.
-   */
-  private String getTab()
-  {
-    return formatter.getTab();
-  }
-
-  /**
-   * Returns the task separator formatted.
-   * @return the task separator formatted.
-   */
-  private String getTaskSeparator()
-  {
-    return formatter.getTaskSeparator();
-  }
-
-  /**
-   * Returns the formatted representation of a progress message for a given
-   * text.
-   * @param text the source text from which we want to get the formatted
-   * representation
-   * @return the formatted representation of a progress message for the given
-   * text.
-   */
-  private String getFormattedProgress(String text)
-  {
-    return formatter.getFormattedProgress(text);
-  }
-
-  /**
-   * Returns the current UninstallProgressStep of the installation process.
-   * @return the current UninstallProgressStep of the installation process.
-   */
-  private UninstallProgressStep getStatus()
-  {
-    return status;
-  }
-
-  private UserUninstallData getUserData()
-  {
-    return userData;
-  }
-
-  /**
    * Actually performs the uninstall in this thread.  The thread is blocked.
    *
    */
-  private void doUninstall()
+  public void run()
   {
+    initMaps();
     PrintStream origErr = System.err;
     PrintStream origOut = System.out;
     try
@@ -535,7 +237,7 @@
         displaySeparator = true;
       }
 
-      Set<String> dbsToDelete = getUserData().getExternalDbsToRemove();
+      Set<String> dbsToDelete = getUninstallUserData().getExternalDbsToRemove();
       if (dbsToDelete.size() > 0)
       {
         status = UninstallProgressStep.DELETING_EXTERNAL_DATABASE_FILES;
@@ -548,7 +250,8 @@
         displaySeparator = true;
       }
 
-      Set<String> logsToDelete = getUserData().getExternalLogsToRemove();
+      Set<String> logsToDelete =
+              getUninstallUserData().getExternalLogsToRemove();
       if (logsToDelete.size() > 0)
       {
         status = UninstallProgressStep.DELETING_EXTERNAL_LOG_FILES;
@@ -562,6 +265,7 @@
         displaySeparator = true;
       }
 
+      UninstallUserData userData = getUninstallUserData();
       boolean somethingToDelete = userData.getRemoveBackups() ||
       userData.getRemoveConfigurationAndSchema() ||
       userData.getRemoveDatabases() ||
@@ -589,7 +293,7 @@
         notifyListeners(null);
       }
 
-    } catch (UninstallException ex)
+    } catch (ApplicationException ex)
     {
       ue = ex;
       status = UninstallProgressStep.FINISHED_WITH_ERROR;
@@ -598,8 +302,8 @@
     }
     catch (Throwable t)
     {
-      ue = new UninstallException(
-          UninstallException.Type.BUG,
+      ue = new ApplicationException(
+          ApplicationException.Type.BUG,
           getThrowableMsg("bug-msg", t), t);
       status = UninstallProgressStep.FINISHED_WITH_ERROR;
       String msg = getFormattedError(ue, true);
@@ -613,37 +317,10 @@
   }
 
   /**
-   * This method notifies the UninstallProgressUpdateListeners that there was an
-   * update in the installation progress.
-   * @param ratio the integer that specifies which percentage of
-   * the whole installation has been completed.
-   * @param currentPhaseSummary the localized summary message for the
-   * current installation progress in formatted form.
-   * @param newLogDetail the new log messages that we have for the
-   * installation in formatted form.
+   * {@inheritDoc}
    */
-  private void notifyListeners(Integer ratio, String currentPhaseSummary,
-      String newLogDetail)
-  {
-    UninstallProgressUpdateEvent ev =
-        new UninstallProgressUpdateEvent(getStatus(), ratio,
-            currentPhaseSummary, newLogDetail);
-    for (UninstallProgressUpdateListener l : listeners)
-    {
-      l.progressUpdate(ev);
-    }
-  }
-
-  /**
-   * This method is called when a new log message has been received.  It will
-   * notify the UninstallProgressUpdateListeners of this fact.
-   * @param newLogDetail the new log detail.
-   */
-  private void notifyListeners(String newLogDetail)
-  {
-    Integer ratio = getRatio(getStatus());
-    String currentPhaseSummary = getSummary(getStatus());
-    notifyListeners(ratio, currentPhaseSummary, newLogDetail);
+  public ProgressStep getStatus() {
+    return status;
   }
 
   /**
@@ -653,9 +330,9 @@
    * @return an integer that specifies which percentage of the whole
    * uninstallation has been completed.
    */
-  private Integer getRatio(UninstallProgressStep status)
+  public Integer getRatio(ProgressStep step)
   {
-    return hmRatio.get(status);
+    return hmRatio.get(step);
   }
 
   /**
@@ -665,16 +342,16 @@
    * @return an formatted representation of the summary for the specified
    * UninstallProgressStep.
    */
-  private String getSummary(UninstallProgressStep status)
+  public String getSummary(ProgressStep step)
   {
-    return hmSummary.get(status);
+    return hmSummary.get(step);
   }
 
   /**
    * This methods stops the server.
-   * @throws UninstallException if something goes wrong.
+   * @throws ApplicationException if something goes wrong.
    */
-  private void stopServer() throws UninstallException
+  private void stopServer() throws ApplicationException
   {
     notifyListeners(getFormattedProgress(getMsg("progress-stopping")) +
         getLineBreak());
@@ -774,8 +451,9 @@
          * The return code is not the one expected, assume the server could
          * not be stopped.
          */
-        throw new UninstallException(UninstallException.Type.STOP_ERROR, msg,
-            null);
+        throw new ApplicationException(ApplicationException.Type.STOP_ERROR,
+                msg,
+                null);
       }
       else
       {
@@ -785,12 +463,12 @@
 
     } catch (IOException ioe)
     {
-      throw new UninstallException(UninstallException.Type.STOP_ERROR,
+      throw new ApplicationException(ApplicationException.Type.STOP_ERROR,
           getThrowableMsg("error-stopping-server", ioe), ioe);
     }
     catch (InterruptedException ie)
     {
-      throw new UninstallException(UninstallException.Type.BUG,
+      throw new ApplicationException(ApplicationException.Type.BUG,
           getThrowableMsg("error-stopping-server", ie), ie);
     }
   }
@@ -798,10 +476,10 @@
   /**
    * Deletes the external database files specified in the provided Set.
    * @param dbFiles the database directories to be deleted.
-   * @throws UninstallException if something goes wrong.
+   * @throws ApplicationException if something goes wrong.
    */
   private void deleteExternalDatabaseFiles(Set<String> dbFiles)
-  throws UninstallException
+  throws ApplicationException
   {
     notifyListeners(getFormattedProgress(
         getMsg("progress-deleting-external-db-files")) +
@@ -815,10 +493,10 @@
   /**
    * Deletes the external database files specified in the provided Set.
    * @param logFiles the log files to be deleted.
-   * @throws UninstallException if something goes wrong.
+   * @throws ApplicationException if something goes wrong.
    */
   private void deleteExternalLogFiles(Set<String> logFiles)
-  throws UninstallException
+  throws ApplicationException
   {
     notifyListeners(getFormattedProgress(
         getMsg("progress-deleting-external-log-files")) +
@@ -831,10 +509,10 @@
 
   /**
    * Deletes the files under the installation path.
-   * @throws UninstallException if something goes wrong.
+   * @throws ApplicationException if something goes wrong.
    */
   private void deleteInstallationFiles(int minRatio, int maxRatio)
-  throws UninstallException
+  throws ApplicationException
   {
     notifyListeners(getFormattedProgress(
         getMsg("progress-deleting-installation-files")) +
@@ -910,26 +588,6 @@
   }
 
   /**
-   * Returns the path to the binaries.
-   * @return the path to the binaries.
-   */
-  private String getBinariesPath()
-  {
-    return Utils.getPath(Utils.getInstallPathFromClasspath(),
-        Utils.getBinariesRelativePath());
-  }
-
-  /**
-   * Returns the path to the libraries.
-   * @return the path to the libraries.
-   */
-  private String getLibrariesPath()
-  {
-    return Utils.getPath(Utils.getInstallPathFromClasspath(),
-        Utils.getLibrariesRelativePath());
-  }
-
-  /**
    * Returns the path to the quicksetup jar file.
    * @return the path to the quicksetup jar file.
    */
@@ -1012,9 +670,9 @@
   /**
    * Deletes everything below the specified file.
    * @param file the path to be deleted.
-   * @throws UninstallException if something goes wrong.
+   * @throws ApplicationException if something goes wrong.
    */
-  private void deleteRecursively(File file) throws UninstallException
+  private void deleteRecursively(File file) throws ApplicationException
   {
     deleteRecursively(file, null);
   }
@@ -1024,11 +682,10 @@
    * @param file the path to be deleted.
    * @param filter the filter of the files to know if the file can be deleted
    * directly or not.
-   * @throws UninstallException if something goes wrong.
+   * @throws ApplicationException if something goes wrong.
    */
-
   private void deleteRecursively(File file, FileFilter filter)
-  throws UninstallException
+  throws ApplicationException
   {
     if (file.exists())
     {
@@ -1081,9 +738,9 @@
   /**
    * Deletes the specified file.
    * @param file the file to be deleted.
-   * @throws UninstallException if something goes wrong.
+   * @throws ApplicationException if something goes wrong.
    */
-  private void delete(File file) throws UninstallException
+  private void delete(File file) throws ApplicationException
   {
     String[] arg = {file.getAbsolutePath()};
     boolean isFile = file.isFile();
@@ -1132,8 +789,8 @@
       {
         errMsg = getMsg("error-deleting-directory", arg);
       }
-      throw new UninstallException(
-          UninstallException.Type.FILE_SYSTEM_ERROR, errMsg, null);
+      throw new ApplicationException(
+          ApplicationException.Type.FILE_SYSTEM_ERROR, errMsg, null);
     }
 
     notifyListeners(getFormattedDone()+getLineBreak());
@@ -1146,6 +803,15 @@
   }
 
   /**
+   * {@inheritDoc}
+   */
+  protected String getBinariesPath()
+  {
+    return Utils.getPath(Utils.getInstallPathFromClasspath(),
+        Utils.getBinariesRelativePath());
+  }
+
+  /**
    * This class is used to read the standard error and standard output of the
    * Stop process.
    *
@@ -1232,6 +898,7 @@
      */
     public boolean accept(File file)
     {
+      UninstallUserData userData = getUninstallUserData();
       boolean[] uData = {
           userData.getRemoveLibrariesAndTools(),
           userData.getRemoveLibrariesAndTools(),
@@ -1292,9 +959,9 @@
 
   /**
    * This methods disables this server as a Windows service.
-   * @throws UninstallException if something goes wrong.
+   * @throws ApplicationException if something goes wrong.
    */
-  protected void disableWindowsService() throws UninstallException
+  protected void disableWindowsService() throws ApplicationException
   {
     notifyListeners(getFormattedProgress(
       getMsg("progress-disabling-windows-service")));
@@ -1309,8 +976,8 @@
       case ConfigureWindowsService.SERVICE_ALREADY_DISABLED:
       break;
       default:
-      throw new UninstallException(
-      UninstallException.Type.WINDOWS_SERVICE_ERROR, errorMessage, null);
+      throw new ApplicationException(
+      ApplicationException.Type.WINDOWS_SERVICE_ERROR, errorMessage, null);
     }
   }
 
@@ -1430,5 +1097,10 @@
       println(new String(b, off, len));
     }
   }
+
+  private UninstallUserData getUninstallUserData() {
+    return (UninstallUserData)getUserData();
+  }
+
 }
 
diff --git a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/uninstaller/UserUninstallDataException.java b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/uninstaller/UserUninstallDataException.java
deleted file mode 100644
index c9374f2..0000000
--- a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/uninstaller/UserUninstallDataException.java
+++ /dev/null
@@ -1,76 +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 2006-2007 Sun Microsystems, Inc.
- */
-
-package org.opends.quicksetup.uninstaller;
-
-import org.opends.quicksetup.Step;
-
-/**
- * This exception is used when there is an error with the data provided by
- * the user.  It will be thrown by the class that is in charge of validating
- * the user data (QuickSetup).
- *
- */
-public class UserUninstallDataException extends Exception
-{
-  private static final long serialVersionUID = 3984412143277614443L;
-
-  private Step step;
-
-  private String localizedMessage;
-
-  /**
-   * Constructor for UserInstallDataException.
-   * @param step the step in the wizard where the exception occurred.
-   * @param localizedMessage the localized message describing the error.
-   */
-  public UserUninstallDataException(Step step, String localizedMessage)
-  {
-    super(localizedMessage);
-    this.step = step;
-    this.localizedMessage = localizedMessage;
-  }
-
-  /**
-   * Returns the localized message describing the error that occurred.
-   * @return the localized message describing the error that occurred.
-   */
-  public String getLocalizedMessage()
-  {
-    return localizedMessage;
-  }
-
-  /**
-   * Returns the step of the wizard in which this exception occurred.
-   * @return the step of the wizard in which this exception occurred.
-   */
-  public Step getStep()
-  {
-    return step;
-  }
-}
-
diff --git a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/util/HtmlProgressMessageFormatter.java b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/util/HtmlProgressMessageFormatter.java
index 89c021e..cf25189 100644
--- a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/util/HtmlProgressMessageFormatter.java
+++ b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/util/HtmlProgressMessageFormatter.java
@@ -325,7 +325,7 @@
   /**
    * Returns the log HTML representation after the user has clicked on a url.
    *
-   * @see getErrorWithStackHtml
+   * @see HtmlProgressMessageFormatter#getErrorWithStackHtml
    * @param url that has been clicked
    * @param lastText the HTML representation of the log before clicking on the
    * url.
@@ -362,17 +362,18 @@
   private String getHtml(String text)
   {
     StringBuffer buffer = new StringBuffer();
-    text = text.replaceAll("\r\n", "\n");
-    String[] lines = text.split("[\n\r\u0085\u2028\u2029]");
-    for (int i = 0; i < lines.length; i++)
-    {
-      if (i != 0)
+    if (text != null) {
+      text = text.replaceAll("\r\n", "\n");
+      String[] lines = text.split("[\n\r\u0085\u2028\u2029]");
+      for (int i = 0; i < lines.length; i++)
       {
-        buffer.append("<br>");
+        if (i != 0)
+        {
+          buffer.append("<br>");
+        }
+        buffer.append(escape(lines[i]));
       }
-      buffer.append(escape(lines[i]));
     }
-
     return buffer.toString();
   }
 
@@ -423,7 +424,7 @@
    * have something of type:
    * key=value
    *
-   * @see ResourceProvider.getMsg(String key)
+   * @see ResourceProvider#getMsg(String)
    * @param key the key in the properties file.
    * @return the value associated to the key in the properties file.
    * properties file.
@@ -525,7 +526,7 @@
 
   /**
    * Gets the url parameters of the href we construct in getErrorWithStackHtml.
-   * @see getErrorWithStackHtml
+   * @see HtmlProgressMessageFormatter#getErrorWithStackHtml
    * @param openDiv the open div tag for the text.
    * @param hideText the text that we display when we do not display the
    * exception.
@@ -551,7 +552,6 @@
   /**
    * Returns the HTML representation of an exception in the
    * progress log for a given url.
-   * @see getHrefString
    * @param url the url containing all the information required to retrieve
    * the HTML representation.
    * @param inverse indicates whether we want to 'inverse' the representation
diff --git a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/util/Utils.java b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/util/Utils.java
index b0f4d75..e00855a 100644
--- a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/util/Utils.java
+++ b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/util/Utils.java
@@ -55,8 +55,8 @@
 import javax.swing.JOptionPane;
 
 import org.opends.quicksetup.CurrentInstallStatus;
+import org.opends.quicksetup.webstart.JnlpProperties;
 import org.opends.quicksetup.i18n.ResourceProvider;
-import org.opends.quicksetup.installer.webstart.JnlpProperties;
 import org.opends.server.util.SetupUtils;
 
 
diff --git a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/util/ZipExtractor.java b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/util/ZipExtractor.java
new file mode 100644
index 0000000..393d80b
--- /dev/null
+++ b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/util/ZipExtractor.java
@@ -0,0 +1,296 @@
+/*
+ * 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.util;
+
+import org.opends.quicksetup.QuickSetupException;
+import org.opends.quicksetup.Application;
+import org.opends.quicksetup.i18n.ResourceProvider;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.File;
+import java.util.zip.ZipInputStream;
+import java.util.zip.ZipEntry;
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.HashMap;
+
+/**
+ * Class for extracting the contents of a zip file and managing
+ * the reporting of progress during extraction.
+ */
+public class ZipExtractor {
+
+  private InputStream is;
+  private int minRatio;
+  private int maxRatio;
+  private String basePath;
+  private int numberZipEntries;
+  private String zipFileName;
+  private Application application;
+
+  /**
+   * Creates an instance of an ZipExtractor.
+   * @param is InputStream of zip file content
+   * @param minRatio int indicating the max ration
+   * @param maxRatio int indicating the min ration
+   * @param basePath filesystem location where content will be unzipped
+   * @param numberZipEntries number of entries in the input stream
+   * @param zipFileName name of the input zip file
+   * @param app application to be notified about progress
+   */
+  public ZipExtractor(InputStream is, int minRatio, int maxRatio,
+                                      String basePath, int numberZipEntries,
+                                      String zipFileName,
+                                      Application app) {
+    this.is = is;
+    this.minRatio = minRatio;
+    this.maxRatio = maxRatio;
+    this.basePath = basePath;
+    this.numberZipEntries = numberZipEntries;
+    this.zipFileName = zipFileName;
+    this.application = app;
+  }
+
+  /**
+   * Performs the zip extraction.
+   * @throws QuickSetupException if something goes wrong
+   */
+  public void extract() throws QuickSetupException {
+
+    ZipInputStream zipIn = new ZipInputStream(is);
+    int nEntries = 1;
+
+    /* This map is updated in the copyZipEntry method with the permissions
+     * of the files that have been copied.  Once all the files have
+     * been copied to the file system we will update the file permissions of
+     * these files.  This is done this way to group the number of calls to
+     * Runtime.exec (which is required to update the file system permissions).
+     */
+    Map<String, ArrayList<String>> permissions =
+        new HashMap<String, ArrayList<String>>();
+
+    String zipFirstPath = null;
+    try
+    {
+      ZipEntry entry = zipIn.getNextEntry();
+      while (entry != null)
+      {
+        int ratioBeforeCompleted = minRatio
+        + ((nEntries - 1) * (maxRatio - minRatio) / numberZipEntries);
+        int ratioWhenCompleted =
+          minRatio + (nEntries * (maxRatio - minRatio) / numberZipEntries);
+
+        if (nEntries == 1)
+        {
+          zipFirstPath = entry.getName();
+        } else
+        {
+          try
+          {
+            copyZipEntry(entry, basePath, zipFirstPath, zipIn,
+            ratioBeforeCompleted, ratioWhenCompleted, permissions, application);
+
+          } catch (IOException ioe)
+          {
+            String[] arg =
+              { entry.getName() };
+            String errorMsg =
+                    Utils.getThrowableMsg(ResourceProvider.getInstance(),
+                      "error-copying", arg, ioe);
+
+            throw new QuickSetupException(
+                    QuickSetupException.Type.FILE_SYSTEM_ERROR,
+                    errorMsg, ioe);
+          }
+        }
+
+        zipIn.closeEntry();
+        entry = zipIn.getNextEntry();
+        nEntries++;
+      }
+
+      if (Utils.isUnix())
+      {
+        // Change the permissions for UNIX systems
+        for (String perm : permissions.keySet())
+        {
+          ArrayList<String> paths = permissions.get(perm);
+          try
+          {
+            int result = Utils.setPermissionsUnix(paths, perm);
+            if (result != 0)
+            {
+              throw new IOException("Could not set permissions on files "
+                  + paths + ".  The chmod error code was: " + result);
+            }
+          } catch (InterruptedException ie)
+          {
+            IOException ioe =
+                new IOException("Could not set permissions on files " + paths
+                    + ".  The chmod call returned an InterruptedException.");
+            ioe.initCause(ie);
+            throw ioe;
+          }
+        }
+      }
+
+    } catch (IOException ioe)
+    {
+      String[] arg =
+        { zipFileName };
+      String errorMsg =
+              Utils.getThrowableMsg(ResourceProvider.getInstance(),
+                      "error-zip-stream", arg, ioe);
+      throw new QuickSetupException(QuickSetupException.Type.FILE_SYSTEM_ERROR,
+          errorMsg, ioe);
+    }
+  }
+
+  /**
+   * Copies a zip entry in the file system.
+   * @param entry the ZipEntry object.
+   * @param basePath the basePath (the installation path)
+   * @param zipFirstPath the first zip file path.  This is required because the
+   * zip file contain a directory of type
+   * 'OpenDS-(major version).(minor version)' that we want to get rid of.  The
+   * first zip file path corresponds to this path.
+   * @param is the ZipInputStream that contains the contents to be copied.
+   * @param ratioBeforeCompleted the progress ratio before the zip file is
+   * copied.
+   * @param ratioWhenCompleted the progress ratio after the zip file is
+   * copied.
+   * @param permissions an ArrayList with permissions whose contents will be
+   * updated.
+   * @param app Application to be notified about progress
+   * @throws IOException if an error occurs.
+   */
+  private void copyZipEntry(ZipEntry entry, String basePath,
+      String zipFirstPath, ZipInputStream is, int ratioBeforeCompleted,
+      int ratioWhenCompleted, Map<String, ArrayList<String>> permissions,
+      Application app)
+      throws IOException
+  {
+    String entryName = entry.getName();
+    // Get rid of the zipFirstPath
+    if (entryName.startsWith(zipFirstPath))
+    {
+      entryName = entryName.substring(zipFirstPath.length());
+    }
+    String path = Utils.getPath(basePath, entryName);
+
+    String progressSummary =
+            ResourceProvider.getInstance().getMsg("progress-extracting",
+                    new String[]{ path });
+    app.notifyListeners(ratioBeforeCompleted, progressSummary);
+    if (Utils.createParentPath(path))
+    {
+      if (entry.isDirectory())
+      {
+        String perm = getDirectoryFileSystemPermissions(path);
+        ArrayList<String> list = permissions.get(perm);
+        if (list == null)
+        {
+          list = new ArrayList<String>();
+        }
+        list.add(path);
+        permissions.put(perm, list);
+
+        if (!Utils.createDirectory(path))
+        {
+          throw new IOException("Could not create path: " + path);
+        }
+      } else
+      {
+        String perm = getFileSystemPermissions(path);
+        ArrayList<String> list = permissions.get(perm);
+        if (list == null)
+        {
+          list = new ArrayList<String>();
+        }
+        list.add(path);
+        Utils.createFile(path, is);
+      }
+    } else
+    {
+      throw new IOException("Could not create parent path: " + path);
+    }
+    application.notifyListenersDone(ratioWhenCompleted);
+  }
+
+  /**
+   * Returns the file system permissions for a directory.
+   * @param path the directory for which we want the file permissions.
+   * @return the file system permissions for the directory.
+   */
+  private String getDirectoryFileSystemPermissions(String path)
+  {
+    // TODO We should get this dynamically during build?
+    return "755";
+  }
+
+  /**
+   * Returns the file system permissions for a file.
+   * @param path the file for which we want the file permissions.
+   * @return the file system permissions for the file.
+   */
+  private String getFileSystemPermissions(String path)
+  {
+    // TODO We should get this dynamically during build?
+    String perm;
+
+    File file = new File(path);
+    if (file.getParent().endsWith(
+        File.separator + Utils.getWindowsBinariesRelativePath()) ||
+        file.getParent().endsWith(
+        File.separator + Utils.getUNIXBinariesRelativePath()))
+    {
+      if (path.endsWith(".bat"))
+      {
+        perm = "644";
+      }
+      else
+      {
+        perm = "755";
+      }
+    }
+    else if (path.endsWith(".sh"))
+    {
+      perm = "755";
+    } else if (path.endsWith(Utils.getUnixSetupFileName()) ||
+            path.endsWith(Utils.getUnixUninstallFileName()))
+    {
+      perm = "755";
+    } else
+    {
+      perm = "644";
+    }
+    return perm;
+  }
+
+}
diff --git a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/webstart/JnlpProperties.java b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/webstart/JnlpProperties.java
similarity index 97%
rename from opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/webstart/JnlpProperties.java
rename to opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/webstart/JnlpProperties.java
index cc74756..89a79e6 100644
--- a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/webstart/JnlpProperties.java
+++ b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/webstart/JnlpProperties.java
@@ -25,7 +25,7 @@
  *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
  */
 
-package org.opends.quicksetup.installer.webstart;
+package org.opends.quicksetup.webstart;
 
 /**
  * The following properties are set in the QuickSetup.jnlp file to provide

--
Gitblit v1.10.0