/*
* 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
*
*
* Copyright 2006-2010 Sun Microsystems, Inc.
*/
package org.opends.guitools.uninstaller;
import org.opends.quicksetup.*;
import static org.opends.quicksetup.Step.FINISHED;
import static org.opends.quicksetup.Step.PROGRESS;
import static org.opends.quicksetup.Step.REVIEW;
import org.opends.admin.ads.ADSContext;
import org.opends.admin.ads.ADSContextException;
import org.opends.admin.ads.ReplicaDescriptor;
import org.opends.admin.ads.ServerDescriptor;
import org.opends.admin.ads.TopologyCache;
import org.opends.admin.ads.TopologyCacheException;
import org.opends.admin.ads.util.ApplicationTrustManager;
import org.opends.admin.ads.util.ConnectionUtils;
import org.opends.admin.ads.util.PreferredConnection;
import org.opends.guitools.uninstaller.ui.ConfirmUninstallPanel;
import org.opends.guitools.uninstaller.ui.LoginDialog;
import org.opends.quicksetup.ui.*;
import static org.opends.quicksetup.util.Utils.*;
import org.opends.quicksetup.util.BackgroundTask;
import org.opends.quicksetup.util.ServerController;
import org.opends.quicksetup.util.UIKeyStore;
import org.opends.quicksetup.util.Utils;
import org.opends.server.admin.AttributeTypePropertyDefinition;
import org.opends.server.admin.ClassLoaderProvider;
import org.opends.server.admin.ClassPropertyDefinition;
import org.opends.server.admin.ManagedObjectNotFoundException;
import org.opends.server.admin.client.ManagementContext;
import org.opends.server.admin.client.ldap.JNDIDirContextAdaptor;
import org.opends.server.admin.client.ldap.LDAPManagementContext;
import org.opends.server.admin.std.client.ReplicationDomainCfgClient;
import
org.opends.server.admin.std.client.ReplicationSynchronizationProviderCfgClient;
import org.opends.server.admin.std.client.ReplicationServerCfgClient;
import org.opends.server.admin.std.client.RootCfgClient;
import org.opends.server.core.DirectoryServer;
import org.opends.server.tools.ConfigureWindowsService;
import org.opends.server.tools.ToolConstants;
import org.opends.messages.Message;
import org.opends.messages.MessageBuilder;
import static org.opends.messages.AdminToolMessages.*;
import static org.opends.messages.QuickSetupMessages.*;
import java.io.*;
import java.net.InetAddress;
import java.net.URI;
import java.security.cert.X509Certificate;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.awt.event.WindowEvent;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.ldap.InitialLdapContext;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import org.opends.server.util.DynamicConstants;
/**
* This class is in charge of performing the uninstallation of Open DS.
*/
public class Uninstaller extends GuiApplication implements CliApplication {
private ProgressStep status = UninstallProgressStep.NOT_STARTED;
private boolean runStarted;
private boolean errorOnRemoteOccurred;
private boolean errorDeletingOccurred;
private UninstallerArgumentParser parser;
private HashMap<ProgressStep, Integer> hmRatio =
new HashMap<ProgressStep, Integer>();
private HashMap<ProgressStep, Message> hmSummary =
new HashMap<ProgressStep, Message>();
private ApplicationException ue;
private Boolean isWindowsServiceEnabled;
private UninstallCliHelper cliHelper = new UninstallCliHelper();
private static final Logger LOG =
Logger.getLogger(Uninstaller.class.getName());
private LoginDialog loginDialog;
private ProgressDialog startProgressDlg;
private MessageBuilder startProgressDetails = new MessageBuilder();
private UninstallData conf;
/**
* Default constructor.
*/
public Uninstaller()
{
super();
/* Do some initialization required to use the administration framework
* classes. Note that this is not done in the uninstaller code because
* when the basic configuration of the server is performed (using
* ConfigureDS) this initialization is done.
*/
DirectoryServer.bootstrapClient();
// Bootstrap definition classes.
try
{
if (!ClassLoaderProvider.getInstance().isEnabled())
{
ClassLoaderProvider.getInstance().enable();
}
}
catch (Throwable t)
{
LOG.log(Level.WARNING, "Error enabling admin framework class loader: "+t,
t);
}
// Switch off class name validation in client.
ClassPropertyDefinition.setAllowClassValidation(false);
// Switch off attribute type name validation in client.
AttributeTypePropertyDefinition.setCheckSchema(false);
LOG.log(Level.INFO, "Uninstaller is created.");
}
/**
* {@inheritDoc}
*/
public Message getFrameTitle() {
Message title = Utils.getCustomizedObject("INFO_FRAME_UNINSTALL_TITLE",
INFO_FRAME_UNINSTALL_TITLE.get(
DynamicConstants.PRODUCT_NAME), Message.class);
return title;
}
/**
* {@inheritDoc}
*/
public UserData createUserData() {
UninstallUserData data = new UninstallUserData();
data.setTrustManager(super.getTrustManager());
return data;
}
/**
* {@inheritDoc}
*/
public WizardStep getFirstWizardStep() {
return Step.CONFIRM_UNINSTALL;
}
/**
* {@inheritDoc}
*/
public WizardStep getNextWizardStep(WizardStep step) {
Step nextStep = null;
if (step != null && step.equals(Step.CONFIRM_UNINSTALL)) {
nextStep = Step.PROGRESS;
}
else if (Step.PROGRESS.equals(step))
{
nextStep = Step.FINISHED;
}
return nextStep;
}
/**
* {@inheritDoc}
*/
public WizardStep getPreviousWizardStep(WizardStep step) {
Step prevStep = null;
if (step != null && step.equals(Step.PROGRESS)) {
prevStep = Step.CONFIRM_UNINSTALL;
}
else if (Step.FINISHED.equals(step))
{
prevStep = Step.PROGRESS;
}
return prevStep;
}
/**
* {@inheritDoc}
*/
public WizardStep getFinishedStep() {
return Step.FINISHED;
}
/**
* {@inheritDoc}
*/
public boolean finishOnLeft()
{
return false;
}
/**
* {@inheritDoc}
*/
public boolean canGoBack(WizardStep step) {
return false;
}
/**
* {@inheritDoc}
*/
public boolean canGoForward(WizardStep step) {
return false;
}
/**
* {@inheritDoc}
*/
public boolean canFinish(WizardStep step) {
return step == Step.CONFIRM_UNINSTALL;
}
/**
* {@inheritDoc}
*/
public boolean canQuit(WizardStep step) {
return step == Step.CONFIRM_UNINSTALL;
}
/**
* {@inheritDoc}
*/
public void nextClicked(WizardStep cStep, QuickSetup qs) {
if (cStep == PROGRESS) {
throw new IllegalStateException(
"Cannot click on next from progress step");
} else if (cStep == REVIEW) {
throw new IllegalStateException("Cannot click on next from review step");
} else if (cStep == FINISHED) {
throw new IllegalStateException(
"Cannot click on next from finished step");
}
}
/**
* {@inheritDoc}
*/
public void closeClicked(WizardStep cStep, QuickSetup qs) {
if (cStep == PROGRESS) {
if (isFinished()
|| qs.displayConfirmation(INFO_CONFIRM_CLOSE_UNINSTALL_MSG.get(),
INFO_CONFIRM_CLOSE_UNINSTALL_TITLE.get()))
{
qs.quit();
}
}
else if (cStep == FINISHED)
{
qs.quit();
} else {
throw new IllegalStateException(
"Close only can be clicked on PROGRESS step");
}
}
/**
* Update the UserData object according to the content of the review
* panel.
*/
private void updateUserUninstallDataForConfirmUninstallPanel(QuickSetup qs)
throws UserDataException {
UninstallUserData uud = getUninstallUserData();
uud.setRemoveLibrariesAndTools(
(Boolean) qs.getFieldValue(FieldName.REMOVE_LIBRARIES_AND_TOOLS));
uud.setRemoveDatabases(
(Boolean) qs.getFieldValue(FieldName.REMOVE_DATABASES));
uud.setRemoveConfigurationAndSchema(
(Boolean) qs.getFieldValue(
FieldName.REMOVE_CONFIGURATION_AND_SCHEMA));
uud.setRemoveBackups(
(Boolean) qs.getFieldValue(FieldName.REMOVE_BACKUPS));
uud.setRemoveLDIFs(
(Boolean) qs.getFieldValue(FieldName.REMOVE_LDIFS));
uud.setRemoveLogs(
(Boolean) qs.getFieldValue(FieldName.REMOVE_LOGS));
// This is updated on the method handleTopologyCache
uud.setUpdateRemoteReplication(false);
Set<String> dbs = new HashSet<String>();
Set<?> s = (Set<?>) qs.getFieldValue(FieldName.EXTERNAL_DB_DIRECTORIES);
for (Object v : s) {
dbs.add((String) v);
}
Set<String> logs = new HashSet<String>();
s = (Set<?>) qs.getFieldValue(FieldName.EXTERNAL_LOG_FILES);
for (Object v : s) {
logs.add((String) v);
}
uud.setExternalDbsToRemove(dbs);
uud.setExternalLogsToRemove(logs);
if ((dbs.size() == 0) &&
(logs.size() == 0) &&
!uud.getRemoveLibrariesAndTools() &&
!uud.getRemoveDatabases() &&
!uud.getRemoveConfigurationAndSchema() &&
!uud.getRemoveBackups() &&
!uud.getRemoveLDIFs() &&
!uud.getRemoveLogs()) {
throw new UserDataException(Step.CONFIRM_UNINSTALL,
INFO_NOTHING_SELECTED_TO_UNINSTALL.get());
}
}
/**
* {@inheritDoc}
*/
public void quitClicked(WizardStep step, QuickSetup qs) {
if (step == Step.PROGRESS) {
throw new IllegalStateException(
"Cannot click on quit from progress step");
}
else if (step == Step.FINISHED) {
throw new IllegalStateException(
"Cannot click on quit from finished step");
}
qs.quit();
}
/**
* {@inheritDoc}
*/
public Message getCloseButtonToolTip() {
return INFO_CLOSE_BUTTON_UNINSTALL_TOOLTIP.get();
}
/**
* {@inheritDoc}
*/
public Message getFinishButtonToolTip() {
return INFO_FINISH_BUTTON_UNINSTALL_TOOLTIP.get();
}
/**
* {@inheritDoc}
*/
public Message getFinishButtonLabel() {
return INFO_FINISH_BUTTON_UNINSTALL_LABEL.get();
}
/**
* {@inheritDoc}
*/
public void previousClicked(WizardStep cStep, QuickSetup qs) {
if (cStep == PROGRESS) {
throw new IllegalStateException(
"Cannot click on previous from progress step");
}
else if (cStep == FINISHED) {
throw new IllegalStateException(
"Cannot click on previous from finished step");
}
}
/**
* {@inheritDoc}
*/
public void notifyListeners(Integer ratio, Message currentPhaseSummary,
final Message newLogDetail)
{
if (runStarted)
{
super.notifyListeners(ratio, currentPhaseSummary, newLogDetail);
}
else
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
if (startProgressDlg != null)
{
if (newLogDetail != null)
{
startProgressDetails.append(newLogDetail);
startProgressDlg.setDetails(startProgressDetails.toMessage());
}
}
}
});
}
}
/**
* {@inheritDoc}
*/
public boolean finishClicked(final WizardStep cStep, final QuickSetup qs) {
if (cStep == Step.CONFIRM_UNINSTALL) {
BackgroundTask<UninstallData> worker =
new BackgroundTask<UninstallData>() {
public UninstallData processBackgroundTask() throws UserDataException {
try {
updateUserUninstallDataForConfirmUninstallPanel(qs);
return new UninstallData(Installation.getLocal());
}
catch (UserDataException uude) {
throw uude;
} catch (Throwable t) {
LOG.log(Level.WARNING, "Error processing task: "+t, t);
throw new UserDataException(Step.CONFIRM_UNINSTALL,
getThrowableMsg(INFO_BUG_MSG.get(), t));
}
}
public void backgroundTaskCompleted(UninstallData returnValue,
Throwable throwable) {
qs.getDialog().workerFinished();
if (throwable != null) {
if (throwable instanceof UserDataException)
{
qs.displayError(Message.raw(throwable.getLocalizedMessage()),
INFO_ERROR_TITLE.get());
}
else
{
LOG.log(Level.WARNING, "Error processing task: "+throwable,
throwable);
qs.displayError(Message.raw(throwable.toString()),
INFO_ERROR_TITLE.get());
}
} else {
conf = returnValue;
if (conf.isADS() && conf.isReplicationServer())
{
if (conf.isServerRunning())
{
if (qs.displayConfirmation(
INFO_CONFIRM_UNINSTALL_REPLICATION_SERVER_RUNNING_MSG.get(),
INFO_CONFIRM_UNINSTALL_REPLICATION_SERVER_RUNNING_TITLE
.get()))
{
askForAuthenticationAndLaunch(qs);
}
else
{
if (qs.displayConfirmation(
INFO_CONFIRM_UNINSTALL_SERVER_RUNNING_MSG.get(),
INFO_CONFIRM_UNINSTALL_SERVER_RUNNING_TITLE.get()))
{
getUserData().setStopServer(true);
qs.launch();
qs.setCurrentStep(
getNextWizardStep(Step.CONFIRM_UNINSTALL));
} else {
getUserData().setStopServer(false);
}
}
}
else
{
if (qs.displayConfirmation(
INFO_CONFIRM_UNINSTALL_REPLICATION_SERVER_NOT_RUNNING_MSG
.get(),
INFO_CONFIRM_UNINSTALL_REPLICATION_SERVER_NOT_RUNNING_TITLE
.get()))
{
boolean startWorked = startServer(qs.getDialog().getFrame());
if (startWorked)
{
askForAuthenticationAndLaunch(qs);
}
else
{
getUserData().setStopServer(false);
if (qs.displayConfirmation(
INFO_CONFIRM_UNINSTALL_SERVER_NOT_RUNNING_MSG.get(),
INFO_CONFIRM_UNINSTALL_SERVER_NOT_RUNNING_TITLE.get()))
{
qs.launch();
qs.setCurrentStep(
getNextWizardStep(Step.CONFIRM_UNINSTALL));
}
}
}
else
{
getUserData().setStopServer(false);
if (qs.displayConfirmation(
INFO_CONFIRM_UNINSTALL_SERVER_NOT_RUNNING_MSG.get(),
INFO_CONFIRM_UNINSTALL_SERVER_NOT_RUNNING_TITLE.get()))
{
qs.launch();
qs.setCurrentStep(
getNextWizardStep(Step.CONFIRM_UNINSTALL));
}
}
}
}
else if (!conf.isServerRunning())
{
getUserData().setStopServer(false);
if (qs.displayConfirmation(
INFO_CONFIRM_UNINSTALL_SERVER_NOT_RUNNING_MSG.get(),
INFO_CONFIRM_UNINSTALL_SERVER_NOT_RUNNING_TITLE.get()))
{
qs.launch();
qs.setCurrentStep(getNextWizardStep(
Step.CONFIRM_UNINSTALL));
}
} else {
if (qs.displayConfirmation(
INFO_CONFIRM_UNINSTALL_SERVER_RUNNING_MSG.get(),
INFO_CONFIRM_UNINSTALL_SERVER_RUNNING_TITLE.get())) {
getUserData().setStopServer(true);
qs.launch();
qs.setCurrentStep(getNextWizardStep(
Step.CONFIRM_UNINSTALL));
} else {
getUserData().setStopServer(false);
}
}
}
}
};
qs.getDialog().workerStarted();
worker.startBackgroundTask();
}
// Uninstaller is responsible for updating user data and launching
return false;
}
/**
* {@inheritDoc}
*/
public void updateUserData(WizardStep step, QuickSetup qs) {
// do nothing;
}
/**
* {@inheritDoc}
*/
public void setWizardDialogState(QuickSetupDialog dlg,
UserData userData,
WizardStep step) {
if (step == Step.CONFIRM_UNINSTALL) {
dlg.setDefaultButton(ButtonName.FINISH);
dlg.setFocusOnButton(ButtonName.FINISH);
} else if ((step == PROGRESS) || (step == FINISHED)) {
dlg.setDefaultButton(ButtonName.CLOSE);
dlg.setFocusOnButton(ButtonName.CLOSE);
dlg.setButtonEnabled(ButtonName.CLOSE, false);
}
}
/**
* {@inheritDoc}
* @param launcher
*/
public UserData createUserData(Launcher launcher)
throws UserDataException, ApplicationException {
parser = (UninstallerArgumentParser)launcher.getArgumentParser();
return cliHelper.createUserData(
parser,
launcher.getArguments());
}
/**
* {@inheritDoc}
*/
public String getInstallationPath() {
return getInstallPathFromClasspath();
}
/**
* {@inheritDoc}
*/
public String getInstancePath() {
return getInstancePathFromInstallPath(getInstallPathFromClasspath());
}
/**
* Returns the ApplicationException that might occur during installation or
* <CODE>null</CODE> if no exception occurred.
*
* @return the ApplicationException that might occur during installation or
* <CODE>null</CODE> if no exception occurred.
*/
public ApplicationException getRunError() {
return ue;
}
/**
* {@inheritDoc}
*/
public ReturnCode getReturnCode() {
return null;
}
/**
* Initialize the different map used in this class.
*/
private void initMaps() {
hmSummary.put(UninstallProgressStep.NOT_STARTED,
getFormattedSummary(INFO_SUMMARY_UNINSTALL_NOT_STARTED.get()));
hmSummary.put(UninstallProgressStep.STOPPING_SERVER,
getFormattedSummary(INFO_SUMMARY_STOPPING.get()));
hmSummary.put(UninstallProgressStep.UNCONFIGURING_REPLICATION,
getFormattedSummary(INFO_SUMMARY_UNCONFIGURING_REPLICATION.get()));
hmSummary.put(UninstallProgressStep.DISABLING_WINDOWS_SERVICE,
getFormattedSummary(INFO_SUMMARY_DISABLING_WINDOWS_SERVICE.get()));
hmSummary.put(UninstallProgressStep.DELETING_EXTERNAL_DATABASE_FILES,
getFormattedSummary(INFO_SUMMARY_DELETING_EXTERNAL_DB_FILES.get()));
hmSummary.put(UninstallProgressStep.DELETING_EXTERNAL_LOG_FILES,
getFormattedSummary(
INFO_SUMMARY_DELETING_EXTERNAL_LOG_FILES.get()));
hmSummary.put(UninstallProgressStep.REMOVING_EXTERNAL_REFERENCES,
getFormattedSummary(
INFO_SUMMARY_DELETING_EXTERNAL_REFERENCES.get()));
hmSummary.put(UninstallProgressStep.DELETING_INSTALLATION_FILES,
getFormattedSummary(
INFO_SUMMARY_DELETING_INSTALLATION_FILES.get()));
Message successMsg;
Installation installation = getInstallation();
String libPath = getPath(installation.getLibrariesDirectory());
String resourcesPath = getPath(installation.getResourcesDirectory());
String classesPath = getPath(installation.getClassesDirectory());
boolean resourcesDefined =
Utils.directoryExistsAndIsNotEmpty(resourcesPath);
boolean classesDefined =
Utils.directoryExistsAndIsNotEmpty(classesPath);
ArrayList<String> paths = new ArrayList<String>();
paths.add(libPath);
if (resourcesDefined)
{
paths.add(resourcesPath);
}
if (classesDefined)
{
paths.add(classesPath);
}
if (isCli()) {
if (getUninstallUserData().getRemoveLibrariesAndTools()) {
String arg;
if (isWindows()) {
arg = installation.getUninstallBatFile() + getLineBreak().toString() +
getTab() + getStringFromCollection(paths,
getLineBreak().toString());
} else {
arg = getStringFromCollection(paths, getLineBreak().toString());
}
successMsg =
INFO_SUMMARY_UNINSTALL_FINISHED_SUCCESSFULLY_REMOVE_JARFILES_CLI
.get(arg);
} else {
successMsg = INFO_SUMMARY_UNINSTALL_FINISHED_SUCCESSFULLY_CLI.get();
}
} else {
if (getUninstallUserData().getRemoveLibrariesAndTools()) {
String formattedPath =
addWordBreaks(
getStringFromCollection(paths, getLineBreak().toString()), 60, 5);
successMsg =
INFO_SUMMARY_UNINSTALL_FINISHED_SUCCESSFULLY_REMOVE_JARFILES
.get(formattedPath);
} else {
successMsg = INFO_SUMMARY_UNINSTALL_FINISHED_SUCCESSFULLY.get();
}
}
hmSummary.put(UninstallProgressStep.FINISHED_SUCCESSFULLY,
getFormattedSuccess(successMsg));
Message nonCriticalMsg;
if (!isCli())
{
nonCriticalMsg =
INFO_SUMMARY_UNINSTALL_FINISHED_WITH_ERROR_ON_REMOTE.get();
}
else
{
nonCriticalMsg =
INFO_SUMMARY_UNINSTALL_FINISHED_WITH_ERROR_ON_REMOTE_CLI.get();
}
hmSummary.put(UninstallProgressStep.FINISHED_WITH_ERROR_ON_REMOTE,
getFormattedWarning(nonCriticalMsg));
if (!isCli())
{
nonCriticalMsg =
INFO_SUMMARY_UNINSTALL_FINISHED_WITH_ERROR_DELETING.get();
}
else
{
nonCriticalMsg =
INFO_SUMMARY_UNINSTALL_FINISHED_WITH_ERROR_DELETING_CLI.get();
}
hmSummary.put(UninstallProgressStep.FINISHED_WITH_ERROR_DELETING,
getFormattedWarning(nonCriticalMsg));
hmSummary.put(UninstallProgressStep.FINISHED_WITH_ERROR,
getFormattedError(
INFO_SUMMARY_UNINSTALL_FINISHED_WITH_ERROR.get()));
/*
* 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.UNCONFIGURING_REPLICATION, 5);
hmTime.put(UninstallProgressStep.STOPPING_SERVER, 15);
hmTime.put(UninstallProgressStep.DISABLING_WINDOWS_SERVICE, 5);
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 (getUninstallUserData().getUpdateRemoteReplication()) {
totalTime += hmTime.get(UninstallProgressStep.UNCONFIGURING_REPLICATION);
steps.add(UninstallProgressStep.UNCONFIGURING_REPLICATION);
}
if (getUserData().getStopServer()) {
totalTime += hmTime.get(UninstallProgressStep.STOPPING_SERVER);
steps.add(UninstallProgressStep.STOPPING_SERVER);
}
if (isWindowsServiceEnabled()) {
totalTime += hmTime.get(UninstallProgressStep.DISABLING_WINDOWS_SERVICE);
steps.add(UninstallProgressStep.DISABLING_WINDOWS_SERVICE);
}
totalTime += hmTime.get(UninstallProgressStep.DELETING_INSTALLATION_FILES);
steps.add(UninstallProgressStep.DELETING_INSTALLATION_FILES);
if (getUninstallUserData().getExternalDbsToRemove().size() > 0) {
totalTime += hmTime.get(
UninstallProgressStep.DELETING_EXTERNAL_DATABASE_FILES);
steps.add(UninstallProgressStep.DELETING_EXTERNAL_DATABASE_FILES);
}
if (getUninstallUserData().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_ON_REMOTE, 100);
hmRatio.put(UninstallProgressStep.FINISHED_WITH_ERROR, 100);
}
/**
* Actually performs the uninstall in this thread. The thread is blocked.
*/
public void run() {
runStarted = true;
LOG.log(Level.INFO, "run of the Uninstaller started");
initMaps();
PrintStream origErr = System.err;
PrintStream origOut = System.out;
try {
PrintStream err = new ErrorPrintStream();
PrintStream out = new OutputPrintStream();
if (!isCli()) {
System.setErr(err);
System.setOut(out);
}
boolean displaySeparator = false;
LOG.log(Level.INFO, "Update remote replication? "+
getUninstallUserData().getUpdateRemoteReplication());
if (getUninstallUserData().getUpdateRemoteReplication())
{
status = UninstallProgressStep.UNCONFIGURING_REPLICATION;
removeRemoteServerReferences();
displaySeparator = true;
}
LOG.log(Level.INFO, "Stop server? "+getUserData().getStopServer());
if (getUserData().getStopServer()) {
status = UninstallProgressStep.STOPPING_SERVER;
if (displaySeparator && isVerbose()) {
notifyListeners(getTaskSeparator());
}
if (!isVerbose())
{
notifyListeners(getFormattedWithPoints(
INFO_PROGRESS_STOPPING_NON_VERBOSE.get()));
}
// In case of uninstall, the server stop has to run locally.
// In order to bypass the tools.properties mechanism, if any,
// we systematically add the --noPropertiesFile flag
// when we run the stop-ds command. This is done
// by setting the parameter "noPropertiesFile" to 'true'
// in the following call.
new ServerController(this).stopServer(!isVerbose(),true);
if (!isVerbose())
{
notifyListeners(getFormattedDoneWithLineBreak());
}
displaySeparator = true;
}
LOG.log(Level.INFO, "Is Windows Service Enabled? "+
isWindowsServiceEnabled());
if (isWindowsServiceEnabled()) {
status = UninstallProgressStep.DISABLING_WINDOWS_SERVICE;
if (displaySeparator && isVerbose()) {
notifyListeners(getTaskSeparator());
}
disableWindowsService();
displaySeparator = true;
}
Set<String> dbsToDelete = getUninstallUserData().getExternalDbsToRemove();
if (dbsToDelete.size() > 0) {
status = UninstallProgressStep.DELETING_EXTERNAL_DATABASE_FILES;
if (displaySeparator && isVerbose()) {
notifyListeners(getTaskSeparator());
}
try
{
deleteExternalDatabaseFiles(dbsToDelete);
displaySeparator = true;
}
catch (ApplicationException ae)
{
if (ae.getType() == ReturnCode.FILE_SYSTEM_ACCESS_ERROR)
{
errorDeletingOccurred = true;
Message msg = getFormattedWarning(ae.getMessageObject());
notifyListeners(msg);
}
else
{
throw ae;
}
}
}
Set<String> logsToDelete =
getUninstallUserData().getExternalLogsToRemove();
if (logsToDelete.size() > 0) {
status = UninstallProgressStep.DELETING_EXTERNAL_LOG_FILES;
if (displaySeparator && isVerbose()) {
notifyListeners(getTaskSeparator());
}
try
{
deleteExternalLogFiles(logsToDelete);
displaySeparator = true;
}
catch (ApplicationException ae)
{
if (ae.getType() == ReturnCode.FILE_SYSTEM_ACCESS_ERROR)
{
errorDeletingOccurred = true;
Message msg = getFormattedWarning(ae.getMessageObject());
notifyListeners(msg);
}
else
{
throw ae;
}
}
}
UninstallUserData userData = getUninstallUserData();
boolean somethingToDelete = userData.getRemoveBackups() ||
userData.getRemoveConfigurationAndSchema() ||
userData.getRemoveDatabases() ||
userData.getRemoveLDIFs() ||
userData.getRemoveLibrariesAndTools() ||
userData.getRemoveLogs();
if (displaySeparator && somethingToDelete && isVerbose()) {
notifyListeners(getTaskSeparator());
}
if (somethingToDelete) {
status = UninstallProgressStep.DELETING_INSTALLATION_FILES;
try
{
deleteInstallationFiles(getRatio(status),
getRatio(UninstallProgressStep.FINISHED_SUCCESSFULLY));
}
catch (ApplicationException ae)
{
if (ae.getType() == ReturnCode.FILE_SYSTEM_ACCESS_ERROR)
{
errorDeletingOccurred = true;
Message msg = getFormattedWarning(ae.getMessageObject());
notifyListeners(msg);
}
else
{
throw ae;
}
}
}
if (errorOnRemoteOccurred)
{
status = UninstallProgressStep.FINISHED_WITH_ERROR_ON_REMOTE;
}
else if (errorDeletingOccurred)
{
status = UninstallProgressStep.FINISHED_WITH_ERROR_DELETING;
}
else
{
status = UninstallProgressStep.FINISHED_SUCCESSFULLY;
}
if (isCli()) {
notifyListeners(new MessageBuilder(getLineBreak())
.append(getLineBreak()).append(getSummary(status))
.toMessage());
} else {
notifyListeners(null);
}
} catch (ApplicationException ex) {
LOG.log(Level.SEVERE, "Error: "+ex, ex);
ue = ex;
status = UninstallProgressStep.FINISHED_WITH_ERROR;
Message msg = getFormattedError(ex, true);
notifyListeners(msg);
}
catch (Throwable t) {
LOG.log(Level.SEVERE, "Error: "+t, t);
ue = new ApplicationException(
ReturnCode.BUG,
getThrowableMsg(INFO_BUG_MSG.get(), t), t);
status = UninstallProgressStep.FINISHED_WITH_ERROR;
Message msg = getFormattedError(ue, true);
notifyListeners(msg);
}
if (!isCli()) {
System.setErr(origErr);
System.setOut(origOut);
}
}
/**
* {@inheritDoc}
*/
public ProgressStep getCurrentProgressStep() {
return status;
}
/**
* 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.
*/
public Integer getRatio(ProgressStep step) {
return hmRatio.get(step);
}
/**
* 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.
*/
public Message getSummary(ProgressStep step) {
return hmSummary.get(step);
}
/**
* {@inheritDoc}
*/
public boolean isFinished() {
return getCurrentProgressStep() ==
UninstallProgressStep.FINISHED_SUCCESSFULLY
|| getCurrentProgressStep() ==
UninstallProgressStep.FINISHED_WITH_ERROR
|| getCurrentProgressStep() ==
UninstallProgressStep.FINISHED_WITH_ERROR_ON_REMOTE
|| getCurrentProgressStep() ==
UninstallProgressStep.FINISHED_WITH_ERROR_DELETING;
}
/**
* {@inheritDoc}
*/
public boolean isCancellable() {
return false;
}
/**
* {@inheritDoc}
*/
public void cancel() {
// do nothing; not cancellable
}
/**
* {@inheritDoc}
*/
public void windowClosing(QuickSetupDialog dlg, WindowEvent evt) {
if ((dlg.getDisplayedStep() == PROGRESS) ||
(dlg.getDisplayedStep() == FINISHED)) {
// Simulate a close button event
dlg.notifyButtonEvent(ButtonName.CLOSE);
} else {
// Simulate a quit button event
dlg.notifyButtonEvent(ButtonName.QUIT);
}
}
/**
* {@inheritDoc}
*/
public ButtonName getInitialFocusButtonName() {
return ButtonName.FINISH;
}
/**
* {@inheritDoc}
*/
public Set<? extends WizardStep> getWizardSteps() {
Set<WizardStep> setSteps = new HashSet<WizardStep>();
setSteps.add(Step.CONFIRM_UNINSTALL);
setSteps.add(Step.PROGRESS);
setSteps.add(Step.FINISHED);
return Collections.unmodifiableSet(setSteps);
}
/**
* {@inheritDoc}
*/
public QuickSetupStepPanel createWizardStepPanel(WizardStep step) {
QuickSetupStepPanel p = null;
if (step == Step.CONFIRM_UNINSTALL) {
p = new ConfirmUninstallPanel(this, installStatus);
} else if (step == Step.PROGRESS) {
p = new ProgressPanel(this);
} else if (step == Step.FINISHED) {
p = new FinishedPanel(this);
}
return p;
}
/**
* Deletes the external database files specified in the provided Set.
*
* @param dbFiles the database directories to be deleted.
* @throws ApplicationException if something goes wrong.
*/
private void deleteExternalDatabaseFiles(Set<String> dbFiles)
throws ApplicationException {
if (isVerbose())
{
notifyListeners(getFormattedProgressWithLineBreak(
INFO_PROGRESS_DELETING_EXTERNAL_DB_FILES.get()));
}
else
{
notifyListeners(getFormattedWithPoints(
INFO_PROGRESS_DELETING_EXTERNAL_DB_FILES_NON_VERBOSE.get()));
}
for (String path : dbFiles) {
deleteRecursively(new File(path));
}
if (!isVerbose())
{
notifyListeners(getFormattedDoneWithLineBreak());
}
}
/**
* Deletes the external database files specified in the provided Set.
*
* @param logFiles the log files to be deleted.
* @throws ApplicationException if something goes wrong.
*/
private void deleteExternalLogFiles(Set<String> logFiles)
throws ApplicationException {
if (isVerbose())
{
notifyListeners(getFormattedProgressWithLineBreak(
INFO_PROGRESS_DELETING_EXTERNAL_LOG_FILES.get()));
}
else
{
notifyListeners(getFormattedWithPoints(
INFO_PROGRESS_DELETING_EXTERNAL_LOG_FILES_NON_VERBOSE.get()));
}
for (String path : logFiles) {
deleteRecursively(new File(path));
}
if (!isVerbose())
{
notifyListeners(getFormattedDoneWithLineBreak());
}
}
/**
* Deletes the files under the installation path.
*
* @throws ApplicationException if something goes wrong.
*/
private void deleteInstallationFiles(int minRatio, int maxRatio)
throws ApplicationException {
if (isVerbose())
{
notifyListeners(getFormattedProgressWithLineBreak(
INFO_PROGRESS_DELETING_INSTALLATION_FILES.get()));
}
else
{
notifyListeners(getFormattedWithPoints(
INFO_PROGRESS_DELETING_INSTALLATION_FILES_NON_VERBOSE.get()));
}
String installPath = getInstallPathFromClasspath();
File installFile = new File(installPath);
try
{
installPath = installFile.getCanonicalPath();
}
catch(Exception e)
{
installPath = getInstallPathFromClasspath();
}
String instancePath =
Utils.getInstancePathFromInstallPath(installFile.getAbsolutePath());
File instanceFile = new File(instancePath);
try
{
instancePath = instanceFile.getCanonicalPath();
} catch (Exception e)
{
instancePath =
Utils.getInstancePathFromInstallPath(installFile.getAbsolutePath());
}
InstallationFilesToDeleteFilter filter =
new InstallationFilesToDeleteFilter();
File[] installFiles = installFile.listFiles();
File[] instanceFiles = null ;
if (! installPath.equals(instancePath))
{
instanceFiles = new File(instancePath).listFiles();
}
File[] rootFiles = null;
if (installFiles == null)
{
rootFiles = new File(instancePath).listFiles();
}
else
if (instanceFiles == null)
{
rootFiles = installFiles;
}
else
{
// both installFiles and instanceFiles are not null
rootFiles = new File[installFiles.length + instanceFiles.length];
System.arraycopy(installFiles, 0, rootFiles, 0, installFiles.length);
System.arraycopy(instanceFiles, 0, rootFiles, installFiles.length,
instanceFiles.length);
}
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++) {
File f = rootFiles[i];
if (filter.accept(f)) {
Installation installation = getInstallation();
int relativeRatio;
if (equalsOrDescendant(rootFiles[i],
installation.getLibrariesDirectory())) {
relativeRatio = 10;
} else
if (equalsOrDescendant(rootFiles[i],
installation.getBinariesDirectory())) {
relativeRatio = 5;
} else
if (equalsOrDescendant(rootFiles[i],
installation.getConfigurationDirectory())) {
relativeRatio = 5;
} else
if (equalsOrDescendant(rootFiles[i],
installation.getBackupDirectory())) {
relativeRatio = 20;
} else
if (equalsOrDescendant(rootFiles[i],
installation.getLdifDirectory())) {
relativeRatio = 20;
} else if (equalsOrDescendant(rootFiles[i],
installation.getDatabasesDirectory())) {
relativeRatio = 50;
} else
if (equalsOrDescendant(rootFiles[i],
installation.getLogsDirectory())) {
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);
}
if (!isVerbose())
{
notifyListeners(getFormattedDone());
}
}
/**
* Deletes everything below the specified file.
*
* @param file the path to be deleted.
* @throws ApplicationException if something goes wrong.
*/
private void deleteRecursively(File file) throws ApplicationException {
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 ApplicationException if something goes wrong.
*/
private void deleteRecursively(File file, FileFilter filter)
throws ApplicationException {
File cfile ;
try
{
cfile = file.getCanonicalFile();
}
catch (Exception e)
{
cfile = file ;
}
if (cfile.exists()) {
if (cfile.isFile()) {
if (filter != null) {
if (filter.accept(cfile)) {
delete(cfile);
}
} else {
delete(cfile);
}
} else {
File[] children = cfile.listFiles();
if (children != null) {
for (int i = 0; i < children.length; i++) {
deleteRecursively(children[i], filter);
}
}
if (filter != null) {
if (filter.accept(cfile)) {
delete(cfile);
}
} else {
delete(cfile);
}
}
} else {
// Just tell that the file/directory does not exist.
notifyListeners(getFormattedWarning(
INFO_PROGRESS_DELETING_FILE_DOES_NOT_EXIST.get(cfile.toString())));
}
}
/**
* Deletes the specified file.
*
* @param file the file to be deleted.
* @throws ApplicationException if something goes wrong.
*/
private void delete(File file) throws ApplicationException {
boolean isFile = file.isFile();
if (isVerbose())
{
if (isFile) {
notifyListeners(getFormattedWithPoints(
INFO_PROGRESS_DELETING_FILE.get(file.getAbsolutePath())));
} else {
notifyListeners(getFormattedWithPoints(
INFO_PROGRESS_DELETING_DIRECTORY.get(file.getAbsolutePath())));
}
}
boolean delete = false;
/*
* Sometimes the server keeps some locks on the files.
* This is dependent on the OS so there is no much we can do here.
*/
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) {
Message errMsg;
if (isFile) {
errMsg = INFO_ERROR_DELETING_FILE.get(file.getAbsolutePath());
} else {
errMsg = INFO_ERROR_DELETING_DIRECTORY.get(file.getAbsolutePath());
}
throw new ApplicationException(
ReturnCode.FILE_SYSTEM_ACCESS_ERROR,
errMsg, null);
}
if (isVerbose())
{
notifyListeners(getFormattedDoneWithLineBreak());
}
}
private boolean equalsOrDescendant(File file, File directory) {
return file.equals(directory) || isDescendant(file, directory);
}
/**
* 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 {
Installation installation = getInstallation();
File quicksetupFile = installation.getQuicksetupJarFile();
File openDSFile = installation.getOpenDSJarFile();
File librariesFile = installation.getLibrariesDirectory();
File resourcesDir = installation.getResourcesDirectory();
File classesDir = installation.getClassesDirectory();
File uninstallBatFile = installation.getUninstallBatFile();
boolean canDeleteResourcesDir =
!Utils.directoryExistsAndIsNotEmpty(resourcesDir.getAbsolutePath());
boolean canDeleteClassesDir =
!Utils.directoryExistsAndIsNotEmpty(classesDir.getAbsolutePath());
File installationPath = installation.getRootDirectory();
/**
* {@inheritDoc}
*/
public boolean accept(File file) {
UninstallUserData userData = getUninstallUserData();
boolean[] uData = {
userData.getRemoveLibrariesAndTools(),
userData.getRemoveLibrariesAndTools(),
userData.getRemoveLibrariesAndTools(),
userData.getRemoveLibrariesAndTools(),
userData.getRemoveDatabases(),
userData.getRemoveLogs(),
userData.getRemoveConfigurationAndSchema(),
userData.getRemoveBackups(),
userData.getRemoveLDIFs()
};
Installation installation = getInstallation();
File[] parentFiles ;
try {
File[] tmp = {
installation.getLibrariesDirectory().getCanonicalFile(),
installation.getBinariesDirectory().getCanonicalFile(),
installation.getResourcesDirectory().getCanonicalFile(),
installation.getClassesDirectory().getCanonicalFile(),
installation.getDatabasesDirectory().getCanonicalFile(),
installation.getLogsDirectory().getCanonicalFile(),
installation.getConfigurationDirectory().getCanonicalFile(),
installation.getBackupDirectory().getCanonicalFile(),
installation.getLdifDirectory().getCanonicalFile()
};
parentFiles = tmp ;
}
catch (Exception e)
{
return true;
}
boolean accept =
!installationPath.equals(file)
&& !equalsOrDescendant(file, librariesFile)
&& (canDeleteClassesDir || !equalsOrDescendant(file, classesDir))
&& (canDeleteResourcesDir || !equalsOrDescendant(file, resourcesDir))
&& !quicksetupFile.equals(file)
&& !openDSFile.equals(file);
if (accept && isWindows() && isCli()) {
accept = !uninstallBatFile.equals(file);
}
for (int i = 0; i < uData.length && accept; i++) {
File parent = parentFiles[i];
accept &= uData[i] ||
!equalsOrDescendant(file, parent);
}
LOG.log(Level.INFO, "accept for :"+file+" is: "+accept);
return accept;
}
}
private boolean isWindowsServiceEnabled() {
if (isWindowsServiceEnabled == null) {
if (ConfigureWindowsService.serviceState(null, null) ==
ConfigureWindowsService.SERVICE_STATE_ENABLED) {
isWindowsServiceEnabled = Boolean.TRUE;
} else {
isWindowsServiceEnabled = Boolean.FALSE;
}
}
return isWindowsServiceEnabled.booleanValue();
}
/**
* {@inheritDoc}
*/
public ApplicationTrustManager getTrustManager()
{
return getUninstallUserData().getTrustManager();
}
/**
* This methods disables this server as a Windows service.
*
* @throws ApplicationException if something goes wrong.
*/
protected void disableWindowsService() throws ApplicationException {
notifyListeners(getFormattedWithPoints(
INFO_PROGRESS_DISABLING_WINDOWS_SERVICE.get()));
int code = ConfigureWindowsService.disableService(System.out, System.err);
Message errorMessage = INFO_ERROR_DISABLING_WINDOWS_SERVICE.get(
getInstallationPath());
switch (code) {
case ConfigureWindowsService.SERVICE_DISABLE_SUCCESS:
break;
case ConfigureWindowsService.SERVICE_ALREADY_DISABLED:
break;
default:
throw new ApplicationException(
ReturnCode.WINDOWS_SERVICE_ERROR,
errorMessage, null);
}
notifyListeners(getLineBreak());
}
private UninstallUserData getUninstallUserData() {
return (UninstallUserData) getUserData();
}
/**
* Tries to start the server and launches a progress dialog. This method
* assumes that is being called from the event thread.
* @return <CODE>true</CODE> if the server could be started and <CODE>
* false</CODE> otherwise.
* @param frame the JFrame to be used as parent of the progress dialog.
*/
private boolean startServer(JFrame frame)
{
startProgressDetails = new MessageBuilder();
startProgressDlg = new ProgressDialog(frame);
startProgressDlg.setSummary(
getFormattedSummary(INFO_SUMMARY_STARTING.get()));
startProgressDlg.setDetails(Message.EMPTY);
startProgressDlg.setCloseButtonEnabled(false);
final Boolean[] returnValue = new Boolean[] {Boolean.FALSE};
Thread t = new Thread(new Runnable()
{
public void run()
{
try
{
new ServerController(Uninstaller.this).startServer();
final boolean isServerRunning =
Installation.getLocal().getStatus().isServerRunning();
returnValue[0] = isServerRunning;
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
if (isServerRunning)
{
startProgressDlg.setSummary(getFormattedSuccess(
INFO_SUMMARY_START_SUCCESS.get()));
}
else
{
startProgressDlg.setSummary(getFormattedError(
INFO_SUMMARY_START_ERROR.get()));
}
startProgressDlg.setCloseButtonEnabled(true);
}
});
}
catch (Throwable t)
{
Message msg = getFormattedError(t, true);
notifyListeners(msg);
}
}
});
t.start();
startProgressDlg.pack();
Utilities.centerOnComponent(startProgressDlg, frame);
startProgressDlg.setModal(true);
startProgressDlg.setVisible(true);
startProgressDlg = null;
return returnValue[0];
}
/**
* This method displays a login dialog message, asking the user to provide
* authentication to retrieve information from the ADS and update the
* remote servers. Then it tries to connect to the remote servers.
*
* @param qs the QuickSetup object.
*/
private void askForAuthenticationAndLaunch(final QuickSetup qs)
{
if (loginDialog == null)
{
loginDialog = new LoginDialog(qs.getDialog().getFrame(),
getTrustManager(), getConnectTimeout());
loginDialog.pack();
}
Utilities.centerOnComponent(loginDialog, qs.getDialog().getFrame());
loginDialog.setModal(true);
loginDialog.setVisible(true);
if (!loginDialog.isCanceled())
{
getUninstallUserData().setAdminUID(loginDialog.getAdministratorUid());
getUninstallUserData().setAdminPwd(loginDialog.getAdministratorPwd());
final InitialLdapContext ctx = loginDialog.getContext();
try
{
getUninstallUserData().setLocalServerUrl(
(String)ctx.getEnvironment().get(Context.PROVIDER_URL));
}
catch (NamingException ne)
{
LOG.log(Level.WARNING, "Could not find local server: "+ne, ne);
getUninstallUserData().setLocalServerUrl("ldap://localhost:389");
}
getUninstallUserData().setReplicationServer(
loginDialog.getHostName() + ":" +
conf.getReplicationServerPort());
getUninstallUserData().setReferencedHostName(loginDialog.getHostName());
BackgroundTask<TopologyCache> worker = new BackgroundTask<TopologyCache>()
{
public TopologyCache processBackgroundTask() throws Throwable
{
LOG.log(Level.INFO, "Loading Topology Cache in askForAuthentication");
ADSContext adsContext = new ADSContext(ctx);
TopologyCache cache = new TopologyCache(adsContext,
getTrustManager(), getConnectTimeout());
cache.getFilter().setSearchMonitoringInformation(false);
cache.reloadTopology();
return cache;
}
public void backgroundTaskCompleted(TopologyCache returnValue,
Throwable throwable) {
qs.getDialog().workerFinished();
if (throwable != null)
{
LOG.log(Level.WARNING, "Throwable: "+throwable, throwable);
if (throwable instanceof TopologyCacheException)
{
qs.displayError(
getMessage(
(TopologyCacheException)throwable),
INFO_ERROR_TITLE.get());
}
else
{
qs.displayError(
getThrowableMsg(INFO_BUG_MSG.get(), throwable),
INFO_ERROR_TITLE.get());
}
LOG.log(Level.INFO, "Error was displayed");
}
else
{
TopologyCache cache = returnValue;
handleTopologyCache(qs, cache);
}
}
};
qs.getDialog().workerStarted();
worker.startBackgroundTask();
}
else
{
if (qs.displayConfirmation(
INFO_CONFIRM_UNINSTALL_SERVER_RUNNING_MSG.get(),
INFO_CONFIRM_UNINSTALL_SERVER_RUNNING_TITLE.get()))
{
getUserData().setStopServer(true);
qs.launch();
qs.setCurrentStep(getNextWizardStep(Step.CONFIRM_UNINSTALL));
} else {
getUserData().setStopServer(false);
}
}
}
/**
* Method that interacts with the user depending on what errors where
* encountered in the TopologyCache object. This method assumes that the
* TopologyCache has been reloaded.
* Note: this method assumes that is being called from the event thread.
* @param qs the QuickSetup object for the application.
* @param cache the TopologyCache.
*/
private void handleTopologyCache(QuickSetup qs, TopologyCache cache)
{
LOG.log(Level.INFO, "Handling TopologyCache");
boolean stopProcessing = false;
Set<TopologyCacheException> exceptions =
new HashSet<TopologyCacheException>();
/* Analyze if we had any exception while loading servers. For the moment
* only throw the exception found if the user did not provide the
* Administrator DN and this caused a problem authenticating in one server
* or if there is a certificate problem.
*/
Set<ServerDescriptor> servers = cache.getServers();
for (ServerDescriptor server : servers)
{
TopologyCacheException e = server.getLastException();
if (e != null)
{
exceptions.add(e);
}
}
Set<Message> exceptionMsgs = new LinkedHashSet<Message>();
/* Check the exceptions and see if we throw them or not. */
for (TopologyCacheException e : exceptions)
{
LOG.log(Level.INFO, "Analyzing exception: "+e, e);
if (stopProcessing)
{
break;
}
switch (e.getType())
{
case NOT_GLOBAL_ADMINISTRATOR:
Message errorMsg = INFO_NOT_GLOBAL_ADMINISTRATOR_PROVIDED.get();
qs.displayError(errorMsg, INFO_ERROR_TITLE.get());
stopProcessing = true;
break;
case GENERIC_CREATING_CONNECTION:
if ((e.getCause() != null) &&
isCertificateException(e.getCause()))
{
UserDataCertificateException.Type excType;
ApplicationTrustManager.Cause cause = null;
if (e.getTrustManager() != null)
{
cause = e.getTrustManager().getLastRefusedCause();
}
LOG.log(Level.INFO, "Certificate exception cause: "+cause);
if (cause == ApplicationTrustManager.Cause.NOT_TRUSTED)
{
excType = UserDataCertificateException.Type.NOT_TRUSTED;
}
else if (cause == ApplicationTrustManager.Cause.HOST_NAME_MISMATCH)
{
excType = UserDataCertificateException.Type.HOST_NAME_MISMATCH;
}
else
{
excType = null;
}
if (excType != null)
{
String h;
int p;
try
{
URI uri = new URI(e.getLdapUrl());
h = uri.getHost();
p = uri.getPort();
}
catch (Throwable t)
{
LOG.log(Level.WARNING,
"Error parsing ldap url of TopologyCacheException.", t);
h = INFO_NOT_AVAILABLE_LABEL.get().toString();
p = -1;
}
UserDataCertificateException exc =
new UserDataCertificateException(Step.REPLICATION_OPTIONS,
INFO_CERTIFICATE_EXCEPTION.get(h, String.valueOf(p)),
e.getCause(), h, p,
e.getTrustManager().getLastRefusedChain(),
e.getTrustManager().getLastRefusedAuthType(), excType);
handleCertificateException(qs, exc, cache);
stopProcessing = true;
}
}
}
exceptionMsgs.add(getMessage(e));
}
if (!stopProcessing && (exceptionMsgs.size() > 0))
{
Message confirmationMsg =
ERR_UNINSTALL_READING_REGISTERED_SERVERS_CONFIRM_UPDATE_REMOTE.get(
getMessageFromCollection(exceptionMsgs, "\n").toString());
stopProcessing = !qs.displayConfirmation(confirmationMsg,
INFO_CONFIRMATION_TITLE.get());
}
if (!stopProcessing)
{
stopProcessing = !qs.displayConfirmation(
INFO_CONFIRM_UNINSTALL_SERVER_RUNNING_MSG.get(),
INFO_CONFIRM_UNINSTALL_SERVER_RUNNING_TITLE.get());
}
if (!stopProcessing)
{
// Launch everything
getUninstallUserData().setUpdateRemoteReplication(true);
getUninstallUserData().setRemoteServers(cache.getServers());
getUserData().setStopServer(true);
qs.launch();
qs.setCurrentStep(getNextWizardStep(Step.CONFIRM_UNINSTALL));
}
}
/**
* Displays a dialog asking the user to accept a certificate if the user
* accepts it, we update the trust manager and call again to the method that
* handles the action of clicking on "Finish".
* This method assumes that we are being called from the event thread.
*/
private void handleCertificateException(final QuickSetup qs,
UserDataCertificateException ce, final TopologyCache cache)
{
CertificateDialog dlg =
new CertificateDialog(qs.getDialog().getFrame(), ce);
dlg.pack();
dlg.setVisible(true);
if (dlg.getUserAnswer() != CertificateDialog.ReturnType.NOT_ACCEPTED)
{
X509Certificate[] chain = ce.getChain();
String authType = ce.getAuthType();
String host = ce.getHost();
if ((chain != null) && (authType != null) && (host != null))
{
LOG.log(Level.INFO, "Accepting certificate presented by host "+host);
getTrustManager().acceptCertificate(chain, authType, host);
BackgroundTask<TopologyCache> worker =
new BackgroundTask<TopologyCache>()
{
public TopologyCache processBackgroundTask() throws Throwable
{
LOG.log(Level.INFO, "Reloading topology");
cache.getFilter().setSearchMonitoringInformation(false);
cache.reloadTopology();
return cache;
}
public void backgroundTaskCompleted(TopologyCache returnValue,
Throwable throwable) {
qs.getDialog().workerFinished();
if (throwable != null)
{
if (throwable instanceof TopologyCacheException)
{
qs.displayError(getMessage((TopologyCacheException)throwable),
INFO_ERROR_TITLE.get());
}
else
{
qs.displayError(
getThrowableMsg(INFO_BUG_MSG.get(), throwable),
INFO_ERROR_TITLE.get());
}
}
else
{
handleTopologyCache(qs, cache);
}
}
};
qs.getDialog().workerStarted();
worker.startBackgroundTask();
}
else
{
if (chain == null)
{
LOG.log(Level.WARNING,
"The chain is null for the UserDataCertificateException");
}
if (authType == null)
{
LOG.log(Level.WARNING,
"The auth type is null for the UserDataCertificateException");
}
if (host == null)
{
LOG.log(Level.WARNING,
"The host is null for the UserDataCertificateException");
}
}
}
if (dlg.getUserAnswer() ==
CertificateDialog.ReturnType.ACCEPTED_PERMANENTLY)
{
X509Certificate[] chain = ce.getChain();
if (chain != null)
{
try
{
UIKeyStore.acceptCertificate(chain);
}
catch (Throwable t)
{
LOG.log(Level.WARNING, "Error accepting certificate: "+t, t);
}
}
}
}
/**
* This method updates the replication in the remote servers. It does
* throw ApplicationException if we are working on the force on error mode.
* It also tries to delete the server registration entry from the remote ADS
* servers.
* @throws ApplicationException if we are not working on force on error mode
* and there is an error.
*/
private void removeRemoteServerReferences() throws ApplicationException
{
Set<ServerDescriptor> servers = getUninstallUserData().getRemoteServers();
Map<ADSContext.ServerProperty, Object> serverADSProperties = null;
for (ServerDescriptor server : servers)
{
if (isServerToUninstall(server))
{
serverADSProperties = server.getAdsProperties();
break;
}
}
if (serverADSProperties == null)
{
LOG.log(Level.WARNING, "The server ADS properties for the server to "+
"uninstall could not be found.");
}
for (ServerDescriptor server : servers)
{
if (server.getAdsProperties() != serverADSProperties)
{
removeReferences(server, serverADSProperties);
}
}
}
/**
* This method updates the replication in the remote server represented by
* a given ServerProperty object.
* It also tries to delete the server registration entry from the remote ADS
* servers if the serverADSProperties object passed is not null.
* @param server the ServerDescriptor object representing the server where
* we want to remove references to the server that we are trying to uninstall.
* @param serverADSProperties the Map with the ADS properties of the server
* that we are trying to uninstall.
* @throws ApplicationException if we are not working on force on error mode
* and there is an error.
*/
private void removeReferences(ServerDescriptor server,
Map<ADSContext.ServerProperty, Object> serverADSProperties)
throws ApplicationException
{
/* First check if the server must be updated based in the contents of the
* ServerDescriptor object. */
boolean hasReferences = false;
Object v = server.getServerProperties().get(
ServerDescriptor.ServerProperty.IS_REPLICATION_SERVER);
if (Boolean.TRUE.equals(v))
{
Set<?> replicationServers = (Set<?>)server.getServerProperties().get(
ServerDescriptor.ServerProperty.EXTERNAL_REPLICATION_SERVERS);
if (replicationServers != null)
{
for (Object o : replicationServers)
{
if (getUninstallUserData().getReplicationServer().equalsIgnoreCase(
(String)o))
{
hasReferences = true;
break;
}
}
}
}
if (!hasReferences)
{
for (ReplicaDescriptor replica : server.getReplicas())
{
if (replica.isReplicated())
{
for (Object o : replica.getReplicationServers())
{
if (getUninstallUserData().getReplicationServer().equalsIgnoreCase(
(String)o))
{
hasReferences = true;
break;
}
}
}
if (hasReferences)
{
break;
}
}
}
if (!hasReferences)
{
LOG.log(Level.INFO, "No references in: "+ server.getHostPort(true));
}
if (hasReferences)
{
LOG.log(Level.INFO, "Updating references in: "+ server.getHostPort(true));
notifyListeners(getFormattedWithPoints(
INFO_PROGRESS_REMOVING_REFERENCES.get(server.getHostPort(true))));
InitialLdapContext ctx = null;
try
{
String dn = ADSContext.getAdministratorDN(
getUninstallUserData().getAdminUID());
String pwd = getUninstallUserData().getAdminPwd();
ctx = getRemoteConnection(server, dn, pwd, getTrustManager(),
getConnectTimeout(),
new LinkedHashSet<PreferredConnection>());
// Update replication servers and domains. If the domain
// is an ADS, then remove it from there.
removeReferences(ctx, server.getHostPort(true), serverADSProperties);
notifyListeners(getFormattedDoneWithLineBreak());
}
catch (ApplicationException ae)
{
errorOnRemoteOccurred = true;
LOG.log(Level.INFO, "Error updating replication references in: "+
server.getHostPort(true), ae);
if (!getUninstallUserData().isForceOnError())
{
Message msg =
ERR_UNINSTALL_ERROR_UPDATING_REMOTE_NO_FORCE.get(
"--"+
parser.getSecureArgsList().adminUidArg.getLongIdentifier(),
"--"+ToolConstants.OPTION_LONG_BINDPWD,
"--"+ToolConstants.OPTION_LONG_BINDPWD_FILE,
"--"+parser.forceOnErrorArg.getLongIdentifier(),
ae.getMessageObject().toString());
throw new ApplicationException(ae.getType(), msg, ae);
}
else
{
Message html = getFormattedError(ae, true);
notifyListeners(html);
}
}
finally
{
if (ctx != null)
{
try
{
ctx.close();
}
catch (Throwable t)
{
}
}
}
}
}
/**
* This method updates the replication in the remote server using the
* provided InitialLdapContext.
* It also tries to delete the server registration entry from the remote ADS
* servers if the serverADSProperties object passed is not null.
* @param ctx the connection to the remote server where we want to remove
* references to the server that we are trying to uninstall.
* @param serverDisplay an String representation that is used to identify
* the remote server in the log messages we present to the user.
* @param serverADSProperties the Map with the ADS properties of the server
* that we are trying to uninstall.
* @throws ApplicationException if an error occurs while updating the remote
* OpenDS server configuration.
*/
private void removeReferences(InitialLdapContext ctx, String serverDisplay,
Map<ADSContext.ServerProperty, Object> serverADSProperties)
throws ApplicationException
{
try
{
ManagementContext mCtx = LDAPManagementContext.createFromContext(
JNDIDirContextAdaptor.adapt(ctx));
RootCfgClient root = mCtx.getRootConfiguration();
ReplicationSynchronizationProviderCfgClient sync =
(ReplicationSynchronizationProviderCfgClient)
root.getSynchronizationProvider("Multimaster Synchronization");
if (sync.hasReplicationServer())
{
ReplicationServerCfgClient replicationServer =
sync.getReplicationServer();
Set<String> replServers = replicationServer.getReplicationServer();
if (replServers != null)
{
String replServer = null;
for (String o : replServers)
{
if (getUninstallUserData().getReplicationServer().equalsIgnoreCase(
o))
{
replServer = o;
break;
}
}
if (replServer != null)
{
LOG.log(Level.INFO, "Updating references in replication server on "+
serverDisplay+".");
replServers.remove(replServer);
if (replServers.size() > 0)
{
replicationServer.setReplicationServer(replServers);
replicationServer.commit();
}
else
{
sync.removeReplicationServer();
sync.commit();
}
}
}
}
String[] domainNames = sync.listReplicationDomains();
if (domainNames != null)
{
for (int i=0; i<domainNames.length; i++)
{
ReplicationDomainCfgClient domain =
sync.getReplicationDomain(domainNames[i]);
Set<String> replServers = domain.getReplicationServer();
if (replServers != null)
{
String replServer = null;
for (String o : replServers)
{
if (getUninstallUserData().getReplicationServer().
equalsIgnoreCase(o))
{
replServer = o;
break;
}
}
if (replServer != null)
{
LOG.log(Level.INFO, "Updating references in domain " +
domain.getBaseDN()+" on " + serverDisplay + ".");
replServers.remove(replServer);
if (replServers.size() > 0)
{
domain.setReplicationServer(replServers);
domain.commit();
}
else
{
sync.removeReplicationDomain(domainNames[i]);
sync.commit();
}
}
}
}
}
}
catch (ManagedObjectNotFoundException monfe)
{
// It does not exist.
LOG.log(Level.INFO, "No synchronization found on "+ serverDisplay+".",
monfe);
}
catch (Throwable t)
{
LOG.log(Level.WARNING,
"Error removing references in replication server on "+
serverDisplay+": "+t, t);
Message errorMessage = INFO_ERROR_CONFIGURING_REMOTE_GENERIC.get(
serverDisplay, t.toString());
throw new ApplicationException(
ReturnCode.CONFIGURATION_ERROR, errorMessage,
t);
}
ADSContext adsContext = new ADSContext(ctx);
try
{
if (adsContext.hasAdminData() && (serverADSProperties != null))
{
LOG.log(Level.INFO, "Unregistering server on ADS of server "+
ConnectionUtils.getHostPort(ctx)+". Properties: "+
serverADSProperties);
adsContext.unregisterServer(serverADSProperties);
}
}
catch (ADSContextException ace)
{
if (ace.getError() !=
ADSContextException.ErrorType.NOT_YET_REGISTERED)
{
throw new ApplicationException(
ReturnCode.CONFIGURATION_ERROR,
INFO_REMOTE_ADS_EXCEPTION.get(
serverDisplay, ace.toString()), ace);
}
else
{
// Nothing to do: this may occur if the new server has been
// unregistered on another server and the modification has
// been already propagated by replication.
}
}
}
/**
* Tells whether this ServerDescriptor object represents the server that we
* are trying to uninstall or not.
* @param server the ServerDescriptor object to analyze.
* @return <CODE>true</CODE> if the ServerDescriptor object represents the
* server that we are trying to uninstall and <CODE>false</CODE> otherwise.
*/
private boolean isServerToUninstall(ServerDescriptor server)
{
boolean isServerToUninstall = false;
String path = (String)server.getAdsProperties().get(
ADSContext.ServerProperty.INSTANCE_PATH);
if (path == null)
{
// Compare the port of the URL we used.
try
{
String usedUrl = getUninstallUserData().getLocalServerUrl();
boolean isSecure = usedUrl.toLowerCase().startsWith("ldaps");
URI uri = new URI(usedUrl);
int port = uri.getPort();
ServerDescriptor.ServerProperty property;
if (isSecure)
{
property = ServerDescriptor.ServerProperty.ADMIN_PORT;
}
else
{
property = ServerDescriptor.ServerProperty.LDAP_PORT;
}
ArrayList<?> ports =
(ArrayList<?>)server.getServerProperties().get(property);
if (ports != null)
{
isServerToUninstall = ports.contains(port);
}
else
{
// This occurs if the instance could not be loaded.
ADSContext.ServerProperty adsProperty;
if (isSecure)
{
adsProperty = ADSContext.ServerProperty.ADMIN_PORT;
}
else
{
adsProperty = ADSContext.ServerProperty.LDAP_PORT;
}
String v = (String)server.getAdsProperties().get(adsProperty);
if (v != null)
{
isServerToUninstall = v.equals(String.valueOf(port));
}
}
}
catch (Throwable t)
{
LOG.log(Level.WARNING, "Failing checking the port: "+t, t);
}
}
else
{
File f = new File(path);
isServerToUninstall =
f.equals(Installation.getLocal().getRootDirectory());
}
if (isServerToUninstall)
{
// TODO: the host name comparison made here does not necessarily work in
// all environments...
String hostName = server.getHostName();
boolean hostNameEquals =
getUninstallUserData().getReferencedHostName().equals(hostName);
try
{
InetAddress localAddress = InetAddress.getLocalHost();
InetAddress[] addresses = InetAddress.getAllByName(hostName);
for (int i=0; i<addresses.length && !hostNameEquals; i++)
{
hostNameEquals = localAddress.equals(addresses[i]);
}
if (!hostNameEquals)
{
hostNameEquals =
localAddress.getHostName().equalsIgnoreCase(hostName) ||
localAddress.getCanonicalHostName().equalsIgnoreCase(hostName);
}
}
catch (Throwable t)
{
LOG.log(Level.WARNING, "Failing checking host names: "+t, t);
}
isServerToUninstall = hostNameEquals;
}
return isServerToUninstall;
}
/**
* Returns the timeout to be used to connect in milliseconds.
* @return the timeout to be used to connect in milliseconds. Returns
* {@code 0} if there is no timeout.
*/
private int getConnectTimeout()
{
return getUserData().getConnectTimeout();
}
}