001/*
002 * The contents of this file are subject to the terms of the Common Development and
003 * Distribution License (the License). You may not use this file except in compliance with the
004 * License.
005 *
006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
007 * specific language governing permission and limitations under the License.
008 *
009 * When distributing Covered Software, include this CDDL Header Notice in each file and include
010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
011 * Header, with the fields enclosed by brackets [] replaced by your own identifying
012 * information: "Portions Copyright [year] [name of copyright owner]".
013 *
014 * Copyright 2006-2010 Sun Microsystems, Inc.
015 * Portions Copyright 2014-2016 ForgeRock AS.
016 */
017package org.opends.guitools.uninstaller;
018
019import java.awt.event.WindowEvent;
020import java.io.File;
021import java.io.FileFilter;
022import java.io.PrintStream;
023import java.net.InetAddress;
024import java.net.URI;
025import java.security.cert.X509Certificate;
026import java.util.ArrayList;
027import java.util.Collections;
028import java.util.HashMap;
029import java.util.HashSet;
030import java.util.Iterator;
031import java.util.LinkedHashSet;
032import java.util.List;
033import java.util.Map;
034import java.util.Set;
035
036import javax.naming.Context;
037import javax.naming.NamingException;
038import javax.swing.JFrame;
039import javax.swing.SwingUtilities;
040
041import org.forgerock.i18n.LocalizableMessage;
042import org.forgerock.i18n.LocalizableMessageBuilder;
043import org.forgerock.i18n.LocalizableMessageDescriptor.Arg0;
044import org.forgerock.i18n.slf4j.LocalizedLogger;
045import org.forgerock.opendj.config.ConfigurationFramework;
046import org.forgerock.opendj.config.ManagedObjectNotFoundException;
047import org.forgerock.opendj.server.config.client.ReplicationDomainCfgClient;
048import org.forgerock.opendj.server.config.client.ReplicationServerCfgClient;
049import org.forgerock.opendj.server.config.client.ReplicationSynchronizationProviderCfgClient;
050import org.forgerock.opendj.server.config.client.RootCfgClient;
051import org.opends.admin.ads.ADSContext;
052import org.opends.admin.ads.ADSContextException;
053import org.opends.admin.ads.ReplicaDescriptor;
054import org.opends.admin.ads.ServerDescriptor;
055import org.opends.admin.ads.ServerDescriptor.ServerProperty;
056import org.opends.admin.ads.TopologyCache;
057import org.opends.admin.ads.TopologyCacheException;
058import org.opends.admin.ads.util.ApplicationTrustManager;
059import org.opends.admin.ads.util.ConnectionWrapper;
060import org.opends.admin.ads.util.PreferredConnection;
061import org.opends.guitools.uninstaller.ui.ConfirmUninstallPanel;
062import org.opends.guitools.uninstaller.ui.LoginDialog;
063import org.opends.quicksetup.ApplicationException;
064import org.opends.quicksetup.ButtonName;
065import org.opends.quicksetup.CliApplication;
066import org.opends.quicksetup.Installation;
067import org.opends.quicksetup.Launcher;
068import org.opends.quicksetup.ProgressStep;
069import org.opends.quicksetup.ReturnCode;
070import org.opends.quicksetup.Step;
071import org.opends.quicksetup.UserData;
072import org.opends.quicksetup.UserDataCertificateException;
073import org.opends.quicksetup.UserDataException;
074import org.opends.quicksetup.WizardStep;
075import org.opends.quicksetup.ui.CertificateDialog;
076import org.opends.quicksetup.ui.FieldName;
077import org.opends.quicksetup.ui.FinishedPanel;
078import org.opends.quicksetup.ui.GuiApplication;
079import org.opends.quicksetup.ui.ProgressDialog;
080import org.opends.quicksetup.ui.ProgressPanel;
081import org.opends.quicksetup.ui.QuickSetup;
082import org.opends.quicksetup.ui.QuickSetupDialog;
083import org.opends.quicksetup.ui.QuickSetupStepPanel;
084import org.opends.quicksetup.ui.Utilities;
085import org.opends.quicksetup.util.BackgroundTask;
086import org.opends.quicksetup.util.ServerController;
087import org.opends.quicksetup.util.UIKeyStore;
088import org.opends.quicksetup.util.Utils;
089import org.opends.server.core.DirectoryServer;
090import org.opends.server.types.HostPort;
091import org.opends.server.util.DynamicConstants;
092
093import com.forgerock.opendj.cli.ClientException;
094
095import static com.forgerock.opendj.cli.ArgumentConstants.*;
096import static com.forgerock.opendj.cli.Utils.*;
097import static com.forgerock.opendj.util.OperatingSystem.*;
098
099import static org.forgerock.util.Utils.*;
100import static org.opends.guitools.uninstaller.UninstallProgressStep.*;
101import static org.opends.messages.AdminToolMessages.*;
102import static org.opends.messages.QuickSetupMessages.*;
103import static org.opends.quicksetup.Step.*;
104import static org.opends.quicksetup.util.Utils.*;
105import static org.opends.server.tools.ConfigureWindowsService.*;
106
107/** This class is in charge of performing the uninstallation of Open DS. */
108public class Uninstaller extends GuiApplication implements CliApplication {
109  private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
110  private UninstallProgressStep status = NOT_STARTED;
111  private boolean displaySeparator;
112  private boolean errorOnRemoteOccurred;
113  private boolean errorDeletingOccurred;
114
115  private UninstallerArgumentParser parser;
116
117  private Map<ProgressStep, Integer> hmRatio = new HashMap<>();
118  private Map<ProgressStep, LocalizableMessage> hmSummary = new HashMap<>();
119
120  private ApplicationException ue;
121  private Boolean isWindowsServiceEnabled;
122  private UninstallCliHelper cliHelper = new UninstallCliHelper();
123
124  private LoginDialog loginDialog;
125  private ProgressDialog startProgressDlg;
126  private LocalizableMessageBuilder startProgressDetails = new LocalizableMessageBuilder();
127  private UninstallData conf;
128
129  /** Default constructor. */
130  public Uninstaller()
131  {
132    super();
133
134    /* Do some initialization required to use the administration framework
135     * classes.  Note that this is not done in the uninstaller code because
136     * when the basic configuration of the server is performed (using
137     * ConfigureDS) this initialization is done.
138     */
139    DirectoryServer.bootstrapClient();
140    //  Bootstrap definition classes.
141    try
142    {
143      ConfigurationFramework configFramework = ConfigurationFramework.getInstance();
144      if (!configFramework.isInitialized())
145      {
146        configFramework.initialize();
147      }
148      configFramework.setIsClient(true);
149    }
150    catch (Throwable t)
151    {
152      logger.warn(LocalizableMessage.raw("Error enabling admin framework class loader: "+t, t));
153    }
154    logger.info(LocalizableMessage.raw("Uninstaller is created."));
155  }
156
157  @Override
158  public LocalizableMessage getFrameTitle() {
159    LocalizableMessage defaultVal = INFO_FRAME_UNINSTALL_TITLE.get(DynamicConstants.PRODUCT_NAME);
160    return Utils.getCustomizedObject("INFO_FRAME_UNINSTALL_TITLE", defaultVal, LocalizableMessage.class);
161  }
162
163  @Override
164  public UserData createUserData() {
165    UninstallUserData data = new UninstallUserData();
166    data.setTrustManager(super.getTrustManager());
167    return data;
168  }
169
170  @Override
171  public WizardStep getFirstWizardStep() {
172    return Step.CONFIRM_UNINSTALL;
173  }
174
175  @Override
176  public WizardStep getNextWizardStep(WizardStep step) {
177    Step nextStep = null;
178    if (step != null && step.equals(Step.CONFIRM_UNINSTALL)) {
179      nextStep = Step.PROGRESS;
180    }
181    else if (Step.PROGRESS.equals(step))
182    {
183      nextStep = Step.FINISHED;
184    }
185    return nextStep;
186  }
187
188  @Override
189  public WizardStep getPreviousWizardStep(WizardStep step) {
190    Step prevStep = null;
191    if (step != null && step.equals(Step.PROGRESS)) {
192      prevStep = Step.CONFIRM_UNINSTALL;
193    }
194    else if (Step.FINISHED.equals(step))
195    {
196      prevStep = Step.PROGRESS;
197    }
198    return prevStep;
199  }
200
201  @Override
202  public WizardStep getFinishedStep() {
203    return Step.FINISHED;
204  }
205
206  @Override
207  public boolean finishOnLeft()
208  {
209    return false;
210  }
211
212  @Override
213  public boolean canGoBack(WizardStep step) {
214    return false;
215  }
216
217  @Override
218  public boolean canGoForward(WizardStep step) {
219    return false;
220  }
221
222  @Override
223  public boolean canFinish(WizardStep step) {
224    return step == Step.CONFIRM_UNINSTALL;
225  }
226
227  /**
228   * Whether the provided wizard step allow to quit.
229   *
230   * @param step the wizard step
231   * @return true if the provided wizard step allow to quit, false otherwise
232   */
233  public boolean canQuit(WizardStep step) {
234    return step == Step.CONFIRM_UNINSTALL;
235  }
236
237  @Override
238  public void nextClicked(WizardStep cStep, QuickSetup qs) {
239    if (cStep == PROGRESS) {
240      throw new IllegalStateException("Cannot click on next from progress step");
241    } else if (cStep == REVIEW) {
242      throw new IllegalStateException("Cannot click on next from review step");
243    } else if (cStep == FINISHED) {
244      throw new IllegalStateException("Cannot click on next from finished step");
245    }
246  }
247
248  @Override
249  public void closeClicked(WizardStep cStep, QuickSetup qs) {
250    if (cStep == PROGRESS) {
251        if (isFinished()
252            || qs.displayConfirmation(INFO_CONFIRM_CLOSE_UNINSTALL_MSG.get(),
253                INFO_CONFIRM_CLOSE_UNINSTALL_TITLE.get()))
254        {
255          qs.quit();
256        }
257    }
258    else if (cStep == FINISHED)
259    {
260      qs.quit();
261    } else {
262      throw new IllegalStateException(
263          "Close only can be clicked on PROGRESS step");
264    }
265  }
266
267  /** Update the UserData object according to the content of the review panel. */
268  private void updateUserUninstallDataForConfirmUninstallPanel(QuickSetup qs)
269          throws UserDataException {
270    UninstallUserData uud = getUninstallUserData();
271    uud.setRemoveLibrariesAndTools(
272            (Boolean) qs.getFieldValue(FieldName.REMOVE_LIBRARIES_AND_TOOLS));
273    uud.setRemoveDatabases(
274            (Boolean) qs.getFieldValue(FieldName.REMOVE_DATABASES));
275    uud.setRemoveConfigurationAndSchema(
276            (Boolean) qs.getFieldValue(
277                    FieldName.REMOVE_CONFIGURATION_AND_SCHEMA));
278    uud.setRemoveBackups(
279            (Boolean) qs.getFieldValue(FieldName.REMOVE_BACKUPS));
280    uud.setRemoveLDIFs(
281            (Boolean) qs.getFieldValue(FieldName.REMOVE_LDIFS));
282    uud.setRemoveLogs(
283            (Boolean) qs.getFieldValue(FieldName.REMOVE_LOGS));
284    // This is updated on the method handleTopologyCache
285    uud.setUpdateRemoteReplication(false);
286
287    Set<String> dbs = new HashSet<>();
288    Set<?> s = (Set<?>) qs.getFieldValue(FieldName.EXTERNAL_DB_DIRECTORIES);
289    for (Object v : s) {
290      dbs.add((String) v);
291    }
292
293    Set<String> logs = new HashSet<>();
294    s = (Set<?>) qs.getFieldValue(FieldName.EXTERNAL_LOG_FILES);
295    for (Object v : s) {
296      logs.add((String) v);
297    }
298
299    uud.setExternalDbsToRemove(dbs);
300    uud.setExternalLogsToRemove(logs);
301
302    if (dbs.isEmpty() &&
303            logs.isEmpty() &&
304            !uud.getRemoveLibrariesAndTools() &&
305            !uud.getRemoveDatabases() &&
306            !uud.getRemoveConfigurationAndSchema() &&
307            !uud.getRemoveBackups() &&
308            !uud.getRemoveLDIFs() &&
309            !uud.getRemoveLogs()) {
310      throw new UserDataException(Step.CONFIRM_UNINSTALL,
311              INFO_NOTHING_SELECTED_TO_UNINSTALL.get());
312    }
313  }
314
315  @Override
316  public void quitClicked(WizardStep step, QuickSetup qs) {
317    if (step == Step.PROGRESS) {
318      throw new IllegalStateException(
319              "Cannot click on quit from progress step");
320    }
321    else if (step == Step.FINISHED) {
322      throw new IllegalStateException(
323      "Cannot click on quit from finished step");
324    }
325    qs.quit();
326  }
327
328  @Override
329  public LocalizableMessage getCloseButtonToolTip() {
330    return INFO_CLOSE_BUTTON_UNINSTALL_TOOLTIP.get();
331  }
332
333  @Override
334  public LocalizableMessage getFinishButtonToolTip() {
335    return INFO_FINISH_BUTTON_UNINSTALL_TOOLTIP.get();
336  }
337
338  @Override
339  public LocalizableMessage getFinishButtonLabel() {
340    return INFO_FINISH_BUTTON_UNINSTALL_LABEL.get();
341  }
342
343  @Override
344  public void previousClicked(WizardStep cStep, QuickSetup qs) {
345    if (cStep == PROGRESS) {
346      throw new IllegalStateException(
347              "Cannot click on previous from progress step");
348    }
349    else if (cStep == FINISHED) {
350      throw new IllegalStateException(
351        "Cannot click on previous from finished step");
352    }
353  }
354
355  @Override
356  public void notifyListeners(Integer ratio, LocalizableMessage currentPhaseSummary,
357      final LocalizableMessage newLogDetail)
358  {
359    if (status != NOT_STARTED)
360    {
361      super.notifyListeners(ratio, currentPhaseSummary, newLogDetail);
362    }
363    else
364    {
365      SwingUtilities.invokeLater(new Runnable()
366      {
367        @Override
368        public void run()
369        {
370          if (startProgressDlg != null && newLogDetail != null)
371          {
372            startProgressDetails.append(newLogDetail);
373            startProgressDlg.setDetails(startProgressDetails.toMessage());
374          }
375        }
376      });
377    }
378  }
379
380  @Override
381  public boolean finishClicked(final WizardStep cStep, final QuickSetup qs) {
382    if (cStep == Step.CONFIRM_UNINSTALL) {
383      BackgroundTask<UninstallData> worker =
384        new BackgroundTask<UninstallData>() {
385        @Override
386        public UninstallData processBackgroundTask() throws UserDataException {
387          try {
388            updateUserUninstallDataForConfirmUninstallPanel(qs);
389            return new UninstallData(Installation.getLocal());
390          }
391          catch (UserDataException uude) {
392            throw uude;
393          } catch (Throwable t) {
394            logger.warn(LocalizableMessage.raw("Error processing task: "+t, t));
395            throw new UserDataException(Step.CONFIRM_UNINSTALL,
396                    getThrowableMsg(INFO_BUG_MSG.get(), t));
397          }
398        }
399
400        @Override
401        public void backgroundTaskCompleted(UninstallData returnValue,
402                                            Throwable throwable) {
403          qs.getDialog().workerFinished();
404          if (throwable != null) {
405            if (throwable instanceof UserDataException)
406            {
407              qs.displayError(LocalizableMessage.raw(throwable.getLocalizedMessage()),
408                    INFO_ERROR_TITLE.get());
409            }
410            else
411            {
412              logger.warn(LocalizableMessage.raw("Error processing task: "+throwable,
413                  throwable));
414              qs.displayError(LocalizableMessage.raw(throwable.toString()),
415                      INFO_ERROR_TITLE.get());
416            }
417          } else {
418            conf = returnValue;
419            if (conf.isADS() && conf.isReplicationServer())
420            {
421              if (conf.isServerRunning())
422              {
423                if (qs.displayConfirmation(
424                    INFO_CONFIRM_UNINSTALL_REPLICATION_SERVER_RUNNING_MSG.get(),
425                    INFO_CONFIRM_UNINSTALL_REPLICATION_SERVER_RUNNING_TITLE
426                            .get()))
427                {
428                  askForAuthenticationAndLaunch(qs);
429                }
430                else if (qs.displayConfirmation(
431                        INFO_CONFIRM_UNINSTALL_SERVER_RUNNING_MSG.get(),
432                        INFO_CONFIRM_UNINSTALL_SERVER_RUNNING_TITLE.get()))
433                {
434                  getUserData().setStopServer(true);
435                  qs.launch();
436                  qs.setCurrentStep(getNextWizardStep(Step.CONFIRM_UNINSTALL));
437                } else {
438                  getUserData().setStopServer(false);
439                }
440              }
441              else if (qs.displayConfirmation(
442                  INFO_CONFIRM_UNINSTALL_REPLICATION_SERVER_NOT_RUNNING_MSG.get(),
443                  INFO_CONFIRM_UNINSTALL_REPLICATION_SERVER_NOT_RUNNING_TITLE.get()))
444              {
445                boolean startWorked = startServer(qs.getDialog().getFrame());
446                if (startWorked)
447                {
448                  askForAuthenticationAndLaunch(qs);
449                }
450                else
451                {
452                  getUserData().setStopServer(false);
453                  if (qs.displayConfirmation(
454                      INFO_CONFIRM_UNINSTALL_SERVER_NOT_RUNNING_MSG.get(),
455                      INFO_CONFIRM_UNINSTALL_SERVER_NOT_RUNNING_TITLE.get()))
456                  {
457                    qs.launch();
458                    qs.setCurrentStep(
459                        getNextWizardStep(Step.CONFIRM_UNINSTALL));
460                  }
461                }
462              }
463              else
464              {
465                getUserData().setStopServer(false);
466                if (qs.displayConfirmation(
467                    INFO_CONFIRM_UNINSTALL_SERVER_NOT_RUNNING_MSG.get(),
468                    INFO_CONFIRM_UNINSTALL_SERVER_NOT_RUNNING_TITLE.get()))
469                {
470                  qs.launch();
471                  qs.setCurrentStep(
472                      getNextWizardStep(Step.CONFIRM_UNINSTALL));
473                }
474              }
475            }
476            else if (!conf.isServerRunning())
477            {
478              getUserData().setStopServer(false);
479              if (qs.displayConfirmation(
480                      INFO_CONFIRM_UNINSTALL_SERVER_NOT_RUNNING_MSG.get(),
481                      INFO_CONFIRM_UNINSTALL_SERVER_NOT_RUNNING_TITLE.get()))
482              {
483                qs.launch();
484                qs.setCurrentStep(getNextWizardStep(Step.CONFIRM_UNINSTALL));
485              }
486            }
487            else if (qs.displayConfirmation(
488                    INFO_CONFIRM_UNINSTALL_SERVER_RUNNING_MSG.get(),
489                    INFO_CONFIRM_UNINSTALL_SERVER_RUNNING_TITLE.get())) {
490              getUserData().setStopServer(true);
491              qs.launch();
492              qs.setCurrentStep(getNextWizardStep(Step.CONFIRM_UNINSTALL));
493            } else {
494              getUserData().setStopServer(false);
495            }
496          }
497        }
498      };
499      qs.getDialog().workerStarted();
500      worker.startBackgroundTask();
501    }
502    // Uninstaller is responsible for updating user data and launching
503    return false;
504  }
505
506  @Override
507  public void updateUserData(WizardStep step, QuickSetup qs) {
508    // do nothing;
509  }
510
511  @Override
512  public void setWizardDialogState(QuickSetupDialog dlg,
513                                      UserData userData,
514                                      WizardStep step) {
515    if (step == Step.CONFIRM_UNINSTALL) {
516      dlg.setDefaultButton(ButtonName.FINISH);
517      dlg.setFocusOnButton(ButtonName.FINISH);
518    } else if (step == PROGRESS || step == FINISHED) {
519      dlg.setDefaultButton(ButtonName.CLOSE);
520      dlg.setFocusOnButton(ButtonName.CLOSE);
521      dlg.setButtonEnabled(ButtonName.CLOSE, false);
522    }
523  }
524
525  @Override
526  public UserData createUserData(Launcher launcher) throws UserDataException,
527      ApplicationException, ClientException
528  {
529    parser = (UninstallerArgumentParser) launcher.getArgumentParser();
530    return cliHelper.createUserData(parser);
531  }
532
533  @Override
534  public String getInstallationPath() {
535    return getInstallPathFromClasspath();
536  }
537
538  @Override
539  public String getInstancePath() {
540    return getInstancePathFromInstallPath(getInstallPathFromClasspath());
541  }
542
543  /**
544   * Returns the ApplicationException that might occur during installation or
545   * <CODE>null</CODE> if no exception occurred.
546   *
547   * @return the ApplicationException that might occur during installation or
548   *         <CODE>null</CODE> if no exception occurred.
549   */
550  @Override
551  public ApplicationException getRunError() {
552    return ue;
553  }
554
555  @Override
556  public ReturnCode getReturnCode() {
557    return null;
558  }
559
560  /** Initialize the different map used in this class. */
561  private void initMaps() {
562    putSummary(NOT_STARTED, INFO_SUMMARY_UNINSTALL_NOT_STARTED);
563    putSummary(STOPPING_SERVER, INFO_SUMMARY_STOPPING);
564    putSummary(UNCONFIGURING_REPLICATION, INFO_SUMMARY_UNCONFIGURING_REPLICATION);
565    putSummary(DISABLING_WINDOWS_SERVICE, INFO_SUMMARY_DISABLING_WINDOWS_SERVICE);
566    putSummary(DELETING_EXTERNAL_DATABASE_FILES, INFO_SUMMARY_DELETING_EXTERNAL_DB_FILES);
567    putSummary(DELETING_EXTERNAL_LOG_FILES, INFO_SUMMARY_DELETING_EXTERNAL_LOG_FILES);
568    putSummary(REMOVING_EXTERNAL_REFERENCES, INFO_SUMMARY_DELETING_EXTERNAL_REFERENCES);
569    putSummary(DELETING_INSTALLATION_FILES, INFO_SUMMARY_DELETING_INSTALLATION_FILES);
570
571    LocalizableMessage successMsg;
572    Installation installation = getInstallation();
573    String libPath = getPath(installation.getLibrariesDirectory());
574    String resourcesPath = getPath(installation.getResourcesDirectory());
575    String classesPath = getPath(installation.getClassesDirectory());
576    boolean resourcesDefined =
577     Utils.directoryExistsAndIsNotEmpty(resourcesPath);
578    boolean classesDefined =
579      Utils.directoryExistsAndIsNotEmpty(classesPath);
580    ArrayList<String> paths = new ArrayList<>();
581    paths.add(libPath);
582    if (resourcesDefined)
583    {
584      paths.add(resourcesPath);
585    }
586    if (classesDefined)
587    {
588      paths.add(classesPath);
589    }
590    if (isCli()) {
591      if (getUninstallUserData().getRemoveLibrariesAndTools()) {
592        String arg;
593        if (isWindows()) {
594          arg = installation.getUninstallBatFile() + getLineBreak().toString() +
595                  getTab() + joinAsString(getLineBreak().toString(), paths);
596        } else {
597          arg = joinAsString(getLineBreak().toString(), paths);
598        }
599        successMsg = INFO_SUMMARY_UNINSTALL_FINISHED_SUCCESSFULLY_REMOVE_JARFILES_CLI.get(arg);
600      } else {
601        successMsg = INFO_SUMMARY_UNINSTALL_FINISHED_SUCCESSFULLY_CLI.get();
602      }
603    } else if (getUninstallUserData().getRemoveLibrariesAndTools()) {
604      String formattedPath =
605          addWordBreaks(joinAsString(getLineBreak().toString(), paths), 60, 5);
606      successMsg = INFO_SUMMARY_UNINSTALL_FINISHED_SUCCESSFULLY_REMOVE_JARFILES.get(formattedPath);
607    } else {
608      successMsg = INFO_SUMMARY_UNINSTALL_FINISHED_SUCCESSFULLY.get();
609    }
610    hmSummary.put(FINISHED_SUCCESSFULLY, getFormattedSuccess(successMsg));
611
612    LocalizableMessage nonCriticalMsg;
613    if (!isCli())
614    {
615      nonCriticalMsg =
616        INFO_SUMMARY_UNINSTALL_FINISHED_WITH_ERROR_ON_REMOTE.get();
617    }
618    else
619    {
620      nonCriticalMsg =
621        INFO_SUMMARY_UNINSTALL_FINISHED_WITH_ERROR_ON_REMOTE_CLI.get();
622    }
623    hmSummary.put(FINISHED_WITH_ERROR_ON_REMOTE, getFormattedWarning(nonCriticalMsg));
624    if (!isCli())
625    {
626      nonCriticalMsg =
627        INFO_SUMMARY_UNINSTALL_FINISHED_WITH_ERROR_DELETING.get();
628    }
629    else
630    {
631      nonCriticalMsg =
632        INFO_SUMMARY_UNINSTALL_FINISHED_WITH_ERROR_DELETING_CLI.get();
633    }
634    hmSummary.put(FINISHED_WITH_ERROR_DELETING, getFormattedWarning(nonCriticalMsg));
635    hmSummary.put(FINISHED_WITH_ERROR, getFormattedError(INFO_SUMMARY_UNINSTALL_FINISHED_WITH_ERROR.get()));
636
637    /*
638    * hmTime contains the relative time that takes for each task to be
639    * accomplished. For instance if stopping takes twice the time of
640    * deleting files, the value for downloading will be the double of the
641    * value for extracting.
642    */
643    Map<UninstallProgressStep, Integer> hmTime = new HashMap<>();
644    hmTime.put(UNCONFIGURING_REPLICATION, 5);
645    hmTime.put(STOPPING_SERVER, 15);
646    hmTime.put(DISABLING_WINDOWS_SERVICE, 5);
647    hmTime.put(DELETING_EXTERNAL_DATABASE_FILES, 30);
648    hmTime.put(DELETING_EXTERNAL_LOG_FILES, 5);
649    hmTime.put(REMOVING_EXTERNAL_REFERENCES, 5);
650    hmTime.put(DELETING_INSTALLATION_FILES, 10);
651
652    int totalTime = 0;
653    List<UninstallProgressStep> steps = new ArrayList<>();
654    if (getUninstallUserData().getUpdateRemoteReplication()) {
655      totalTime += hmTime.get(UNCONFIGURING_REPLICATION);
656      steps.add(UNCONFIGURING_REPLICATION);
657    }
658    if (getUserData().getStopServer()) {
659      totalTime += hmTime.get(STOPPING_SERVER);
660      steps.add(STOPPING_SERVER);
661    }
662    if (isWindowsServiceEnabled()) {
663      totalTime += hmTime.get(DISABLING_WINDOWS_SERVICE);
664      steps.add(DISABLING_WINDOWS_SERVICE);
665    }
666    totalTime += hmTime.get(DELETING_INSTALLATION_FILES);
667    steps.add(DELETING_INSTALLATION_FILES);
668
669    if (!getUninstallUserData().getExternalDbsToRemove().isEmpty()) {
670      totalTime += hmTime.get(DELETING_EXTERNAL_DATABASE_FILES);
671      steps.add(DELETING_EXTERNAL_DATABASE_FILES);
672    }
673
674    if (!getUninstallUserData().getExternalLogsToRemove().isEmpty()) {
675      totalTime += hmTime.get(DELETING_EXTERNAL_LOG_FILES);
676      steps.add(DELETING_EXTERNAL_LOG_FILES);
677    }
678
679    int cumulatedTime = 0;
680    for (UninstallProgressStep s : steps) {
681      Integer statusTime = hmTime.get(s);
682      hmRatio.put(s, (100 * cumulatedTime) / totalTime);
683      if (statusTime != null) {
684        cumulatedTime += statusTime;
685      }
686    }
687
688    hmRatio.put(FINISHED_SUCCESSFULLY, 100);
689    hmRatio.put(FINISHED_WITH_ERROR_ON_REMOTE, 100);
690    hmRatio.put(FINISHED_WITH_ERROR, 100);
691  }
692
693  private void putSummary(UninstallProgressStep status, Arg0 msg)
694  {
695    hmSummary.put(status, getFormattedSummary(msg.get()));
696  }
697
698  /** Actually performs the uninstall in this thread. The thread is blocked. */
699  @Override
700  public void run() {
701    status = STARTED;
702    logger.info(LocalizableMessage.raw("run of the Uninstaller started"));
703
704    initMaps();
705    PrintStream origErr = System.err;
706    PrintStream origOut = System.out;
707    try {
708      PrintStream err = new ErrorPrintStream();
709      PrintStream out = new OutputPrintStream();
710      if (!isCli()) {
711        System.setErr(err);
712        System.setOut(out);
713      }
714
715      displaySeparator = false;
716      removeRemoteServerReferences0();
717      stopServer0();
718      disableWindowsService0();
719      deleteExternalDatabaseFiles0();
720      deleteExternalLogFiles0();
721      deleteInstallationFiles0();
722      if (errorOnRemoteOccurred)
723      {
724        status = FINISHED_WITH_ERROR_ON_REMOTE;
725      }
726      else if (errorDeletingOccurred)
727      {
728        status = FINISHED_WITH_ERROR_DELETING;
729      }
730      else
731      {
732        status = FINISHED_SUCCESSFULLY;
733      }
734      if (isCli()) {
735        notifyListeners(new LocalizableMessageBuilder(getLineBreak())
736                .append(getLineBreak()).append(getSummary(status))
737                .toMessage());
738      } else {
739        notifyListeners(null);
740      }
741    } catch (ApplicationException ex) {
742      logger.error(LocalizableMessage.raw("Error: "+ex, ex));
743      ue = ex;
744      status = FINISHED_WITH_ERROR;
745      notifyListeners(getFormattedError(ex, true));
746    }
747    catch (Throwable t) {
748      logger.error(LocalizableMessage.raw("Error: "+t, t));
749      ue = new ApplicationException(
750              ReturnCode.BUG,
751              getThrowableMsg(INFO_BUG_MSG.get(), t), t);
752      status = FINISHED_WITH_ERROR;
753      notifyListeners(getFormattedError(ue, true));
754    }
755    if (!isCli()) {
756      System.setErr(origErr);
757      System.setOut(origOut);
758    }
759  }
760
761  private void removeRemoteServerReferences0() throws ApplicationException
762  {
763    boolean runStep = getUninstallUserData().getUpdateRemoteReplication();
764    logger.info(LocalizableMessage.raw("Update remote replication? " + runStep));
765    if (runStep)
766    {
767      status = UNCONFIGURING_REPLICATION;
768      removeRemoteServerReferences();
769      displaySeparator = true;
770    }
771  }
772
773  private void disableWindowsService0() throws ApplicationException
774  {
775    boolean runStep = isWindowsServiceEnabled();
776    logger.info(LocalizableMessage.raw("Is Windows Service Enabled? " + runStep));
777    if (runStep)
778    {
779      status = DISABLING_WINDOWS_SERVICE;
780      notifyListenersBeforeStep();
781      disableWindowsService();
782      displaySeparator = true;
783    }
784  }
785
786  private void stopServer0() throws ApplicationException
787  {
788    boolean runStep = getUserData().getStopServer();
789    logger.info(LocalizableMessage.raw("Stop server? " + runStep));
790    if (runStep)
791    {
792      status = STOPPING_SERVER;
793      notifyListenersBeforeStep();
794      if (!isVerbose())
795      {
796        notifyListeners(getFormattedWithPoints(
797            INFO_PROGRESS_STOPPING_NON_VERBOSE.get()));
798      }
799      // In case of uninstall, the server stop has to run locally.
800      // In order to bypass the tools.properties mechanism, if any,
801      // we systematically add the --noPropertiesFile flag
802      // when we run the stop-ds command. This is done
803      // by setting the parameter "noPropertiesFile" to 'true'
804      // in the following call.
805      new ServerController(this).stopServer(!isVerbose(),true);
806      if (!isVerbose())
807      {
808        notifyListeners(getFormattedDoneWithLineBreak());
809      }
810      displaySeparator = true;
811    }
812  }
813
814  private void deleteInstallationFiles0() throws ApplicationException
815  {
816    UninstallUserData userData = getUninstallUserData();
817    boolean somethingToDelete = userData.getRemoveBackups() ||
818            userData.getRemoveConfigurationAndSchema() ||
819            userData.getRemoveDatabases() ||
820            userData.getRemoveLDIFs() ||
821            userData.getRemoveLibrariesAndTools() ||
822            userData.getRemoveLogs();
823
824    if (somethingToDelete) {
825      status = DELETING_INSTALLATION_FILES;
826      notifyListenersBeforeStep();
827      try
828      {
829        deleteInstallationFiles(getRatio(status), getRatio(FINISHED_SUCCESSFULLY));
830      }
831      catch (ApplicationException ae)
832      {
833        handle(ae);
834      }
835    }
836  }
837
838  private void deleteExternalLogFiles0() throws ApplicationException
839  {
840    Set<String> logsToDelete = getUninstallUserData().getExternalLogsToRemove();
841    if (!logsToDelete.isEmpty())
842    {
843      status = DELETING_EXTERNAL_LOG_FILES;
844      notifyListenersBeforeStep();
845
846      try
847      {
848        deleteExternalLogFiles(logsToDelete);
849        displaySeparator = true;
850      }
851      catch (ApplicationException ae)
852      {
853        handle(ae);
854      }
855    }
856  }
857
858  private void deleteExternalDatabaseFiles0() throws ApplicationException
859  {
860    Set<String> dbsToDelete = getUninstallUserData().getExternalDbsToRemove();
861    if (!dbsToDelete.isEmpty()) {
862      status = DELETING_EXTERNAL_DATABASE_FILES;
863      notifyListenersBeforeStep();
864
865      try
866      {
867        deleteExternalDatabaseFiles(dbsToDelete);
868        displaySeparator = true;
869      }
870      catch (ApplicationException ae)
871      {
872        handle(ae);
873      }
874    }
875  }
876
877  private void notifyListenersBeforeStep()
878  {
879    if (displaySeparator && isVerbose())
880    {
881      notifyListeners(getTaskSeparator());
882    }
883  }
884
885  private void handle(ApplicationException e) throws ApplicationException
886  {
887    if (e.getType() == ReturnCode.FILE_SYSTEM_ACCESS_ERROR)
888    {
889      errorDeletingOccurred = true;
890      notifyListeners(getFormattedWarning(e.getMessageObject()));
891    }
892    else
893    {
894      throw e;
895    }
896  }
897
898  @Override
899  public UninstallProgressStep getCurrentProgressStep() {
900    return status;
901  }
902
903  /**
904   * Returns an integer that specifies which percentage of the whole
905   * installation has been completed.
906   *
907   * @param step the UninstallProgressStep for which we want to get the ratio.
908   * @return an integer that specifies which percentage of the whole
909   *         uninstallation has been completed.
910   */
911  @Override
912  public Integer getRatio(ProgressStep step) {
913    return hmRatio.get(step);
914  }
915
916  /**
917   * Returns an formatted representation of the summary for the specified
918   * UninstallProgressStep.
919   *
920   * @param step the UninstallProgressStep for which we want to get the summary.
921   * @return an formatted representation of the summary for the specified
922   *         UninstallProgressStep.
923   */
924  @Override
925  public LocalizableMessage getSummary(ProgressStep step) {
926    return hmSummary.get(step);
927  }
928
929  @Override
930  public boolean isFinished() {
931    ProgressStep currentProgressStep = getCurrentProgressStep();
932    return currentProgressStep == FINISHED_SUCCESSFULLY
933        || currentProgressStep == FINISHED_WITH_ERROR
934        || currentProgressStep == FINISHED_WITH_ERROR_ON_REMOTE
935        || currentProgressStep == FINISHED_WITH_ERROR_DELETING;
936  }
937
938  @Override
939  public boolean isCancellable() {
940    return false;
941  }
942
943  @Override
944  public void cancel() {
945    // do nothing; not cancellable
946  }
947
948  @Override
949  public void windowClosing(QuickSetupDialog dlg, WindowEvent evt) {
950    if (dlg.getDisplayedStep() == PROGRESS ||
951        dlg.getDisplayedStep() == FINISHED) {
952      // Simulate a close button event
953      dlg.notifyButtonEvent(ButtonName.CLOSE);
954    } else {
955      // Simulate a quit button event
956      dlg.notifyButtonEvent(ButtonName.QUIT);
957    }
958  }
959
960  @Override
961  public ButtonName getInitialFocusButtonName() {
962    return ButtonName.FINISH;
963  }
964
965  @Override
966  public Set<? extends WizardStep> getWizardSteps() {
967    Set<WizardStep> setSteps = new HashSet<>();
968    setSteps.add(Step.CONFIRM_UNINSTALL);
969    setSteps.add(Step.PROGRESS);
970    setSteps.add(Step.FINISHED);
971    return Collections.unmodifiableSet(setSteps);
972  }
973
974  @Override
975  public QuickSetupStepPanel createWizardStepPanel(WizardStep step) {
976    if (step == Step.CONFIRM_UNINSTALL) {
977      return new ConfirmUninstallPanel(this);
978    } else if (step == Step.PROGRESS) {
979      return new ProgressPanel(this);
980    } else if (step == Step.FINISHED) {
981      return new FinishedPanel(this);
982    }
983    return null;
984  }
985
986  /**
987   * Deletes the external database files specified in the provided Set.
988   *
989   * @param dbFiles the database directories to be deleted.
990   * @throws ApplicationException if something goes wrong.
991   */
992  private void deleteExternalDatabaseFiles(Set<String> dbFiles)
993          throws ApplicationException {
994    if (isVerbose())
995    {
996      notifyListeners(getFormattedProgressWithLineBreak(
997            INFO_PROGRESS_DELETING_EXTERNAL_DB_FILES.get()));
998    }
999    else
1000    {
1001      notifyListeners(getFormattedWithPoints(
1002          INFO_PROGRESS_DELETING_EXTERNAL_DB_FILES_NON_VERBOSE.get()));
1003    }
1004    for (String path : dbFiles) {
1005      deleteRecursively(new File(path));
1006    }
1007    if (!isVerbose())
1008    {
1009      notifyListeners(getFormattedDoneWithLineBreak());
1010    }
1011  }
1012
1013  /**
1014   * Deletes the external database files specified in the provided Set.
1015   *
1016   * @param logFiles the log files to be deleted.
1017   * @throws ApplicationException if something goes wrong.
1018   */
1019  private void deleteExternalLogFiles(Set<String> logFiles)
1020          throws ApplicationException {
1021    if (isVerbose())
1022    {
1023      notifyListeners(getFormattedProgressWithLineBreak(
1024          INFO_PROGRESS_DELETING_EXTERNAL_LOG_FILES.get()));
1025    }
1026    else
1027    {
1028      notifyListeners(getFormattedWithPoints(
1029          INFO_PROGRESS_DELETING_EXTERNAL_LOG_FILES_NON_VERBOSE.get()));
1030    }
1031    for (String path : logFiles) {
1032      deleteRecursively(new File(path));
1033    }
1034    if (!isVerbose())
1035    {
1036      notifyListeners(getFormattedDoneWithLineBreak());
1037    }
1038  }
1039
1040  /**
1041   * Deletes the files under the installation path.
1042   *
1043   * @throws ApplicationException if something goes wrong.
1044   */
1045  private void deleteInstallationFiles(int minRatio, int maxRatio)
1046          throws ApplicationException {
1047    if (isVerbose())
1048    {
1049      notifyListeners(getFormattedProgressWithLineBreak(
1050          INFO_PROGRESS_DELETING_INSTALLATION_FILES.get()));
1051    }
1052    else
1053    {
1054      notifyListeners(getFormattedWithPoints(
1055          INFO_PROGRESS_DELETING_INSTALLATION_FILES_NON_VERBOSE.get()));
1056    }
1057
1058    String installPath = getInstallPathFromClasspath();
1059    File installFile = new File(installPath);
1060    try
1061    {
1062      installPath = installFile.getCanonicalPath();
1063    }
1064    catch(Exception e)
1065    {
1066      installPath = getInstallPathFromClasspath();
1067    }
1068
1069    String instancePath =
1070      Utils.getInstancePathFromInstallPath(installFile.getAbsolutePath());
1071    File instanceFile = new File(instancePath);
1072    try
1073    {
1074      instancePath = instanceFile.getCanonicalPath();
1075    } catch (Exception e)
1076    {
1077      instancePath =
1078        Utils.getInstancePathFromInstallPath(installFile.getAbsolutePath());
1079    }
1080
1081    InstallationFilesToDeleteFilter filter =
1082            new InstallationFilesToDeleteFilter();
1083
1084    File[] installFiles  = installFile.listFiles();
1085    File[] instanceFiles  = null ;
1086    if (! installPath.equals(instancePath))
1087    {
1088      instanceFiles = new File(instancePath).listFiles();
1089    }
1090
1091    File[] rootFiles = null;
1092
1093    if (installFiles == null)
1094    {
1095      rootFiles = new File(instancePath).listFiles();
1096    }
1097    else
1098    if (instanceFiles == null)
1099    {
1100      rootFiles = installFiles;
1101    }
1102    else
1103    {
1104      // both installFiles and instanceFiles are not null
1105      rootFiles = new File[installFiles.length + instanceFiles.length];
1106      System.arraycopy(installFiles,  0, rootFiles, 0, installFiles.length);
1107      System.arraycopy(instanceFiles, 0, rootFiles, installFiles.length,
1108          instanceFiles.length);
1109    }
1110
1111    if (rootFiles != null) {
1112      // The following is done to have a moving progress bar when we delete the installation files
1113      int totalRatio = 0;
1114      ArrayList<Integer> cumulatedRatio = new ArrayList<>();
1115      for (File f : rootFiles) {
1116        if (filter.accept(f)) {
1117          Installation installation = getInstallation();
1118          int relativeRatio;
1119          if (equalsOrDescendant(f, installation.getLibrariesDirectory())) {
1120            relativeRatio = 10;
1121          } else if (equalsOrDescendant(f, installation.getBinariesDirectory())) {
1122            relativeRatio = 5;
1123          } else if (equalsOrDescendant(f, installation.getConfigurationDirectory())) {
1124            relativeRatio = 5;
1125          } else if (equalsOrDescendant(f, installation.getBackupDirectory())) {
1126            relativeRatio = 20;
1127          } else if (equalsOrDescendant(f, installation.getLdifDirectory())) {
1128            relativeRatio = 20;
1129          } else if (equalsOrDescendant(f, installation.getDatabasesDirectory())) {
1130            relativeRatio = 50;
1131          } else if (equalsOrDescendant(f, installation.getLogsDirectory())) {
1132            relativeRatio = 30;
1133          } else {
1134            relativeRatio = 2;
1135          }
1136          cumulatedRatio.add(totalRatio);
1137          totalRatio += relativeRatio;
1138        } else {
1139          cumulatedRatio.add(totalRatio);
1140        }
1141      }
1142      Iterator<Integer> it = cumulatedRatio.iterator();
1143      for (File rootFile : rootFiles)
1144      {
1145        int beforeRatio = minRatio +
1146                (it.next() * (maxRatio - minRatio)) / totalRatio;
1147        hmRatio.put(DELETING_INSTALLATION_FILES, beforeRatio);
1148        deleteRecursively(rootFile, filter);
1149      }
1150      hmRatio.put(DELETING_INSTALLATION_FILES, maxRatio);
1151    }
1152    if (!isVerbose())
1153    {
1154      notifyListeners(getFormattedDone());
1155    }
1156  }
1157
1158  /**
1159   * Deletes everything below the specified file.
1160   *
1161   * @param file the path to be deleted.
1162   * @throws ApplicationException if something goes wrong.
1163   */
1164  private void deleteRecursively(File file) throws ApplicationException {
1165    deleteRecursively(file, null);
1166  }
1167
1168  /**
1169   * Deletes everything below the specified file.
1170   *
1171   * @param file   the path to be deleted.
1172   * @param filter the filter of the files to know if the file can be deleted
1173   *               directly or not.
1174   * @throws ApplicationException if something goes wrong.
1175   */
1176  private void deleteRecursively(File file, FileFilter filter)
1177          throws ApplicationException {
1178    File cfile ;
1179    try
1180    {
1181      cfile = file.getCanonicalFile();
1182    }
1183    catch (Exception e)
1184    {
1185      cfile = file ;
1186    }
1187    if (cfile.exists()) {
1188      if (cfile.isFile()) {
1189        if (filter != null) {
1190          if (filter.accept(cfile)) {
1191            delete(cfile);
1192          }
1193        } else {
1194          delete(cfile);
1195        }
1196      } else {
1197        File[] children = cfile.listFiles();
1198        if (children != null) {
1199          for (File element : children)
1200          {
1201            deleteRecursively(element, filter);
1202          }
1203        }
1204        if (filter != null) {
1205          if (filter.accept(cfile)) {
1206            delete(cfile);
1207          }
1208        } else {
1209          delete(cfile);
1210        }
1211      }
1212    } else {
1213      // Just tell that the file/directory does not exist.
1214      notifyListeners(getFormattedWarning(
1215          INFO_PROGRESS_DELETING_FILE_DOES_NOT_EXIST.get(cfile)));
1216    }
1217  }
1218
1219  /**
1220   * Deletes the specified file.
1221   *
1222   * @param file the file to be deleted.
1223   * @throws ApplicationException if something goes wrong.
1224   */
1225  private void delete(File file) throws ApplicationException {
1226    boolean isFile = file.isFile();
1227
1228    if (isVerbose())
1229    {
1230      if (isFile) {
1231        notifyListeners(getFormattedWithPoints(
1232            INFO_PROGRESS_DELETING_FILE.get(file.getAbsolutePath())));
1233      } else {
1234        notifyListeners(getFormattedWithPoints(
1235            INFO_PROGRESS_DELETING_DIRECTORY.get(file.getAbsolutePath())));
1236      }
1237    }
1238
1239    boolean delete = false;
1240    /*
1241     * Sometimes the server keeps some locks on the files.
1242     * This is dependent on the OS so there is no much we can do here.
1243     */
1244    int nTries = 5;
1245    for (int i = 0; i < nTries && !delete; i++) {
1246      delete = file.delete();
1247      if (!delete) {
1248        try {
1249          Thread.sleep(1000);
1250        }
1251        catch (Exception ex) {
1252        }
1253      }
1254    }
1255
1256    if (!delete) {
1257      LocalizableMessage errMsg;
1258      if (isFile) {
1259        errMsg = INFO_ERROR_DELETING_FILE.get(file.getAbsolutePath());
1260      } else {
1261        errMsg = INFO_ERROR_DELETING_DIRECTORY.get(file.getAbsolutePath());
1262      }
1263      throw new ApplicationException(
1264          ReturnCode.FILE_SYSTEM_ACCESS_ERROR,
1265          errMsg, null);
1266    }
1267
1268    if (isVerbose())
1269    {
1270      notifyListeners(getFormattedDoneWithLineBreak());
1271    }
1272  }
1273
1274  private boolean equalsOrDescendant(File file, File directory) {
1275    return file.equals(directory) || isDescendant(file, directory);
1276  }
1277
1278  /**
1279   * This class is used to get the files that are not binaries.  This is
1280   * required to know which are the files that can be deleted directly and which
1281   * not.
1282   */
1283  private class InstallationFilesToDeleteFilter implements FileFilter {
1284    private Installation installation = getInstallation();
1285    private File quicksetupFile = installation.getQuicksetupJarFile();
1286    private File openDSFile = installation.getOpenDSJarFile();
1287    private File librariesFile = installation.getLibrariesDirectory();
1288    private File resourcesDir = installation.getResourcesDirectory();
1289    private File classesDir = installation.getClassesDirectory();
1290    private File uninstallBatFile = installation.getUninstallBatFile();
1291
1292    private boolean canDeleteResourcesDir =
1293      !Utils.directoryExistsAndIsNotEmpty(resourcesDir.getAbsolutePath());
1294    private boolean canDeleteClassesDir =
1295      !Utils.directoryExistsAndIsNotEmpty(classesDir.getAbsolutePath());
1296
1297    private File installationPath = installation.getRootDirectory();
1298
1299    @Override
1300    public boolean accept(File file) {
1301      UninstallUserData userData = getUninstallUserData();
1302      boolean[] uData = {
1303              userData.getRemoveLibrariesAndTools(),
1304              userData.getRemoveLibrariesAndTools(),
1305              userData.getRemoveLibrariesAndTools(),
1306              userData.getRemoveLibrariesAndTools(),
1307              userData.getRemoveDatabases(),
1308              userData.getRemoveLogs(),
1309              userData.getRemoveConfigurationAndSchema(),
1310              userData.getRemoveBackups(),
1311              userData.getRemoveLDIFs()
1312      };
1313
1314      Installation installation = getInstallation();
1315      File[] parentFiles;
1316      try {
1317        parentFiles = new File[] {
1318              installation.getLibrariesDirectory().getCanonicalFile(),
1319              installation.getBinariesDirectory().getCanonicalFile(),
1320              installation.getResourcesDirectory().getCanonicalFile(),
1321              installation.getClassesDirectory().getCanonicalFile(),
1322              installation.getDatabasesDirectory().getCanonicalFile(),
1323              installation.getLogsDirectory().getCanonicalFile(),
1324              installation.getConfigurationDirectory().getCanonicalFile(),
1325              installation.getBackupDirectory().getCanonicalFile(),
1326              installation.getLdifDirectory().getCanonicalFile()
1327        };
1328      }
1329      catch (Exception e)
1330      {
1331        return true;
1332      }
1333
1334      boolean accept =
1335        !installationPath.equals(file)
1336        && !equalsOrDescendant(file, librariesFile)
1337        && (canDeleteClassesDir  || !equalsOrDescendant(file, classesDir))
1338        && (canDeleteResourcesDir || !equalsOrDescendant(file, resourcesDir))
1339        && !quicksetupFile.equals(file)
1340        && !openDSFile.equals(file);
1341
1342      if (accept && isWindows() && isCli()) {
1343        accept = !uninstallBatFile.equals(file);
1344      }
1345
1346      for (int i = 0; i < uData.length && accept; i++) {
1347        File parent = parentFiles[i];
1348        accept &= uData[i] || !equalsOrDescendant(file, parent);
1349      }
1350
1351      logger.info(LocalizableMessage.raw("accept for :"+file+" is: "+accept));
1352      return accept;
1353    }
1354  }
1355
1356  private boolean isWindowsServiceEnabled() {
1357    if (isWindowsServiceEnabled == null) {
1358      isWindowsServiceEnabled = serviceState() == SERVICE_STATE_ENABLED;
1359    }
1360    return isWindowsServiceEnabled.booleanValue();
1361  }
1362
1363  @Override
1364  public ApplicationTrustManager getTrustManager()
1365  {
1366    return getUninstallUserData().getTrustManager();
1367  }
1368
1369  /**
1370   * This methods disables this server as a Windows service.
1371   *
1372   * @throws ApplicationException if something goes wrong.
1373   */
1374  private void disableWindowsService() throws ApplicationException {
1375    notifyListeners(getFormattedWithPoints(
1376            INFO_PROGRESS_DISABLING_WINDOWS_SERVICE.get()));
1377    int code = disableService(System.out, System.err);
1378
1379    LocalizableMessage errorMessage = INFO_ERROR_DISABLING_WINDOWS_SERVICE.get(
1380            getInstallationPath());
1381
1382    switch (code) {
1383      case SERVICE_DISABLE_SUCCESS:
1384      case SERVICE_ALREADY_DISABLED:
1385        break;
1386      default:
1387        throw new ApplicationException(ReturnCode.WINDOWS_SERVICE_ERROR, errorMessage, null);
1388    }
1389    notifyListeners(getLineBreak());
1390  }
1391
1392  private UninstallUserData getUninstallUserData() {
1393    return (UninstallUserData) getUserData();
1394  }
1395
1396  /**
1397   * Tries to start the server and launches a progress dialog.  This method
1398   * assumes that is being called from the event thread.
1399   * @return <CODE>true</CODE> if the server could be started and <CODE>
1400   * false</CODE> otherwise.
1401   * @param frame the JFrame to be used as parent of the progress dialog.
1402   */
1403  private boolean startServer(JFrame frame)
1404  {
1405    startProgressDetails = new LocalizableMessageBuilder();
1406    startProgressDlg = new ProgressDialog(frame);
1407    startProgressDlg.setSummary(
1408        getFormattedSummary(INFO_SUMMARY_STARTING.get()));
1409    startProgressDlg.setDetails(LocalizableMessage.EMPTY);
1410    startProgressDlg.setCloseButtonEnabled(false);
1411    final Boolean[] returnValue = new Boolean[] {Boolean.FALSE};
1412    Thread t = new Thread(new Runnable()
1413    {
1414      @Override
1415      public void run()
1416      {
1417        try
1418        {
1419          new ServerController(Uninstaller.this).startServer();
1420          final boolean isServerRunning =
1421            Installation.getLocal().getStatus().isServerRunning();
1422          returnValue[0] = isServerRunning;
1423          SwingUtilities.invokeLater(new Runnable()
1424          {
1425            @Override
1426            public void run()
1427            {
1428              startProgressDlg.setSummary(isServerRunning
1429                  ? getFormattedSuccess(INFO_SUMMARY_START_SUCCESS.get())
1430                  : getFormattedError(INFO_SUMMARY_START_ERROR.get()));
1431              startProgressDlg.setCloseButtonEnabled(true);
1432            }
1433          });
1434        }
1435        catch (Throwable t)
1436        {
1437          notifyListeners(getFormattedError(t, true));
1438        }
1439      }
1440    });
1441    t.start();
1442    startProgressDlg.pack();
1443    Utilities.centerOnComponent(startProgressDlg, frame);
1444    startProgressDlg.setModal(true);
1445    startProgressDlg.setVisible(true);
1446    startProgressDlg = null;
1447    return returnValue[0];
1448  }
1449
1450  /**
1451   * This method displays a login dialog message, asking the user to provide
1452   * authentication to retrieve information from the ADS and update the
1453   * remote servers.  Then it tries to connect to the remote servers.
1454   *
1455   * @param qs the QuickSetup object.
1456   */
1457  private void askForAuthenticationAndLaunch(final QuickSetup qs)
1458  {
1459    if (loginDialog == null)
1460    {
1461      loginDialog = new LoginDialog(qs.getDialog().getFrame(),
1462          getTrustManager(), getConnectTimeout());
1463      loginDialog.pack();
1464    }
1465    Utilities.centerOnComponent(loginDialog, qs.getDialog().getFrame());
1466    loginDialog.setModal(true);
1467    loginDialog.setVisible(true);
1468    if (!loginDialog.isCanceled())
1469    {
1470      getUninstallUserData().setAdminUID(loginDialog.getAdministratorUid());
1471      getUninstallUserData().setAdminPwd(loginDialog.getAdministratorPwd());
1472      final ConnectionWrapper connWrapper = loginDialog.getConnection();
1473      try
1474      {
1475        getUninstallUserData().setLocalServerUrl(
1476            (String)connWrapper.getLdapContext().getEnvironment().get(Context.PROVIDER_URL));
1477      }
1478      catch (NamingException ne)
1479      {
1480        logger.warn(LocalizableMessage.raw("Could not find local server: "+ne, ne));
1481        getUninstallUserData().setLocalServerUrl("ldap://localhost:389");
1482      }
1483      getUninstallUserData().setReplicationServer(
1484          loginDialog.getHostName() + ":" +
1485          conf.getReplicationServerPort());
1486      getUninstallUserData().setReferencedHostName(loginDialog.getHostName());
1487
1488      BackgroundTask<TopologyCache> worker = new BackgroundTask<TopologyCache>()
1489      {
1490        @Override
1491        public TopologyCache processBackgroundTask() throws Throwable
1492        {
1493          logger.info(LocalizableMessage.raw("Loading Topology Cache in askForAuthentication"));
1494          ADSContext adsContext = new ADSContext(connWrapper);
1495          TopologyCache cache = new TopologyCache(adsContext,
1496              getTrustManager(), getConnectTimeout());
1497          cache.getFilter().setSearchMonitoringInformation(false);
1498          cache.reloadTopology();
1499          return cache;
1500        }
1501        @Override
1502        public void backgroundTaskCompleted(TopologyCache returnValue,
1503            Throwable throwable) {
1504          qs.getDialog().workerFinished();
1505          if (throwable != null)
1506          {
1507            logger.warn(LocalizableMessage.raw("Throwable: "+throwable, throwable));
1508            if (throwable instanceof TopologyCacheException)
1509            {
1510              qs.displayError(
1511                      getMessage((TopologyCacheException) throwable),
1512                      INFO_ERROR_TITLE.get());
1513            }
1514            else
1515            {
1516              qs.displayError(
1517                  getThrowableMsg(INFO_BUG_MSG.get(), throwable),
1518                  INFO_ERROR_TITLE.get());
1519            }
1520            logger.info(LocalizableMessage.raw("Error was displayed"));
1521          }
1522          else
1523          {
1524            TopologyCache cache = returnValue;
1525            handleTopologyCache(qs, cache);
1526          }
1527        }
1528      };
1529
1530      qs.getDialog().workerStarted();
1531      worker.startBackgroundTask();
1532    }
1533    else if (qs.displayConfirmation(
1534        INFO_CONFIRM_UNINSTALL_SERVER_RUNNING_MSG.get(),
1535        INFO_CONFIRM_UNINSTALL_SERVER_RUNNING_TITLE.get()))
1536    {
1537      getUserData().setStopServer(true);
1538      qs.launch();
1539      qs.setCurrentStep(getNextWizardStep(Step.CONFIRM_UNINSTALL));
1540    } else {
1541      getUserData().setStopServer(false);
1542    }
1543  }
1544
1545  /**
1546   * Method that interacts with the user depending on what errors where
1547   * encountered in the TopologyCache object.  This method assumes that the
1548   * TopologyCache has been reloaded.
1549   * Note: this method assumes that is being called from the event thread.
1550   * @param qs the QuickSetup object for the application.
1551   * @param cache the TopologyCache.
1552   */
1553  private void handleTopologyCache(QuickSetup qs, TopologyCache cache)
1554  {
1555    logger.info(LocalizableMessage.raw("Handling TopologyCache"));
1556    boolean stopProcessing = false;
1557    Set<TopologyCacheException> exceptions = new HashSet<>();
1558    /* Analyze if we had any exception while loading servers.  For the moment
1559     * only throw the exception found if the user did not provide the
1560     * Administrator DN and this caused a problem authenticating in one server
1561     * or if there is a certificate problem.
1562     */
1563    for (ServerDescriptor server : cache.getServers())
1564    {
1565      TopologyCacheException e = server.getLastException();
1566      if (e != null)
1567      {
1568        exceptions.add(e);
1569      }
1570    }
1571    Set<LocalizableMessage> exceptionMsgs = new LinkedHashSet<>();
1572    /* Check the exceptions and see if we throw them or not. */
1573    for (TopologyCacheException e : exceptions)
1574    {
1575      logger.info(LocalizableMessage.raw("Analyzing exception: "+e, e));
1576      if (stopProcessing)
1577      {
1578        break;
1579      }
1580      switch (e.getType())
1581      {
1582      case NOT_GLOBAL_ADMINISTRATOR:
1583        LocalizableMessage errorMsg = INFO_NOT_GLOBAL_ADMINISTRATOR_PROVIDED.get();
1584        qs.displayError(errorMsg, INFO_ERROR_TITLE.get());
1585        stopProcessing = true;
1586        break;
1587      case GENERIC_CREATING_CONNECTION:
1588        if (isCertificateException(e.getCause()))
1589        {
1590          ApplicationTrustManager.Cause cause = null;
1591          if (e.getTrustManager() != null)
1592          {
1593            cause = e.getTrustManager().getLastRefusedCause();
1594          }
1595          logger.info(LocalizableMessage.raw("Certificate exception cause: "+cause));
1596          UserDataCertificateException.Type excType = getCertificateExceptionType(cause);
1597          if (excType != null)
1598          {
1599            String h;
1600            int p;
1601            try
1602            {
1603              URI uri = new URI(e.getLdapUrl());
1604              h = uri.getHost();
1605              p = uri.getPort();
1606            }
1607            catch (Throwable t)
1608            {
1609              logger.warn(LocalizableMessage.raw(
1610                  "Error parsing ldap url of TopologyCacheException.", t));
1611              h = INFO_NOT_AVAILABLE_LABEL.get().toString();
1612              p = -1;
1613            }
1614            UserDataCertificateException exc =
1615              new UserDataCertificateException(Step.REPLICATION_OPTIONS,
1616                INFO_CERTIFICATE_EXCEPTION.get(h, p),
1617                e.getCause(), h, p,
1618                e.getTrustManager().getLastRefusedChain(),
1619                e.getTrustManager().getLastRefusedAuthType(), excType);
1620            handleCertificateException(qs, exc, cache);
1621            stopProcessing = true;
1622          }
1623        }
1624      }
1625      exceptionMsgs.add(getMessage(e));
1626    }
1627    if (!stopProcessing && !exceptionMsgs.isEmpty())
1628    {
1629      LocalizableMessage confirmationMsg =
1630        ERR_UNINSTALL_READING_REGISTERED_SERVERS_CONFIRM_UPDATE_REMOTE.get(
1631                getMessageFromCollection(exceptionMsgs, "\n"));
1632      stopProcessing = !qs.displayConfirmation(confirmationMsg,
1633          INFO_CONFIRMATION_TITLE.get());
1634    }
1635    if (!stopProcessing)
1636    {
1637      stopProcessing = !qs.displayConfirmation(
1638          INFO_CONFIRM_UNINSTALL_SERVER_RUNNING_MSG.get(),
1639          INFO_CONFIRM_UNINSTALL_SERVER_RUNNING_TITLE.get());
1640    }
1641    if (!stopProcessing)
1642    {
1643      // Launch everything
1644      getUninstallUserData().setUpdateRemoteReplication(true);
1645      getUninstallUserData().setRemoteServers(cache.getServers());
1646      getUserData().setStopServer(true);
1647      qs.launch();
1648      qs.setCurrentStep(getNextWizardStep(Step.CONFIRM_UNINSTALL));
1649    }
1650  }
1651
1652  private UserDataCertificateException.Type getCertificateExceptionType(ApplicationTrustManager.Cause cause)
1653  {
1654    if (cause == ApplicationTrustManager.Cause.NOT_TRUSTED)
1655    {
1656      return UserDataCertificateException.Type.NOT_TRUSTED;
1657    }
1658    else if (cause == ApplicationTrustManager.Cause.HOST_NAME_MISMATCH)
1659    {
1660      return UserDataCertificateException.Type.HOST_NAME_MISMATCH;
1661    }
1662    else
1663    {
1664      return null;
1665    }
1666  }
1667
1668  /**
1669   * Displays a dialog asking the user to accept a certificate if the user
1670   * accepts it, we update the trust manager and call again to the method that
1671   * handles the action of clicking on "Finish".
1672   * This method assumes that we are being called from the event thread.
1673   */
1674  private void handleCertificateException(final QuickSetup qs,
1675      UserDataCertificateException ce, final TopologyCache cache)
1676  {
1677    CertificateDialog dlg =
1678      new CertificateDialog(qs.getDialog().getFrame(), ce);
1679    dlg.pack();
1680    dlg.setVisible(true);
1681    if (dlg.getUserAnswer() != CertificateDialog.ReturnType.NOT_ACCEPTED)
1682    {
1683      X509Certificate[] chain = ce.getChain();
1684      String authType = ce.getAuthType();
1685      String host = ce.getHost();
1686
1687      if (chain != null && authType != null && host != null)
1688      {
1689        logger.info(LocalizableMessage.raw("Accepting certificate presented by host "+host));
1690        getTrustManager().acceptCertificate(chain, authType, host);
1691        BackgroundTask<TopologyCache> worker =
1692          new BackgroundTask<TopologyCache>()
1693        {
1694          @Override
1695          public TopologyCache processBackgroundTask() throws Throwable
1696          {
1697            logger.info(LocalizableMessage.raw("Reloading topology"));
1698            cache.getFilter().setSearchMonitoringInformation(false);
1699            cache.reloadTopology();
1700            return cache;
1701          }
1702          @Override
1703          public void backgroundTaskCompleted(TopologyCache returnValue,
1704              Throwable throwable) {
1705            qs.getDialog().workerFinished();
1706            if (throwable != null)
1707            {
1708              if (throwable instanceof TopologyCacheException)
1709              {
1710                qs.displayError(getMessage((TopologyCacheException)throwable),
1711                    INFO_ERROR_TITLE.get());
1712              }
1713              else
1714              {
1715                qs.displayError(
1716                    getThrowableMsg(INFO_BUG_MSG.get(), throwable),
1717                    INFO_ERROR_TITLE.get());
1718              }
1719            }
1720            else
1721            {
1722              handleTopologyCache(qs, cache);
1723            }
1724          }
1725        };
1726
1727        qs.getDialog().workerStarted();
1728        worker.startBackgroundTask();
1729      }
1730      else
1731      {
1732        if (chain == null)
1733        {
1734          logger.warn(LocalizableMessage.raw(
1735              "The chain is null for the UserDataCertificateException"));
1736        }
1737        if (authType == null)
1738        {
1739          logger.warn(LocalizableMessage.raw(
1740              "The auth type is null for the UserDataCertificateException"));
1741        }
1742        if (host == null)
1743        {
1744          logger.warn(LocalizableMessage.raw(
1745              "The host is null for the UserDataCertificateException"));
1746        }
1747      }
1748    }
1749    if (dlg.getUserAnswer() ==
1750      CertificateDialog.ReturnType.ACCEPTED_PERMANENTLY)
1751    {
1752      X509Certificate[] chain = ce.getChain();
1753      if (chain != null)
1754      {
1755        try
1756        {
1757          UIKeyStore.acceptCertificate(chain);
1758        }
1759        catch (Throwable t)
1760        {
1761          logger.warn(LocalizableMessage.raw("Error accepting certificate: "+t, t));
1762        }
1763      }
1764    }
1765  }
1766
1767  /**
1768   * This method updates the replication in the remote servers.  It does
1769   * throw ApplicationException if we are working on the force on error mode.
1770   * It also tries to delete the server registration entry from the remote ADS
1771   * servers.
1772   * @throws ApplicationException if we are not working on force on error mode
1773   * and there is an error.
1774   */
1775  private void removeRemoteServerReferences() throws ApplicationException
1776  {
1777    Set<ServerDescriptor> servers = getUninstallUserData().getRemoteServers();
1778    Map<ADSContext.ServerProperty, Object> serverADSProperties = null;
1779    for (ServerDescriptor server : servers)
1780    {
1781      if (isServerToUninstall(server))
1782      {
1783        serverADSProperties = server.getAdsProperties();
1784        break;
1785      }
1786    }
1787    if (serverADSProperties == null)
1788    {
1789      logger.warn(LocalizableMessage.raw("The server ADS properties for the server to "+
1790          "uninstall could not be found."));
1791    }
1792
1793    for (ServerDescriptor server : servers)
1794    {
1795      if (server.getAdsProperties() != serverADSProperties)
1796      {
1797        removeReferences(server, serverADSProperties);
1798      }
1799    }
1800  }
1801
1802  /**
1803   * This method updates the replication in the remote server represented by
1804   * a given ServerProperty object.
1805   * It also tries to delete the server registration entry from the remote ADS
1806   * servers if the serverADSProperties object passed is not null.
1807   * @param server the ServerDescriptor object representing the server where
1808   * we want to remove references to the server that we are trying to uninstall.
1809   * @param serverADSProperties the Map with the ADS properties of the server
1810   * that we are trying to uninstall.
1811   * @throws ApplicationException if we are not working on force on error mode
1812   * and there is an error.
1813   */
1814  private void removeReferences(ServerDescriptor server,
1815      Map<ADSContext.ServerProperty, Object> serverADSProperties)
1816  throws ApplicationException
1817  {
1818    /* First check if the server must be updated based in the contents of the
1819     * ServerDescriptor object. */
1820    UninstallUserData uData = getUninstallUserData();
1821    String rsUrl = uData.getReplicationServer();
1822    if (!isReferenced(server.getServerProperties(), rsUrl)
1823        && !isReferenced(server.getReplicas(), rsUrl))
1824    {
1825      logger.info(LocalizableMessage.raw("No references in: " + server.getHostPort(true)));
1826      return;
1827    }
1828
1829    logger.info(LocalizableMessage.raw("Updating references in: " + server.getHostPort(true)));
1830    notifyListeners(getFormattedWithPoints(INFO_PROGRESS_REMOVING_REFERENCES.get(server.getHostPort(true))));
1831
1832    String dn = ADSContext.getAdministratorDN(uData.getAdminUID());
1833    String pwd = uData.getAdminPwd();
1834    try (ConnectionWrapper connWrapper =
1835        getRemoteConnection(server, dn, pwd, getConnectTimeout(), new LinkedHashSet<PreferredConnection>()))
1836    {
1837      // Update replication servers and domains. If the domain
1838      // is an ADS, then remove it from there.
1839      removeReferences(connWrapper, server.getHostPort(true), serverADSProperties);
1840
1841      notifyListeners(getFormattedDoneWithLineBreak());
1842    }
1843    catch (ApplicationException ae)
1844    {
1845      errorOnRemoteOccurred = true;
1846      logger.info(LocalizableMessage.raw("Error updating replication references in: " + server.getHostPort(true), ae));
1847
1848      if (!uData.isForceOnError())
1849      {
1850        LocalizableMessage msg =
1851            ERR_UNINSTALL_ERROR_UPDATING_REMOTE_NO_FORCE.get("--" + parser.getSecureArgsList().getAdminUidArg()
1852                .getLongIdentifier(), "--" + OPTION_LONG_BINDPWD, "--" + OPTION_LONG_BINDPWD_FILE, "--"
1853                    + parser.forceOnErrorArg.getLongIdentifier(), ae.getMessageObject());
1854        throw new ApplicationException(ae.getType(), msg, ae);
1855      }
1856      else
1857      {
1858        notifyListeners(getFormattedError(ae, true));
1859      }
1860    }
1861  }
1862
1863  private boolean isReferenced(Map<ServerProperty, Object> serverProperties, String toFind)
1864  {
1865    Object v = serverProperties.get(ServerDescriptor.ServerProperty.IS_REPLICATION_SERVER);
1866    if (Boolean.TRUE.equals(v))
1867    {
1868      Set<?> replicationServers = (Set<?>)
1869          serverProperties.get(ServerDescriptor.ServerProperty.EXTERNAL_REPLICATION_SERVERS);
1870      if (replicationServers != null)
1871      {
1872        for (Object rsUrl : replicationServers)
1873        {
1874          if (toFind.equalsIgnoreCase((String) rsUrl))
1875          {
1876            return true;
1877          }
1878        }
1879      }
1880    }
1881    return false;
1882  }
1883
1884  private boolean isReferenced(Set<ReplicaDescriptor> replicas, String toFind)
1885  {
1886    for (ReplicaDescriptor replica : replicas)
1887    {
1888      if (replica.isReplicated())
1889      {
1890        for (String rsUrl : replica.getReplicationServers())
1891        {
1892          if (toFind.equalsIgnoreCase(rsUrl))
1893          {
1894            return true;
1895          }
1896        }
1897      }
1898    }
1899    return false;
1900  }
1901
1902  /**
1903   * This method updates the replication in the remote server using the
1904   * provided InitialLdapContext.
1905   * It also tries to delete the server registration entry from the remote ADS
1906   * servers if the serverADSProperties object passed is not null.
1907   * @param connWrapper the connection to the remote server where we want to remove
1908   * references to the server that we are trying to uninstall.
1909   * @param serverDisplay an String representation that is used to identify
1910   * the remote server in the log messages we present to the user.
1911   * @param serverADSProperties the Map with the ADS properties of the server
1912   * that we are trying to uninstall.
1913   * @throws ApplicationException if an error occurs while updating the remote
1914   * OpenDS server configuration.
1915   */
1916  private void removeReferences(ConnectionWrapper connWrapper, HostPort serverDisplay,
1917      Map<ADSContext.ServerProperty, Object> serverADSProperties)
1918  throws ApplicationException
1919  {
1920    try
1921    {
1922      RootCfgClient root = connWrapper.getRootConfiguration();
1923      ReplicationSynchronizationProviderCfgClient sync =
1924        (ReplicationSynchronizationProviderCfgClient)
1925        root.getSynchronizationProvider("Multimaster Synchronization");
1926      if (sync.hasReplicationServer())
1927      {
1928        ReplicationServerCfgClient replicationServer =
1929          sync.getReplicationServer();
1930        Set<String> replServers = replicationServer.getReplicationServer();
1931        if (replServers != null)
1932        {
1933          String replServer = findReplicationServer(replServers);
1934          if (replServer != null)
1935          {
1936            logger.info(LocalizableMessage.raw("Updating references in replication server on "+
1937                serverDisplay+"."));
1938            replServers.remove(replServer);
1939            if (!replServers.isEmpty())
1940            {
1941              replicationServer.setReplicationServer(replServers);
1942              replicationServer.commit();
1943            }
1944            else
1945            {
1946              sync.removeReplicationServer();
1947              sync.commit();
1948            }
1949          }
1950        }
1951      }
1952      String[] domainNames = sync.listReplicationDomains();
1953      if (domainNames != null)
1954      {
1955        for (String domainName : domainNames)
1956        {
1957          ReplicationDomainCfgClient domain =
1958            sync.getReplicationDomain(domainName);
1959          Set<String> replServers = domain.getReplicationServer();
1960          if (replServers != null)
1961          {
1962            String replServer = findReplicationServer(replServers);
1963            if (replServer != null)
1964            {
1965              logger.info(LocalizableMessage.raw("Updating references in domain " +
1966                  domain.getBaseDN()+" on " + serverDisplay + "."));
1967              replServers.remove(replServer);
1968              if (!replServers.isEmpty())
1969              {
1970                domain.setReplicationServer(replServers);
1971                domain.commit();
1972              }
1973              else
1974              {
1975                sync.removeReplicationDomain(domainName);
1976                sync.commit();
1977              }
1978            }
1979          }
1980        }
1981      }
1982    }
1983    catch (ManagedObjectNotFoundException monfe)
1984    {
1985      // It does not exist.
1986      logger.info(LocalizableMessage.raw("No synchronization found on "+ serverDisplay+".",
1987          monfe));
1988    }
1989    catch (Throwable t)
1990    {
1991      logger.warn(LocalizableMessage.raw(
1992          "Error removing references in replication server on "+
1993          serverDisplay+": "+t, t));
1994      LocalizableMessage errorMessage = INFO_ERROR_CONFIGURING_REMOTE_GENERIC.get(
1995              serverDisplay, t);
1996      throw new ApplicationException(
1997          ReturnCode.CONFIGURATION_ERROR, errorMessage, t);
1998    }
1999    ADSContext adsContext = new ADSContext(connWrapper);
2000
2001    try
2002    {
2003      if (adsContext.hasAdminData() && serverADSProperties != null)
2004      {
2005        logger.info(LocalizableMessage.raw("Unregistering server on ADS of server " + connWrapper.getHostPort()
2006            + ".  Properties: " + serverADSProperties));
2007        adsContext.unregisterServer(serverADSProperties);
2008      }
2009    }
2010    catch (ADSContextException ace)
2011    {
2012      if (ace.getError() !=
2013        ADSContextException.ErrorType.NOT_YET_REGISTERED)
2014      {
2015        throw new ApplicationException(
2016            ReturnCode.CONFIGURATION_ERROR,
2017            INFO_REMOTE_ADS_EXCEPTION.get(serverDisplay, ace),
2018            ace);
2019      }
2020      else
2021      {
2022        // Nothing to do: this may occur if the new server has been
2023        // unregistered on another server and the modification has
2024        // been already propagated by replication.
2025      }
2026    }
2027  }
2028
2029  private String findReplicationServer(Set<String> replServers)
2030  {
2031    for (String s : replServers)
2032    {
2033      if (getUninstallUserData().getReplicationServer().equalsIgnoreCase(s))
2034      {
2035        return s;
2036      }
2037    }
2038    return null;
2039  }
2040
2041  /**
2042   * Tells whether this ServerDescriptor object represents the server that we
2043   * are trying to uninstall or not.
2044   * @param server the ServerDescriptor object to analyze.
2045   * @return <CODE>true</CODE> if the ServerDescriptor object represents the
2046   * server that we are trying to uninstall and <CODE>false</CODE> otherwise.
2047   */
2048  private boolean isServerToUninstall(ServerDescriptor server)
2049  {
2050    boolean isServerToUninstall = false;
2051    String path = (String)server.getAdsProperties().get(
2052        ADSContext.ServerProperty.INSTANCE_PATH);
2053    if (path == null)
2054    {
2055      // Compare the port of the URL we used.
2056      try
2057      {
2058        String usedUrl = getUninstallUserData().getLocalServerUrl();
2059        boolean isSecure = usedUrl.toLowerCase().startsWith("ldaps");
2060        URI uri = new URI(usedUrl);
2061        int port = uri.getPort();
2062        ServerDescriptor.ServerProperty property;
2063        if (isSecure)
2064        {
2065          property = ServerDescriptor.ServerProperty.ADMIN_PORT;
2066        }
2067        else
2068        {
2069          property = ServerDescriptor.ServerProperty.LDAP_PORT;
2070        }
2071        ArrayList<?> ports =
2072          (ArrayList<?>)server.getServerProperties().get(property);
2073        if (ports != null)
2074        {
2075          isServerToUninstall = ports.contains(port);
2076        }
2077        else
2078        {
2079          // This occurs if the instance could not be loaded.
2080          ADSContext.ServerProperty adsProperty;
2081          if (isSecure)
2082          {
2083            adsProperty = ADSContext.ServerProperty.ADMIN_PORT;
2084          }
2085          else
2086          {
2087            adsProperty = ADSContext.ServerProperty.LDAP_PORT;
2088          }
2089          String v = (String)server.getAdsProperties().get(adsProperty);
2090          if (v != null)
2091          {
2092            isServerToUninstall = v.equals(String.valueOf(port));
2093          }
2094        }
2095      }
2096      catch (Throwable t)
2097      {
2098        logger.warn(LocalizableMessage.raw("Failing checking the port: "+t, t));
2099      }
2100    }
2101    else
2102    {
2103      File f = new File(path);
2104      isServerToUninstall =
2105        f.equals(Installation.getLocal().getRootDirectory());
2106    }
2107
2108    if (isServerToUninstall)
2109    {
2110      // TODO: the host name comparison made here does not necessarily work in
2111      // all environments...
2112      String hostName = server.getHostName();
2113      boolean hostNameEquals =
2114        getUninstallUserData().getReferencedHostName().equals(hostName);
2115      try
2116      {
2117        InetAddress localAddress = InetAddress.getLocalHost();
2118        InetAddress[] addresses = InetAddress.getAllByName(hostName);
2119        for (int i=0; i<addresses.length && !hostNameEquals; i++)
2120        {
2121          hostNameEquals = localAddress.equals(addresses[i]);
2122        }
2123        if (!hostNameEquals)
2124        {
2125          hostNameEquals =
2126            localAddress.getHostName().equalsIgnoreCase(hostName) ||
2127            localAddress.getCanonicalHostName().equalsIgnoreCase(hostName);
2128        }
2129      }
2130      catch (Throwable t)
2131      {
2132        logger.warn(LocalizableMessage.raw("Failing checking host names: "+t, t));
2133      }
2134      isServerToUninstall = hostNameEquals;
2135    }
2136    return isServerToUninstall;
2137  }
2138
2139  /**
2140   * Returns the timeout to be used to connect in milliseconds.
2141   * @return the timeout to be used to connect in milliseconds.  Returns
2142   * {@code 0} if there is no timeout.
2143   */
2144  private int getConnectTimeout()
2145  {
2146    return getUserData().getConnectTimeout();
2147  }
2148}