From c40f084a6d3e897785f2fbff3ddb97545644cddc Mon Sep 17 00:00:00 2001
From: jvergara <jvergara@localhost>
Date: Mon, 11 Dec 2006 15:34:39 +0000
Subject: [PATCH] The following modifications include the comments from Neil and Brian (thanks to both for your help):
---
opends/src/quicksetup/org/opends/quicksetup/uninstaller/Uninstaller.java | 1211 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 1,207 insertions(+), 4 deletions(-)
diff --git a/opends/src/quicksetup/org/opends/quicksetup/uninstaller/Uninstaller.java b/opends/src/quicksetup/org/opends/quicksetup/uninstaller/Uninstaller.java
index b21091f..01e5a71 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/uninstaller/Uninstaller.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/uninstaller/Uninstaller.java
@@ -27,14 +27,79 @@
package org.opends.quicksetup.uninstaller;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileFilter;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Writer;
+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.event.UninstallProgressUpdateEvent;
+import org.opends.quicksetup.event.UninstallProgressUpdateListener;
+import org.opends.quicksetup.i18n.ResourceProvider;
+import org.opends.quicksetup.util.ProgressMessageFormatter;
+import org.opends.quicksetup.util.Utils;
+
/**
* This class is in charge of performing the uninstallation of Open DS.
*
- * TODO implement this class.
- *
*/
public class Uninstaller
{
+ private UserUninstallData userData;
+ private ProgressMessageFormatter formatter;
+ private UninstallProgressStep status;
+ private HashMap<UninstallProgressStep, Integer> hmRatio =
+ new HashMap<UninstallProgressStep, Integer>();
+
+ private HashMap<UninstallProgressStep, String> hmSummary =
+ new HashMap<UninstallProgressStep, String>();
+
+ private HashSet<UninstallProgressUpdateListener> listeners =
+ new HashSet<UninstallProgressUpdateListener>();
+
+ private UninstallException ue;
+
+ /**
+ * 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.
+ */
+ public Uninstaller(UserUninstallData userData,
+ ProgressMessageFormatter formatter)
+ {
+ this.userData = userData;
+ this.formatter = formatter;
+ initMaps();
+ status = UninstallProgressStep.NOT_STARTED;
+ }
+
+ /**
+ * Start the uninstall process. This method will not block the thread on
+ * which is invoked.
+ */
+ public void start()
+ {
+ Thread t = new Thread(new Runnable()
+ {
+ public void run()
+ {
+ doUninstall();
+ }
+ });
+ t.start();
+ }
+
/**
* Returns whether the uninstaller has finished or not.
* @return <CODE>true</CODE> if the install is finished or <CODE>false
@@ -42,7 +107,1145 @@
*/
public boolean isFinished()
{
- /* TODO implement this */
- return false;
+ 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
+ * <CODE>null</CODE> if no exception occurred.
+ * @return the UninstallException that might occur during installation or
+ * <CODE>null</CODE> if no exception occurred.
+ */
+ public UninstallException getException()
+ {
+ return ue;
+ }
+
+ /**
+ * Initialize the different map used in this class.
+ *
+ */
+ private void initMaps()
+ {
+ hmSummary.put(UninstallProgressStep.NOT_STARTED,
+ getFormattedSummary(getMsg("summary-uninstall-not-started")));
+ hmSummary.put(UninstallProgressStep.STOPPING_SERVER,
+ getFormattedSummary(getMsg("summary-stopping")));
+ hmSummary.put(UninstallProgressStep.DELETING_EXTERNAL_DATABASE_FILES,
+ getFormattedSummary(getMsg("summary-deleting-external-db-files")));
+ hmSummary.put(UninstallProgressStep.DELETING_EXTERNAL_LOG_FILES,
+ getFormattedSummary(getMsg("summary-deleting-external-log-files")));
+ hmSummary.put(UninstallProgressStep.REMOVING_EXTERNAL_REFERENCES,
+ getFormattedSummary(getMsg("summary-deleting-external-references")));
+ hmSummary.put(UninstallProgressStep.DELETING_INSTALLATION_FILES,
+ getFormattedSummary(getMsg("summary-deleting-installation-files")));
+
+ String successMsg;
+ if (Utils.isCli())
+ {
+ if (userData.getRemoveLibrariesAndTools())
+ {
+ String[] arg = {getTab()+getQuicksetupJarPath()+
+ getLineBreak()+getTab()+getOpenDSJarPath()};
+ successMsg = getMsg(
+ "summary-uninstall-finished-successfully-remove-jarfiles-cli",
+ arg);
+ }
+ else
+ {
+ successMsg = getMsg("summary-uninstall-finished-successfully-cli");
+ }
+ }
+ else
+ {
+ if (userData.getRemoveLibrariesAndTools())
+ {
+ String[] arg = {getTab()+getQuicksetupJarPath()+
+ getLineBreak()+getTab()+getOpenDSJarPath()};
+ successMsg = getMsg(
+ "summary-uninstall-finished-successfully-remove-jarfiles", arg);
+ }
+ else
+ {
+ successMsg = getMsg("summary-uninstall-finished-successfully");
+ }
+ }
+ hmSummary.put(UninstallProgressStep.FINISHED_SUCCESSFULLY,
+ getFormattedSuccess(successMsg));
+ hmSummary.put(UninstallProgressStep.FINISHED_WITH_ERROR,
+ getFormattedError(getMsg("summary-uninstall-finished-with-error")));
+
+
+ /*
+ * hmTime contains the relative time that takes for each task to be
+ * accomplished. For instance if stopping takes twice the time of
+ * deleting files, the value for downloading will be the double of the
+ * value for extracting.
+ */
+ HashMap<UninstallProgressStep, Integer> hmTime =
+ new HashMap<UninstallProgressStep, Integer>();
+ hmTime.put(UninstallProgressStep.STOPPING_SERVER, 15);
+ hmTime.put(UninstallProgressStep.DELETING_EXTERNAL_DATABASE_FILES, 30);
+ hmTime.put(UninstallProgressStep.DELETING_EXTERNAL_LOG_FILES, 5);
+ hmTime.put(UninstallProgressStep.REMOVING_EXTERNAL_REFERENCES, 5);
+ hmTime.put(UninstallProgressStep.DELETING_INSTALLATION_FILES, 10);
+
+ int totalTime = 0;
+ ArrayList<UninstallProgressStep> steps =
+ new ArrayList<UninstallProgressStep>();
+ if (getUserData().getStopServer())
+ {
+ totalTime += hmTime.get(UninstallProgressStep.STOPPING_SERVER);
+ steps.add(UninstallProgressStep.STOPPING_SERVER);
+ }
+ totalTime += hmTime.get(UninstallProgressStep.DELETING_INSTALLATION_FILES);
+ steps.add(UninstallProgressStep.DELETING_INSTALLATION_FILES);
+
+ if (getUserData().getExternalDbsToRemove().size() > 0)
+ {
+ totalTime += hmTime.get(
+ UninstallProgressStep.DELETING_EXTERNAL_DATABASE_FILES);
+ steps.add(UninstallProgressStep.DELETING_EXTERNAL_DATABASE_FILES);
+ }
+
+ if (getUserData().getExternalLogsToRemove().size() > 0)
+ {
+ totalTime += hmTime.get(
+ UninstallProgressStep.DELETING_EXTERNAL_LOG_FILES);
+ steps.add(UninstallProgressStep.DELETING_EXTERNAL_LOG_FILES);
+ }
+
+ int cumulatedTime = 0;
+ for (UninstallProgressStep s : steps)
+ {
+ Integer statusTime = hmTime.get(s);
+ hmRatio.put(s, (100 * cumulatedTime) / totalTime);
+ if (statusTime != null)
+ {
+ cumulatedTime += statusTime;
+ }
+ }
+
+ hmRatio.put(UninstallProgressStep.FINISHED_SUCCESSFULLY, 100);
+ hmRatio.put(UninstallProgressStep.FINISHED_WITH_ERROR, 100);
+ }
+
+ /**
+ * 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()
+ {
+ try
+ {
+ boolean displaySeparator = false;
+ if (getUserData().getStopServer())
+ {
+ status = UninstallProgressStep.STOPPING_SERVER;
+ stopServer();
+ displaySeparator = true;
+ }
+
+ Set<String> dbsToDelete = getUserData().getExternalDbsToRemove();
+ if (dbsToDelete.size() > 0)
+ {
+ status = UninstallProgressStep.DELETING_EXTERNAL_DATABASE_FILES;
+ if (displaySeparator)
+ {
+ notifyListeners(getTaskSeparator());
+ }
+
+ deleteExternalDatabaseFiles(dbsToDelete);
+ displaySeparator = true;
+ }
+
+ Set<String> logsToDelete = getUserData().getExternalLogsToRemove();
+ if (logsToDelete.size() > 0)
+ {
+ status = UninstallProgressStep.DELETING_EXTERNAL_LOG_FILES;
+
+ if (displaySeparator)
+ {
+ notifyListeners(getTaskSeparator());
+ }
+
+ deleteExternalLogFiles(logsToDelete);
+ displaySeparator = true;
+ }
+
+ boolean somethingToDelete = userData.getRemoveBackups() ||
+ userData.getRemoveConfigurationAndSchema() ||
+ userData.getRemoveDatabases() ||
+ userData.getRemoveLDIFs() ||
+ userData.getRemoveLibrariesAndTools() ||
+ userData.getRemoveLogs();
+ if (displaySeparator && somethingToDelete)
+ {
+ notifyListeners(getTaskSeparator());
+ }
+
+ if (somethingToDelete)
+ {
+ status = UninstallProgressStep.DELETING_INSTALLATION_FILES;
+ deleteInstallationFiles(getRatio(status),
+ getRatio(UninstallProgressStep.FINISHED_SUCCESSFULLY));
+ }
+ status = UninstallProgressStep.FINISHED_SUCCESSFULLY;
+ if (Utils.isCli())
+ {
+ notifyListeners(getLineBreak()+getLineBreak()+getSummary(status));
+ }
+ else
+ {
+ notifyListeners(null);
+ }
+
+ } catch (UninstallException ex)
+ {
+ ue = ex;
+ status = UninstallProgressStep.FINISHED_WITH_ERROR;
+ String msg = getFormattedError(ex, true);
+ notifyListeners(msg);
+ }
+ catch (Throwable t)
+ {
+ ue = new UninstallException(
+ UninstallException.Type.BUG,
+ getThrowableMsg("bug-msg", t), t);
+ status = UninstallProgressStep.FINISHED_WITH_ERROR;
+ String msg = getFormattedError(ue, true);
+ notifyListeners(msg);
+ }
+ }
+
+ /**
+ * 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.
+ */
+ 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);
+ }
+
+ /**
+ * Returns an integer that specifies which percentage of the whole
+ * installation has been completed.
+ * @param step the UninstallProgressStep for which we want to get the ratio.
+ * @return an integer that specifies which percentage of the whole
+ * uninstallation has been completed.
+ */
+ private Integer getRatio(UninstallProgressStep status)
+ {
+ return hmRatio.get(status);
+ }
+
+ /**
+ * Returns an formatted representation of the summary for the specified
+ * UninstallProgressStep.
+ * @param step the UninstallProgressStep for which we want to get the summary.
+ * @return an formatted representation of the summary for the specified
+ * UninstallProgressStep.
+ */
+ private String getSummary(UninstallProgressStep status)
+ {
+ return hmSummary.get(status);
+ }
+
+ /**
+ * This methods stops the server.
+ * @throws UninstallException if something goes wrong.
+ */
+ private void stopServer() throws UninstallException
+ {
+ notifyListeners(getFormattedProgress(getMsg("progress-stopping")) +
+ getLineBreak());
+
+ ArrayList<String> argList = new ArrayList<String>();
+
+ if (Utils.isWindows())
+ {
+ argList.add(Utils.getPath(getBinariesPath(), "stop-ds.bat"));
+ argList.add("--bindDN");
+ argList.add(userData.getDirectoryManagerDn());
+ argList.add("--bindPassword");
+ argList.add(userData.getDirectoryManagerPwd());
+ } else
+ {
+ argList.add(Utils.getPath(getBinariesPath(), "stop-ds"));
+ }
+ 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 uninstaller
+ * JVM to stop the server.
+ */
+ env.remove("JAVA_BIN");
+
+ try
+ {
+ Process process = pb.start();
+
+ BufferedReader err =
+ new BufferedReader(new InputStreamReader(process.getErrorStream()));
+ BufferedReader out =
+ new BufferedReader(new InputStreamReader(process.getInputStream()));
+
+ /* Create these objects to resend the stop process output to the details
+ * area.
+ */
+ new StopReader(err, true);
+ new StopReader(out, false);
+
+ int returnValue = process.waitFor();
+
+ int clientSideError =
+ org.opends.server.protocols.ldap.LDAPResultCode.CLIENT_SIDE_CONNECT_ERROR;
+ if ((returnValue == clientSideError) || (returnValue == 0))
+ {
+ if (Utils.isWindows())
+ {
+ /*
+ * Sometimes the server keeps some locks on the files.
+ * TODO: remove this code once stop-ds returns properly when server
+ * is stopped.
+ */
+ int nTries = 10;
+ boolean stopped = false;
+ String testPath = Utils.getInstallPathFromClasspath()+File.separator+
+ "locks"+File.separator+"server.lock";
+ File testFile = new File(testPath);
+ for (int i=0; i<nTries && !stopped; i++)
+ {
+ stopped = canWriteFile(testFile);
+ if (!stopped)
+ {
+ String msg =
+ getFormattedLog(getMsg("progress-server-waiting-to-stop"))+
+ getLineBreak();
+ notifyListeners(msg);
+ try
+ {
+ Thread.sleep(5000);
+ }
+ catch (Exception ex)
+ {
+
+ }
+ }
+ }
+ if (!stopped)
+ {
+ returnValue = -1;
+ }
+ }
+ }
+
+ if (returnValue == clientSideError)
+ {
+ String msg = getLineBreak() +
+ getFormattedLog(getMsg("progress-server-already-stopped"))+
+ getLineBreak();
+ notifyListeners(msg);
+
+ }
+ else if (returnValue != 0)
+ {
+ String[] arg = {String.valueOf(returnValue)};
+ String msg = getMsg("error-stopping-server-code", arg);
+
+ /*
+ * The return code is not the one expected, assume the server could
+ * not be stopped.
+ */
+ throw new UninstallException(UninstallException.Type.STOP_ERROR, msg,
+ null);
+ }
+ else
+ {
+ String msg = getFormattedLog(getMsg("progress-server-stopped"));
+ notifyListeners(msg);
+ }
+
+ } catch (IOException ioe)
+ {
+ throw new UninstallException(UninstallException.Type.STOP_ERROR,
+ getThrowableMsg("error-stopping-server", ioe), ioe);
+ }
+ catch (InterruptedException ie)
+ {
+ throw new UninstallException(UninstallException.Type.BUG,
+ getThrowableMsg("error-stopping-server", ie), ie);
+ }
+ }
+
+ /**
+ * Deletes the external database files specified in the provided Set.
+ * @param dbFiles the database directories to be deleted.
+ * @throws UninstallException if something goes wrong.
+ */
+ private void deleteExternalDatabaseFiles(Set<String> dbFiles)
+ throws UninstallException
+ {
+ notifyListeners(getFormattedProgress(
+ getMsg("progress-deleting-external-db-files")) +
+ getLineBreak());
+ for (String path : dbFiles)
+ {
+ deleteRecursively(new File(path));
+ }
+ }
+
+ /**
+ * Deletes the external database files specified in the provided Set.
+ * @param logFiles the log files to be deleted.
+ * @throws UninstallException if something goes wrong.
+ */
+ private void deleteExternalLogFiles(Set<String> logFiles)
+ throws UninstallException
+ {
+ notifyListeners(getFormattedProgress(
+ getMsg("progress-deleting-external-log-files")) +
+ getLineBreak());
+ for (String path : logFiles)
+ {
+ deleteRecursively(new File(path));
+ }
+ }
+
+ /**
+ * Deletes the files under the installation path.
+ * @throws UninstallException if something goes wrong.
+ */
+ private void deleteInstallationFiles(int minRatio, int maxRatio)
+ throws UninstallException
+ {
+ notifyListeners(getFormattedProgress(
+ getMsg("progress-deleting-installation-files")) +
+ getLineBreak());
+ File f = new File(Utils.getInstallPathFromClasspath());
+ InstallationFilesToDeleteFilter filter =
+ new InstallationFilesToDeleteFilter();
+ File[] rootFiles = f.listFiles();
+ if (rootFiles != null)
+ {
+ /* The following is done to have a moving progress bar when we delete
+ * the installation files.
+ */
+ int totalRatio = 0;
+ ArrayList<Integer> cumulatedRatio = new ArrayList<Integer>();
+ for (int i=0; i<rootFiles.length; i++)
+ {
+ if (filter.accept(rootFiles[i]))
+ {
+ int relativeRatio;
+ if (equalsOrDescendant(rootFiles[i], new File(getLibrariesPath())))
+ {
+ relativeRatio = 10;
+ }
+ else if (equalsOrDescendant(rootFiles[i], new File(getBinariesPath())))
+ {
+ relativeRatio = 5;
+ }
+ else if (equalsOrDescendant(rootFiles[i], new File(getConfigPath())))
+ {
+ relativeRatio = 5;
+ }
+ else if (equalsOrDescendant(rootFiles[i], new File(getBackupsPath())))
+ {
+ relativeRatio = 20;
+ }
+ else if (equalsOrDescendant(rootFiles[i], new File(getLDIFsPath())))
+ {
+ relativeRatio = 20;
+ }
+ else if (equalsOrDescendant(rootFiles[i],
+ new File(getDatabasesPath())))
+ {
+ relativeRatio = 50;
+ }
+ else if (equalsOrDescendant(rootFiles[i], new File(getLogsPath())))
+ {
+ relativeRatio = 30;
+ }
+ else
+ {
+ relativeRatio = 2;
+ }
+ cumulatedRatio.add(totalRatio);
+ totalRatio += relativeRatio;
+ }
+ else
+ {
+ cumulatedRatio.add(totalRatio);
+ }
+ }
+ Iterator<Integer> it = cumulatedRatio.iterator();
+ for (int i=0; i<rootFiles.length; i++)
+ {
+ int beforeRatio = minRatio +
+ ((it.next() * (maxRatio - minRatio)) / totalRatio);
+ hmRatio.put(UninstallProgressStep.DELETING_INSTALLATION_FILES,
+ beforeRatio);
+ deleteRecursively(rootFiles[i], filter);
+ }
+ hmRatio.put(UninstallProgressStep.DELETING_INSTALLATION_FILES, maxRatio);
+ }
+ }
+
+ /**
+ * 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.
+ */
+ private String getQuicksetupJarPath()
+ {
+ return Utils.getPath(getLibrariesPath(), "quicksetup.jar");
+ }
+
+ /**
+ * Returns the path to the open ds jar file.
+ * @return the path to the open ds jar file.
+ */
+ private String getOpenDSJarPath()
+ {
+ return Utils.getPath(getLibrariesPath(), "OpenDS.jar");
+ }
+
+ /**
+ * Returns the path to the backup files under the install path.
+ * @return the path to the backup files under the install path.
+ */
+ private String getBackupsPath()
+ {
+ return Utils.getPath(Utils.getInstallPathFromClasspath(),
+ Utils.getBackupsRelativePath());
+ }
+
+ /**
+ * Returns the path to the LDIF files under the install path.
+ * @return the path to the LDIF files under the install path.
+ */
+ private String getLDIFsPath()
+ {
+ return Utils.getPath(Utils.getInstallPathFromClasspath(),
+ Utils.getLDIFsRelativePath());
+ }
+
+ /**
+ * Returns the path to the config files under the install path.
+ * @return the path to the config files under the install path.
+ */
+ private String getConfigPath()
+ {
+ return Utils.getPath(Utils.getInstallPathFromClasspath(),
+ Utils.getConfigRelativePath());
+ }
+
+ /**
+ * Returns the path to the log files under the install path.
+ * @return the path to the log files under the install path.
+ */
+ private String getLogsPath()
+ {
+ return Utils.getPath(Utils.getInstallPathFromClasspath(),
+ Utils.getLogsRelativePath());
+ }
+
+ /**
+ * Returns the path to the database files under the install path.
+ * @return the path to the database files under the install path.
+ */
+ private String getDatabasesPath()
+ {
+ return Utils.getPath(Utils.getInstallPathFromClasspath(),
+ Utils.getDatabasesRelativePath());
+ }
+
+ /**
+ * Deletes everything below the specified file.
+ * @param file the path to be deleted.
+ * @throws UninstallException if something goes wrong.
+ */
+ private void deleteRecursively(File file) throws UninstallException
+ {
+ deleteRecursively(file, null);
+ }
+
+ /**
+ * Deletes everything below the specified file.
+ * @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.
+ */
+
+ private void deleteRecursively(File file, FileFilter filter)
+ throws UninstallException
+ {
+ if (file.exists())
+ {
+ if (file.isFile())
+ {
+ if (filter != null)
+ {
+ if (filter.accept(file))
+ {
+ delete(file);
+ }
+ }
+ else
+ {
+ delete(file);
+ }
+ }
+ else
+ {
+ File[] children = file.listFiles();
+ if (children != null)
+ {
+ for (int i=0; i<children.length; i++)
+ {
+ deleteRecursively(children[i], filter);
+ }
+ }
+ if (filter != null)
+ {
+ if (filter.accept(file))
+ {
+ delete(file);
+ }
+ }
+ else
+ {
+ delete(file);
+ }
+ }
+ }
+ else
+ {
+ // Just tell that the file/directory does not exist.
+ String[] arg = {file.toString()};
+ notifyListeners(getFormattedWarning(
+ getMsg("deleting-file-does-not-exist", arg)));
+ }
+ }
+
+ /**
+ * Deletes the specified file.
+ * @param file the file to be deleted.
+ * @throws UninstallException if something goes wrong.
+ */
+ private void delete(File file) throws UninstallException
+ {
+ String[] arg = {file.getAbsolutePath()};
+ boolean isFile = file.isFile();
+
+ if (isFile)
+ {
+ notifyListeners(getFormattedWithPoints(
+ getMsg("progress-deleting-file", arg)));
+ }
+ else
+ {
+ notifyListeners(getFormattedWithPoints(
+ getMsg("progress-deleting-directory", arg)));
+ }
+
+ boolean delete = false;
+ /*
+ * Sometimes the server keeps some locks on the files.
+ * TODO: remove this code once stop-ds returns properly when server
+ * is stopped.
+ */
+ int nTries = 5;
+ for (int i=0; i<nTries && !delete; i++)
+ {
+ delete = file.delete();
+ if (!delete)
+ {
+ try
+ {
+ Thread.sleep(1000);
+ }
+ catch (Exception ex)
+ {
+ }
+ }
+ }
+
+ if (!delete)
+ {
+ String errMsg;
+ if (isFile)
+ {
+ errMsg = getMsg("error-deleting-file", arg);
+ }
+ else
+ {
+ errMsg = getMsg("error-deleting-directory", arg);
+ }
+ throw new UninstallException(
+ UninstallException.Type.FILE_SYSTEM_ERROR, errMsg, null);
+ }
+
+ notifyListeners(getFormattedDone()+getLineBreak());
+ }
+
+ private boolean equalsOrDescendant(File file, File directory)
+ {
+ return file.equals(directory) ||
+ Utils.isDescendant(file.toString(), directory.toString());
+ }
+
+ /**
+ * This class is used to read the standard error and standard output of the
+ * Stop process.
+ *
+ * When a new log message is found notifies the
+ * UninstallProgressUpdateListeners of it. If an error occurs it also
+ * notifies the listeners.
+ *
+ */
+ private class StopReader
+ {
+ private UninstallException ex;
+
+ private boolean isFirstLine;
+
+ /**
+ * The protected constructor.
+ * @param reader the BufferedReader of the stop process.
+ * @param isError a boolean indicating whether the BufferedReader
+ * corresponds to the standard error or to the standard output.
+ */
+ public StopReader(final BufferedReader reader,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;
+
+ line = reader.readLine();
+ }
+ } catch (IOException ioe)
+ {
+ String errorMsg = getThrowableMsg(errorTag, ioe);
+ ex =
+ new UninstallException(UninstallException.Type.STOP_ERROR,
+ errorMsg, ioe);
+
+ } catch (Throwable t)
+ {
+ String errorMsg = getThrowableMsg(errorTag, t);
+ ex =
+ new UninstallException(UninstallException.Type.STOP_ERROR,
+ errorMsg, t);
+ }
+ }
+ });
+ t.start();
+ }
+
+ /**
+ * Returns the UninstallException that occurred reading the Stop 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 UninstallException getException()
+ {
+ return ex;
+ }
+ }
+
+ private boolean canWriteFile(File file)
+ {
+ boolean canWriteFile = false;
+ Writer output = null;
+ try {
+ //use buffering
+ //FileWriter always assumes default encoding is OK!
+ output = new BufferedWriter( new FileWriter(file) );
+ output.write("test");
+ output.close();
+ canWriteFile = true;
+ }
+ catch (Throwable t)
+ {
+ }
+ return canWriteFile;
+ }
+
+ /**
+ * This class is used to get the files that are not binaries. This is
+ * required to know which are the files that can be deleted directly and which
+ * not.
+ */
+ class InstallationFilesToDeleteFilter implements FileFilter
+ {
+ File quicksetupFile = new File(getQuicksetupJarPath());
+ File openDSFile = new File(getOpenDSJarPath());
+ File librariesFile = new File(getLibrariesPath());
+
+ File installationPath = new File(Utils.getInstallPathFromClasspath());
+ /**
+ * {@inheritDoc}
+ */
+ public boolean accept(File file)
+ {
+ boolean[] uData = {
+ userData.getRemoveLibrariesAndTools(),
+ userData.getRemoveLibrariesAndTools(),
+ userData.getRemoveDatabases(),
+ userData.getRemoveLogs(),
+ userData.getRemoveConfigurationAndSchema(),
+ userData.getRemoveBackups(),
+ userData.getRemoveLDIFs()
+ };
+
+ String[] parentFiles = {
+ getLibrariesPath(),
+ getBinariesPath(),
+ getDatabasesPath(),
+ getLogsPath(),
+ getConfigPath(),
+ getBackupsPath(),
+ getLDIFsPath()
+ };
+
+ boolean accept =
+ !installationPath.equals(file)
+ && !librariesFile.equals(file)
+ && !quicksetupFile.equals(file)
+ && !openDSFile.equals(file);
+
+ for (int i=0; i<uData.length && accept; i++)
+ {
+ accept &= uData[i] ||
+ !equalsOrDescendant(file, new File(parentFiles[i]));
+ }
+
+ return accept;
+ }
}
}
--
Gitblit v1.10.0