001/*
002 * CDDL HEADER START
003 *
004 * The contents of this file are subject to the terms of the
005 * Common Development and Distribution License, Version 1.0 only
006 * (the "License").  You may not use this file except in compliance
007 * with the License.
008 *
009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
010 * or http://forgerock.org/license/CDDLv1.0.html.
011 * See the License for the specific language governing permissions
012 * and limitations under the License.
013 *
014 * When distributing Covered Code, include this CDDL HEADER in each
015 * file and include the License file at legal-notices/CDDLv1_0.txt.
016 * If applicable, add the following below this CDDL HEADER, with the
017 * fields enclosed by brackets "[]" replaced with your own identifying
018 * information:
019 *      Portions Copyright [yyyy] [name of copyright owner]
020 *
021 * CDDL HEADER END
022 *
023 *
024 *      Copyright 2006-2010 Sun Microsystems, Inc.
025 *      Portions Copyright 2014-2015 ForgeRock AS
026 */
027package org.opends.guitools.uninstaller;
028
029import static org.forgerock.util.Utils.*;
030import static org.opends.admin.ads.util.ConnectionUtils.*;
031import static org.opends.messages.AdminToolMessages.*;
032import static org.opends.messages.QuickSetupMessages.*;
033
034import static com.forgerock.opendj.cli.ArgumentConstants.*;
035import static com.forgerock.opendj.cli.Utils.*;
036
037import java.io.BufferedReader;
038import java.io.File;
039import java.io.FileReader;
040import java.io.IOException;
041import java.net.URI;
042import java.util.Collections;
043import java.util.HashSet;
044import java.util.LinkedHashSet;
045import java.util.Set;
046
047import javax.naming.NamingException;
048import javax.naming.NoPermissionException;
049import javax.naming.ldap.InitialLdapContext;
050import javax.net.ssl.TrustManager;
051
052import org.forgerock.i18n.LocalizableMessage;
053import org.forgerock.i18n.LocalizableMessageBuilder;
054import org.forgerock.i18n.slf4j.LocalizedLogger;
055import org.opends.admin.ads.ADSContext;
056import org.opends.admin.ads.ServerDescriptor;
057import org.opends.admin.ads.TopologyCache;
058import org.opends.admin.ads.TopologyCacheException;
059import org.opends.admin.ads.util.ApplicationTrustManager;
060import org.opends.admin.ads.util.ConnectionUtils;
061import org.opends.guitools.controlpanel.datamodel.ConnectionProtocolPolicy;
062import org.opends.guitools.controlpanel.datamodel.ControlPanelInfo;
063import org.opends.quicksetup.Application;
064import org.opends.quicksetup.ApplicationException;
065import org.opends.quicksetup.Configuration;
066import org.opends.quicksetup.Constants;
067import org.opends.quicksetup.Installation;
068import org.opends.quicksetup.ProgressStep;
069import org.opends.quicksetup.Step;
070import org.opends.quicksetup.UserDataException;
071import org.opends.quicksetup.event.ProgressUpdateEvent;
072import org.opends.quicksetup.event.ProgressUpdateListener;
073import org.opends.quicksetup.util.PlainTextProgressMessageFormatter;
074import org.opends.quicksetup.util.ServerController;
075import org.opends.quicksetup.util.Utils;
076import org.opends.server.admin.client.cli.SecureConnectionCliArgs;
077import org.opends.server.util.StaticUtils;
078import org.opends.server.util.cli.LDAPConnectionConsoleInteraction;
079
080import com.forgerock.opendj.cli.ArgumentException;
081import com.forgerock.opendj.cli.ClientException;
082import com.forgerock.opendj.cli.ConsoleApplication;
083import com.forgerock.opendj.cli.Menu;
084import com.forgerock.opendj.cli.MenuBuilder;
085import com.forgerock.opendj.cli.MenuResult;
086import com.forgerock.opendj.cli.ReturnCode;
087
088/**
089 * The class used to provide some CLI interface in the uninstall.
090 *
091 * This class basically is in charge of parsing the data provided by the user
092 * in the command line and displaying messages asking the user for information.
093 *
094 * Once the user has provided all the required information it calls Uninstaller
095 * and launches it.
096 *
097 */
098public class UninstallCliHelper extends ConsoleApplication {
099
100  private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
101
102  private UninstallerArgumentParser parser;
103  private LDAPConnectionConsoleInteraction ci;
104  private ControlPanelInfo info;
105
106  private boolean forceNonInteractive;
107  private boolean useSSL = true;
108  private boolean useStartTLS;
109
110  /**
111   * Default constructor.
112   */
113  public UninstallCliHelper()
114  {
115    // Nothing to do.
116  }
117
118  /**
119   * Creates a UserData based in the arguments provided. It asks user for
120   * additional information if what is provided in the arguments is not enough.
121   *
122   * @param args
123   *          the ArgumentParser with the allowed arguments of the command line.
124   *          The code assumes that the arguments have already been parsed.
125   * @param rawArguments
126   *          the arguments provided in the command line.
127   * @return the UserData object with what the user wants to uninstall and null
128   *         if the user cancels the uninstallation.
129   * @throws UserDataException
130   *           if there is an error with the data in the arguments.
131   * @throws ClientException
132   *           If there is an error processing data in non-interactive mode and
133   *           an error must be thrown (not in force on error mode).
134   */
135  public UninstallUserData createUserData(UninstallerArgumentParser args,
136      String[] rawArguments)
137  throws UserDataException, ClientException
138  {
139    parser = args;
140    UninstallUserData userData = new UninstallUserData();
141    try
142    {
143      boolean isInteractive;
144      boolean isQuiet;
145      boolean isVerbose;
146      boolean isCanceled = false;
147
148      /* Step 1: analyze the arguments.
149       */
150
151      isInteractive = args.isInteractive();
152
153      isQuiet = args.isQuiet();
154
155      isVerbose = args.isVerbose();
156
157      userData.setQuiet(isQuiet);
158      userData.setVerbose(isVerbose);
159      userData.setForceOnError(args.isForceOnError());
160      userData.setTrustManager(args.getTrustManager());
161
162      userData.setConnectTimeout(getConnectTimeout());
163
164      /*
165       * Step 2: check that the provided parameters are compatible.
166       */
167      LocalizableMessageBuilder buf = new LocalizableMessageBuilder();
168      int v = args.validateGlobalOptions(buf);
169      if (v != ReturnCode.SUCCESS.get())
170      {
171        throw new UserDataException(null, buf.toMessage());
172      }
173
174      /* Step 3: If this is an interactive uninstall ask for confirmation to
175       * delete the different parts of the installation if the user did not
176       * specify anything to delete.  If we are not in interactive mode
177       * check that the user specified something to be deleted.
178       */
179      Set<String> outsideDbs;
180      Set<String> outsideLogs;
181      Configuration config =
182        Installation.getLocal().getCurrentConfiguration();
183      try {
184        outsideDbs = config.getOutsideDbs();
185      } catch (IOException ioe) {
186        outsideDbs = Collections.emptySet();
187        logger.info(LocalizableMessage.raw("error determining outside databases", ioe));
188      }
189
190      try {
191        outsideLogs = config.getOutsideLogs();
192      } catch (IOException ioe) {
193        outsideLogs = Collections.emptySet();
194        logger.info(LocalizableMessage.raw("error determining outside logs", ioe));
195      }
196
197      boolean somethingSpecifiedToDelete =
198        args.removeAll() ||
199        args.removeBackupFiles() ||
200        args.removeDatabases() ||
201        args.removeLDIFFiles() ||
202        args.removeConfigurationFiles() ||
203        args.removeLogFiles() ||
204        args.removeServerLibraries();
205
206      if (somethingSpecifiedToDelete)
207      {
208        userData.setRemoveBackups(args.removeAll() || args.removeBackupFiles());
209        userData.setRemoveConfigurationAndSchema(args.removeAll() ||
210            args.removeConfigurationFiles());
211        userData.setRemoveDatabases(args.removeAll() || args.removeDatabases());
212        userData.setRemoveLDIFs(args.removeAll() || args.removeLDIFFiles());
213        userData.setRemoveLibrariesAndTools(args.removeAll() ||
214            args.removeServerLibraries());
215        userData.setRemoveLogs(args.removeAll() || args.removeLogFiles());
216
217        userData.setExternalDbsToRemove(outsideDbs);
218        userData.setExternalLogsToRemove(outsideLogs);
219      }
220      else if (!isInteractive)
221      {
222        throw new UserDataException(null,
223           ERR_CLI_UNINSTALL_NOTHING_TO_BE_UNINSTALLED_NON_INTERACTIVE.get());
224      }
225      else
226      {
227        isCanceled = askWhatToDelete(userData, outsideDbs, outsideLogs);
228      }
229      String adminUid = args.getAdministratorUID();
230      if (adminUid == null && !args.isInteractive())
231      {
232        adminUid = args.getDefaultAdministratorUID();
233      }
234      userData.setAdminUID(adminUid);
235      userData.setAdminPwd(args.getBindPassword());
236      String referencedHostName = args.getReferencedHostName();
237      if (referencedHostName == null && !args.isInteractive())
238      {
239        referencedHostName = args.getDefaultReferencedHostName();
240      }
241      try
242      {
243        UninstallData d = new UninstallData(Installation.getLocal());
244        userData.setReplicationServer(
245            referencedHostName+":"+d.getReplicationServerPort());
246      }
247      catch (Throwable t)
248      {
249        logger.error(LocalizableMessage.raw("Could not create UninstallData: "+t, t));
250        userData.setReplicationServer(
251            referencedHostName+":8989");
252      }
253      info = ControlPanelInfo.getInstance();
254      info.setTrustManager(userData.getTrustManager());
255      info.setConnectTimeout(getConnectTimeout());
256      info.regenerateDescriptor();
257      info.setConnectionPolicy(ConnectionProtocolPolicy.USE_ADMIN);
258
259      String adminConnectorUrl = info.getAdminConnectorURL();
260
261      if (adminConnectorUrl == null)
262      {
263        logger.warn(LocalizableMessage.raw(
264        "Error retrieving a valid LDAP URL in conf file."));
265        if (!parser.isInteractive())
266        {
267          LocalizableMessage msg = ERR_COULD_NOT_FIND_VALID_LDAPURL.get();
268          throw new ClientException(ReturnCode.APPLICATION_ERROR, msg);
269        }
270      }
271      userData.setLocalServerUrl(adminConnectorUrl);
272      userData.setReferencedHostName(referencedHostName);
273
274      /*
275       * Step 4: check if server is running.  Depending if it is running and the
276       * OS we are running, ask for authentication information.
277       */
278      if (!isCanceled)
279      {
280        isCanceled = checkServerState(userData);
281      }
282
283      if (isCanceled && !userData.isForceOnError())
284      {
285        logger.info(LocalizableMessage.raw("User cancelled uninstall."));
286        userData = null;
287      }
288
289      if (userData != null && !args.isQuiet())
290      {
291        println();
292      }
293    }
294    catch (Throwable t)
295    {
296      logger.warn(LocalizableMessage.raw("Exception: "+t, t));
297      if (t instanceof UserDataException)
298      {
299        throw (UserDataException)t;
300      }
301      else if (t instanceof ClientException)
302      {
303        throw (ClientException)t;
304      }
305      else
306      {
307        throw new IllegalStateException("Unexpected error: "+t, t);
308      }
309    }
310    logger.info(LocalizableMessage.raw("Successfully created user data"));
311    return userData;
312  }
313
314  /**
315   * Commodity method used to ask the user to confirm the deletion of certain
316   * parts of the server.  It updates the provided UserData object
317   * accordingly.  Returns <CODE>true</CODE> if the user cancels and <CODE>
318   * false</CODE> otherwise.
319   * @param userData the UserData object to be updated.
320   * @param outsideDbs the set of relative paths of databases located outside
321   * the installation path of the server.
322   * @param outsideLogs the set of relative paths of log files located outside
323   * the installation path of the server.
324   * @return <CODE>true</CODE> if the user cancels and <CODE>false</CODE>
325   * otherwise.
326   */
327  private boolean askWhatToDelete(UninstallUserData userData,
328      Set<String> outsideDbs, Set<String> outsideLogs) throws UserDataException
329  {
330    boolean cancelled = false;
331    final int REMOVE_ALL = 1;
332    final int SPECIFY_TO_REMOVE = 2;
333    int[] indexes = {REMOVE_ALL, SPECIFY_TO_REMOVE};
334    LocalizableMessage[] msgs = new LocalizableMessage[] {
335        INFO_CLI_UNINSTALL_REMOVE_ALL.get(),
336        INFO_CLI_UNINSTALL_SPECIFY_WHAT_REMOVE.get()
337      };
338
339    MenuBuilder<Integer> builder = new MenuBuilder<>(this);
340    builder.setPrompt(INFO_CLI_UNINSTALL_WHAT_TO_DELETE.get());
341
342    for (int i=0; i<indexes.length; i++)
343    {
344      builder.addNumberedOption(msgs[i], MenuResult.success(indexes[i]));
345    }
346
347    builder.addQuitOption();
348
349    builder.setDefault(LocalizableMessage.raw(String.valueOf(REMOVE_ALL)),
350        MenuResult.success(REMOVE_ALL));
351
352    builder.setMaxTries(CONFIRMATION_MAX_TRIES);
353
354    Menu<Integer> menu = builder.toMenu();
355    int choice;
356    try
357    {
358      MenuResult<Integer> m = menu.run();
359      if (m.isSuccess())
360      {
361        choice = m.getValue();
362      }
363      else if (m.isQuit())
364      {
365        choice = REMOVE_ALL;
366        cancelled = true;
367      }
368      else
369      {
370        // Should never happen.
371        throw new RuntimeException();
372      }
373    }
374    catch (ClientException ce)
375    {
376      logger.warn(LocalizableMessage.raw("Error reading input: "+ce, ce));
377      throw new UserDataException(null, ce.getMessageObject(), ce);
378    }
379
380    if (cancelled)
381    {
382      // Nothing to do
383    }
384    else if (choice == REMOVE_ALL)
385    {
386      userData.setRemoveBackups(true);
387      userData.setRemoveConfigurationAndSchema(true);
388      userData.setRemoveDatabases(true);
389      userData.setRemoveLDIFs(true);
390      userData.setRemoveLibrariesAndTools(true);
391      userData.setRemoveLogs(true);
392
393      userData.setExternalDbsToRemove(outsideDbs);
394      userData.setExternalLogsToRemove(outsideLogs);
395    }
396    else
397    {
398      boolean somethingSelected = false;
399      while (!somethingSelected && !cancelled)
400      {
401        println();
402//      Ask for confirmation for the different items
403        msgs = new LocalizableMessage [] {
404                INFO_CLI_UNINSTALL_CONFIRM_LIBRARIES_BINARIES.get(),
405                INFO_CLI_UNINSTALL_CONFIRM_DATABASES.get(),
406                INFO_CLI_UNINSTALL_CONFIRM_LOGS.get(),
407                INFO_CLI_UNINSTALL_CONFIRM_CONFIGURATION_SCHEMA.get(),
408                INFO_CLI_UNINSTALL_CONFIRM_BACKUPS.get(),
409                INFO_CLI_UNINSTALL_CONFIRM_LDIFS.get(),
410                INFO_CLI_UNINSTALL_CONFIRM_OUTSIDEDBS.get(
411                        joinAsString(Constants.LINE_SEPARATOR, outsideDbs)),
412                INFO_CLI_UNINSTALL_CONFIRM_OUTSIDELOGS.get(
413                        joinAsString(Constants.LINE_SEPARATOR, outsideLogs)
414                )
415        };
416
417        boolean[] answers = new boolean[msgs.length];
418        try
419        {
420          for (int i=0; i<msgs.length; i++)
421          {
422            boolean ignore = (i == 6 && outsideDbs.isEmpty())
423                || (i == 7 && outsideLogs.isEmpty());
424            if (!ignore)
425            {
426              answers[i] = askConfirmation(msgs[i], true, logger);
427            }
428            else
429            {
430              answers[i] = false;
431            }
432          }
433        }
434        catch (ClientException ce)
435        {
436          throw new UserDataException(null, ce.getMessageObject(), ce);
437        }
438
439        if (!cancelled)
440        {
441          for (int i=0; i<answers.length; i++)
442          {
443            switch (i)
444            {
445            case 0:
446              userData.setRemoveLibrariesAndTools(answers[i]);
447              break;
448
449            case 1:
450              userData.setRemoveDatabases(answers[i]);
451              break;
452
453            case 2:
454              userData.setRemoveLogs(answers[i]);
455              break;
456
457            case 3:
458              userData.setRemoveConfigurationAndSchema(answers[i]);
459              break;
460
461            case 4:
462              userData.setRemoveBackups(answers[i]);
463              break;
464
465            case 5:
466              userData.setRemoveLDIFs(answers[i]);
467              break;
468
469            case 6:
470              if (answers[i])
471              {
472                userData.setExternalDbsToRemove(outsideDbs);
473              }
474              break;
475
476            case 7:
477              if (answers[i])
478              {
479                userData.setExternalLogsToRemove(outsideLogs);
480              }
481              break;
482            }
483          }
484          if (userData.getExternalDbsToRemove().isEmpty() &&
485              userData.getExternalLogsToRemove().isEmpty() &&
486              !userData.getRemoveLibrariesAndTools() &&
487              !userData.getRemoveDatabases() &&
488              !userData.getRemoveConfigurationAndSchema() &&
489              !userData.getRemoveBackups() &&
490              !userData.getRemoveLDIFs() &&
491              !userData.getRemoveLogs())
492          {
493            somethingSelected = false;
494            println();
495            printErrorMessage(
496                ERR_CLI_UNINSTALL_NOTHING_TO_BE_UNINSTALLED.get());
497          }
498          else
499          {
500            somethingSelected = true;
501          }
502        }
503      }
504    }
505
506    return cancelled;
507  }
508
509  /**
510   * Commodity method used to ask the user (when necessary) if the server must
511   * be stopped or not. It also prompts (if required) for authentication.
512   *
513   * @param userData
514   *          the UserData object to be updated with the authentication of the
515   *          user.
516   * @return <CODE>true</CODE> if the user wants to continue with uninstall and
517   *         <CODE>false</CODE> otherwise.
518   * @throws UserDataException
519   *           if there is a problem with the data provided by the user (in the
520   *           particular case where we are on non-interactive uninstall and
521   *           some data is missing or not valid).
522   * @throws ClientException
523   *           If there is an error processing data in non-interactive mode and
524   *           an error must be thrown (not in force on error mode).
525   */
526  private boolean checkServerState(UninstallUserData userData)
527  throws UserDataException, ClientException
528  {
529    boolean cancelled = false;
530    boolean interactive = parser.isInteractive();
531    boolean forceOnError = parser.isForceOnError();
532    UninstallData conf = null;
533    try
534    {
535      conf = new UninstallData(Installation.getLocal());
536    }
537    catch (Throwable t)
538    {
539      logger.warn(LocalizableMessage.raw("Error processing task: "+t, t));
540      throw new UserDataException(Step.CONFIRM_UNINSTALL,
541          getThrowableMsg(INFO_BUG_MSG.get(), t));
542    }
543    logger.info(LocalizableMessage.raw("interactive: "+interactive));
544    logger.info(LocalizableMessage.raw("forceOnError: "+forceOnError));
545    logger.info(LocalizableMessage.raw("conf.isADS(): "+conf.isADS()));
546    logger.info(LocalizableMessage.raw("conf.isReplicationServer(): "+
547        conf.isReplicationServer()));
548    logger.info(LocalizableMessage.raw("conf.isServerRunning(): "+conf.isServerRunning()));
549    if (conf.isADS() && conf.isReplicationServer())
550    {
551      if (conf.isServerRunning())
552      {
553        if (interactive)
554        {
555          try
556          {
557            println();
558            if (confirmToUpdateRemote())
559            {
560              cancelled = !askForAuthenticationIfNeeded(userData);
561              if (cancelled)
562              {
563                /* Ask for confirmation to stop server */
564                println();
565                cancelled = !confirmToStopServer();
566              }
567              else
568              {
569                cancelled = !updateUserUninstallDataWithRemoteServers(userData);
570                if (cancelled)
571                {
572                  println();
573                  /* Ask for confirmation to stop server */
574                  cancelled = !confirmToStopServer();
575                }
576              }
577            }
578            else
579            {
580              /* Ask for confirmation to stop server */
581              cancelled = !confirmToStopServer();
582            }
583          }
584          catch (ClientException ce)
585          {
586            throw new UserDataException(null, ce.getMessageObject(), ce);
587          }
588        }
589        else
590        {
591          boolean errorWithRemote =
592            !updateUserUninstallDataWithRemoteServers(userData);
593          cancelled = errorWithRemote && !parser.isForceOnError();
594          logger.info(LocalizableMessage.raw("Non interactive mode.  errorWithRemote: "+
595              errorWithRemote));
596        }
597      }
598      else if (interactive)
599      {
600        println();
601        try
602        {
603          if (confirmToUpdateRemoteAndStart())
604          {
605            boolean startWorked = startServer(userData.isQuiet());
606            // Ask for authentication if needed, etc.
607            if (startWorked)
608            {
609              cancelled = !askForAuthenticationIfNeeded(userData);
610              if (cancelled)
611              {
612                println();
613                /* Ask for confirmation to stop server */
614                cancelled = !confirmToStopServer();
615              }
616              else
617              {
618                cancelled =
619                  !updateUserUninstallDataWithRemoteServers(userData);
620                if (cancelled)
621                {
622                  println();
623                  /* Ask for confirmation to stop server */
624                  cancelled = !confirmToStopServer();
625                }
626              }
627              userData.setStopServer(true);
628            }
629            else
630            {
631              userData.setStopServer(false);
632              println();
633              /* Ask for confirmation to delete files */
634              cancelled = !confirmDeleteFiles();
635            }
636          }
637          else
638          {
639            println();
640            /* Ask for confirmation to delete files */
641            cancelled = !confirmDeleteFiles();
642          }
643        }
644        catch (ClientException ce)
645        {
646          throw new UserDataException(null, ce.getMessageObject(), ce);
647        }
648      }
649      else
650      {
651        boolean startWorked = startServer(userData.isQuiet());
652        // Ask for authentication if needed, etc.
653        if (startWorked)
654        {
655          userData.setStopServer(true);
656          boolean errorWithRemote =
657            !updateUserUninstallDataWithRemoteServers(userData);
658          cancelled = errorWithRemote && !parser.isForceOnError();
659        }
660        else
661        {
662          cancelled  = !forceOnError;
663          userData.setStopServer(false);
664        }
665      }
666      if (!cancelled || parser.isForceOnError())
667      {
668        /* During all the confirmations, the server might be stopped. */
669        userData.setStopServer(
670            Installation.getLocal().getStatus().isServerRunning());
671        logger.info(LocalizableMessage.raw("Must stop the server after confirmations? "+
672            userData.getStopServer()));
673      }
674    }
675    else if (conf.isServerRunning())
676    {
677      try
678      {
679        if (interactive)
680        {
681          println();
682          /* Ask for confirmation to stop server */
683          cancelled = !confirmToStopServer();
684        }
685
686        if (!cancelled)
687        {
688          /* During all the confirmations, the server might be stopped. */
689          userData.setStopServer(
690              Installation.getLocal().getStatus().isServerRunning());
691          logger.info(LocalizableMessage.raw("Must stop the server after confirmations? "+
692              userData.getStopServer()));
693        }
694      }
695      catch (ClientException ce)
696      {
697        throw new UserDataException(null, ce.getMessageObject(), ce);
698      }
699    }
700    else
701    {
702      userData.setStopServer(false);
703      if (interactive)
704      {
705        println();
706        /* Ask for confirmation to delete files */
707        try
708        {
709          cancelled = !confirmDeleteFiles();
710        }
711        catch (ClientException ce)
712        {
713          throw new UserDataException(null, ce.getMessageObject(), ce);
714        }
715      }
716    }
717    logger.info(LocalizableMessage.raw("cancelled: "+cancelled));
718    return cancelled;
719  }
720
721  /**
722   *  Ask for confirmation to stop server.
723   *  @return <CODE>true</CODE> if the user wants to continue and stop the
724   *  server.  <CODE>false</CODE> otherwise.
725   *  @throws ClientException if the user reached the confirmation limit.
726   */
727  private boolean confirmToStopServer() throws ClientException
728  {
729    return askConfirmation(INFO_CLI_UNINSTALL_CONFIRM_STOP.get(), true, logger);
730  }
731
732  /**
733   *  Ask for confirmation to delete files.
734   *  @return <CODE>true</CODE> if the user wants to continue and delete the
735   *  files.  <CODE>false</CODE> otherwise.
736   *  @throws ClientException if the user reached the confirmation limit.
737   */
738  private boolean confirmDeleteFiles() throws ClientException
739  {
740    return askConfirmation(INFO_CLI_UNINSTALL_CONFIRM_DELETE_FILES.get(), true,
741        logger);
742  }
743
744  /**
745   *  Ask for confirmation to update configuration on remote servers.
746   *  @return <CODE>true</CODE> if the user wants to continue and stop the
747   *  server.  <CODE>false</CODE> otherwise.
748   *  @throws ClientException if the user reached the confirmation limit.
749   */
750  private boolean confirmToUpdateRemote() throws ClientException
751  {
752    return askConfirmation(INFO_CLI_UNINSTALL_CONFIRM_UPDATE_REMOTE.get(), true,
753        logger);
754  }
755
756  /**
757   *  Ask for confirmation to update configuration on remote servers.
758   *  @return <CODE>true</CODE> if the user wants to continue and stop the
759   *  server.  <CODE>false</CODE> otherwise.
760   *  @throws ClientException if the user reached the confirmation limit.
761   */
762  private boolean confirmToUpdateRemoteAndStart() throws ClientException
763  {
764    return askConfirmation(
765        INFO_CLI_UNINSTALL_CONFIRM_UPDATE_REMOTE_AND_START.get(), true, logger);
766  }
767
768  /**
769   *  Ask for confirmation to provide again authentication.
770   *  @return <CODE>true</CODE> if the user wants to provide authentication
771   *  again.  <CODE>false</CODE> otherwise.
772   *  @throws ClientException if the user reached the confirmation limit.
773   */
774  private boolean promptToProvideAuthenticationAgain() throws ClientException
775  {
776    return askConfirmation(
777        INFO_UNINSTALL_CONFIRM_PROVIDE_AUTHENTICATION_AGAIN.get(), true, logger);
778  }
779
780  /**
781   * Ask for data required to update configuration on remote servers. If all the
782   * data is provided and validated, we assume that the user wants to update the
783   * remote servers.
784   *
785   * @return <CODE>true</CODE> if the user wants to continue and update the
786   *         remote servers. <CODE>false</CODE> otherwise.
787   * @throws UserDataException
788   *           if there is a problem with the information provided by the user.
789   * @throws ClientException
790   *           If there is an error processing data.
791   */
792  private boolean askForAuthenticationIfNeeded(UninstallUserData userData)
793  throws UserDataException, ClientException
794  {
795    boolean accepted = true;
796    String uid = userData.getAdminUID();
797    String pwd = userData.getAdminPwd();
798
799    boolean couldConnect = false;
800
801    while (!couldConnect && accepted)
802    {
803
804      // This is done because we do not need to ask the user about these
805      // parameters.  If we force their presence the class
806      // LDAPConnectionConsoleInteraction will not prompt the user for
807      // them.
808      SecureConnectionCliArgs secureArgsList = parser.getSecureArgsList();
809
810      secureArgsList.hostNameArg.setPresent(true);
811      secureArgsList.portArg.setPresent(true);
812      secureArgsList.hostNameArg.clearValues();
813      secureArgsList.hostNameArg.addValue(
814          secureArgsList.hostNameArg.getDefaultValue());
815      secureArgsList.portArg.clearValues();
816      secureArgsList.portArg.addValue(
817          secureArgsList.portArg.getDefaultValue());
818      secureArgsList.bindDnArg.clearValues();
819      if (uid != null)
820      {
821        secureArgsList.bindDnArg.addValue(ADSContext.getAdministratorDN(uid));
822        secureArgsList.bindDnArg.setPresent(true);
823      }
824      else
825      {
826        secureArgsList.bindDnArg.setPresent(false);
827      }
828      secureArgsList.bindPasswordArg.clearValues();
829      if (pwd != null)
830      {
831        secureArgsList.bindPasswordArg.addValue(pwd);
832        secureArgsList.bindPasswordArg.setPresent(true);
833      }
834      else
835      {
836        secureArgsList.bindPasswordArg.setPresent(false);
837      }
838
839      if (ci == null)
840      {
841        ci =
842        new LDAPConnectionConsoleInteraction(this, parser.getSecureArgsList());
843        ci.setDisplayLdapIfSecureParameters(true);
844      }
845
846      try
847      {
848        ci.run(false);
849        userData.setAdminUID(ci.getAdministratorUID());
850        userData.setAdminPwd(ci.getBindPassword());
851
852        info.setConnectionPolicy(ConnectionProtocolPolicy.USE_ADMIN);
853
854        String adminConnectorUrl = info.getAdminConnectorURL();
855        if (adminConnectorUrl == null)
856        {
857          logger.warn(LocalizableMessage.raw(
858         "Error retrieving a valid Administration Connector URL in conf file."));
859          LocalizableMessage msg = ERR_COULD_NOT_FIND_VALID_LDAPURL.get();
860            throw new ClientException(ReturnCode.APPLICATION_ERROR, msg);
861        }
862        try
863        {
864          URI uri = new URI(adminConnectorUrl);
865          int port = uri.getPort();
866          secureArgsList.portArg.clearValues();
867          secureArgsList.portArg.addValue(String.valueOf(port));
868          ci.setPortNumber(port);
869        }
870        catch (Throwable t)
871        {
872          logger.error(LocalizableMessage.raw("Error parsing url: "+adminConnectorUrl));
873        }
874        updateTrustManager(userData, ci);
875
876        info.setConnectionPolicy(ConnectionProtocolPolicy.USE_ADMIN);
877
878        adminConnectorUrl = info.getAdminConnectorURL();
879
880        if (adminConnectorUrl == null)
881        {
882          logger.warn(LocalizableMessage.raw(
883         "Error retrieving a valid Administration Connector URL in conf file."));
884          LocalizableMessage msg = ERR_COULD_NOT_FIND_VALID_LDAPURL.get();
885          throw new ClientException(ReturnCode.APPLICATION_ERROR, msg);
886        }
887
888        userData.setLocalServerUrl(adminConnectorUrl);
889        couldConnect = true;
890      }
891      catch (ArgumentException e)
892      {
893        parser.displayMessageAndUsageReference(getErrStream(), e.getMessageObject());
894      }
895      catch (ClientException e) {
896        printErrorMessage(e.getMessageObject());
897        println();
898      }
899
900      if (!couldConnect)
901      {
902        try
903        {
904          accepted = promptToProvideAuthenticationAgain();
905          if (accepted)
906          {
907            uid = null;
908            pwd = null;
909          }
910        }
911        catch (ClientException ce)
912        {
913          throw new UserDataException(null, ce.getMessageObject(), ce);
914        }
915      }
916    }
917
918    if (accepted)
919    {
920      String referencedHostName = parser.getReferencedHostName();
921      while (referencedHostName == null)
922      {
923        println();
924        referencedHostName = askForReferencedHostName(userData.getHostName());
925      }
926      try
927      {
928        UninstallData d = new UninstallData(Installation.getLocal());
929        userData.setReplicationServer(
930            referencedHostName+":"+d.getReplicationServerPort());
931        userData.setReferencedHostName(referencedHostName);
932      }
933      catch (Throwable t)
934      {
935        logger.error(LocalizableMessage.raw("Could not create UninstallData: "+t, t));
936      }
937    }
938    userData.setUpdateRemoteReplication(accepted);
939    return accepted;
940  }
941
942  private String askForReferencedHostName(String defaultHostName)
943  {
944    String s = defaultHostName;
945    try
946    {
947      s = readInput(INFO_UNINSTALL_CLI_REFERENCED_HOSTNAME_PROMPT.get(),
948          defaultHostName);
949    }
950    catch (ClientException ce)
951    {
952      logger.warn(LocalizableMessage.raw("Error reading input: %s", ce), ce);
953    }
954    return s;
955  }
956
957  private boolean startServer(boolean suppressOutput)
958  {
959    logger.info(LocalizableMessage.raw("startServer, suppressOutput: " + suppressOutput));
960    boolean serverStarted = false;
961    Application application = new Application()
962    {
963      /** {@inheritDoc} */
964      @Override
965      public String getInstallationPath()
966      {
967        return Installation.getLocal().getRootDirectory().getAbsolutePath();
968      }
969      /** {@inheritDoc} */
970      @Override
971      public String getInstancePath()
972      {
973        String installPath =  getInstallationPath();
974
975        // look for <installPath>/lib/resource.loc
976        String instancePathFileName = installPath + File.separator + "lib"
977        + File.separator + "resource.loc";
978        File f = new File(instancePathFileName);
979
980        if (! f.exists())
981        {
982          return installPath;
983        }
984
985        BufferedReader reader;
986        try
987        {
988          reader = new BufferedReader(new FileReader(instancePathFileName));
989        }
990        catch (Exception e)
991        {
992          return installPath;
993        }
994
995
996        // Read the first line and close the file.
997        String line;
998        try
999        {
1000          line = reader.readLine();
1001          return new File(line).getAbsolutePath();
1002        }
1003        catch (Exception e)
1004        {
1005          return installPath;
1006        }
1007        finally
1008        {
1009          StaticUtils.close(reader);
1010        }
1011      }
1012      /** {@inheritDoc} */
1013      @Override
1014      public ProgressStep getCurrentProgressStep()
1015      {
1016        return UninstallProgressStep.NOT_STARTED;
1017      }
1018      /** {@inheritDoc} */
1019      @Override
1020      public Integer getRatio(ProgressStep step)
1021      {
1022        return 0;
1023      }
1024      /** {@inheritDoc} */
1025      @Override
1026      public LocalizableMessage getSummary(ProgressStep step)
1027      {
1028        return null;
1029      }
1030      /** {@inheritDoc} */
1031      @Override
1032      public boolean isFinished()
1033      {
1034        return false;
1035      }
1036      /** {@inheritDoc} */
1037      @Override
1038      public boolean isCancellable()
1039      {
1040        return false;
1041      }
1042      /** {@inheritDoc} */
1043      @Override
1044      public void cancel()
1045      {
1046      }
1047      /** {@inheritDoc} */
1048      @Override
1049      public void run()
1050      {
1051      }
1052    };
1053    application.setProgressMessageFormatter(
1054        new PlainTextProgressMessageFormatter());
1055    if (!suppressOutput)
1056    {
1057      application.addProgressUpdateListener(
1058          new ProgressUpdateListener() {
1059            @Override
1060            public void progressUpdate(ProgressUpdateEvent ev) {
1061              System.out.print(ev.getNewLogs().toString());
1062              System.out.flush();
1063            }
1064          });
1065    }
1066    ServerController controller = new ServerController(application,
1067        Installation.getLocal());
1068    try
1069    {
1070      if (!suppressOutput)
1071      {
1072        println();
1073      }
1074      controller.startServer(suppressOutput);
1075      if (!suppressOutput)
1076      {
1077        println();
1078      }
1079      serverStarted = Installation.getLocal().getStatus().isServerRunning();
1080      logger.info(LocalizableMessage.raw("server started successfully. serverStarted: "+
1081          serverStarted));
1082    }
1083    catch (ApplicationException ae)
1084    {
1085      logger.warn(LocalizableMessage.raw("ApplicationException: "+ae, ae));
1086      if (!suppressOutput)
1087      {
1088        printErrorMessage(ae.getMessageObject());
1089      }
1090    }
1091    catch (Throwable t)
1092    {
1093      logger.error(LocalizableMessage.raw("Unexpected error: "+t, t));
1094      throw new IllegalStateException("Unexpected error: "+t, t);
1095    }
1096    return serverStarted;
1097  }
1098
1099  /**
1100   * Returns an InitialLdapContext using the provided parameters. We try to
1101   * guarantee that the connection is able to read the configuration.
1102   *
1103   * @param host
1104   *          the host name.
1105   * @param port
1106   *          the port to connect.
1107   * @param useSSL
1108   *          whether to use SSL or not.
1109   * @param useStartTLS
1110   *          whether to use StartTLS or not.
1111   * @param bindDn
1112   *          the bind dn to be used.
1113   * @param pwd
1114   *          the password.
1115   * @param connectTimeout
1116   *          the timeout in milliseconds to connect to the server.
1117   * @param trustManager
1118   *          the trust manager.
1119   * @return an InitialLdapContext connected.
1120   * @throws NamingException
1121   *           if there was an error establishing the connection.
1122   */
1123  private InitialLdapContext createAdministrativeContext(String host,
1124      int port, boolean useSSL, boolean useStartTLS, String bindDn, String pwd,
1125      int connectTimeout, ApplicationTrustManager trustManager)
1126      throws NamingException
1127  {
1128    InitialLdapContext ctx;
1129    String ldapUrl = ConnectionUtils.getLDAPUrl(host, port, useSSL);
1130    if (useSSL)
1131    {
1132      ctx = createLdapsContext(ldapUrl, bindDn, pwd, connectTimeout, null, trustManager, null);
1133    }
1134    else if (useStartTLS)
1135    {
1136      ctx =
1137          Utils.createStartTLSContext(ldapUrl, bindDn, pwd, connectTimeout,
1138              null, trustManager, null);
1139    }
1140    else
1141    {
1142      ctx = createLdapContext(ldapUrl, bindDn, pwd, connectTimeout, null);
1143    }
1144    if (!ConnectionUtils.connectedAsAdministrativeUser(ctx))
1145    {
1146      throw new NoPermissionException(ERR_NOT_ADMINISTRATIVE_USER.get()
1147          .toString());
1148    }
1149    return ctx;
1150  }
1151
1152  /**
1153   * Updates the contents of the UninstallUserData while trying to connect to
1154   * the remote servers. It returns <CODE>true</CODE> if we could connect to the
1155   * remote servers and all the presented certificates were accepted and
1156   * <CODE>false</CODE> otherwise. continue if
1157   *
1158   * @param userData
1159   *          the user data to be updated.
1160   * @return <CODE>true</CODE> if we could connect to the remote servers and all
1161   *         the presented certificates were accepted and <CODE>false</CODE>
1162   *         otherwise.
1163   * @throws UserDataException
1164   *           if were are not in interactive mode and not in force on error
1165   *           mode and the operation must be stopped.
1166   * @throws ClientException
1167   *           If there is an error processing data in non-interactive mode and
1168   *           an error must be thrown (not in force on error mode).
1169   */
1170  private boolean updateUserUninstallDataWithRemoteServers(
1171      UninstallUserData userData) throws UserDataException, ClientException
1172  {
1173    boolean accepted = false;
1174    boolean interactive = parser.isInteractive();
1175    boolean forceOnError = parser.isForceOnError();
1176
1177    boolean exceptionOccurred = true;
1178
1179    LocalizableMessage exceptionMsg = null;
1180
1181    logger.info(LocalizableMessage.raw("Updating user data with remote servers."));
1182
1183    InitialLdapContext ctx = null;
1184    try
1185    {
1186      info.setTrustManager(userData.getTrustManager());
1187      info.setConnectTimeout(getConnectTimeout());
1188      String host = "localhost";
1189      int port = 389;
1190      String adminUid = userData.getAdminUID();
1191      String pwd = userData.getAdminPwd();
1192      String dn = ADSContext.getAdministratorDN(adminUid);
1193
1194      info.setConnectionPolicy(ConnectionProtocolPolicy.USE_ADMIN);
1195      String adminConnectorUrl = info.getAdminConnectorURL();
1196      try
1197      {
1198        URI uri = new URI(adminConnectorUrl);
1199        host = uri.getHost();
1200        port = uri.getPort();
1201      }
1202      catch (Throwable t)
1203      {
1204        logger.error(LocalizableMessage.raw("Error parsing url: "+adminConnectorUrl));
1205      }
1206      ctx = createAdministrativeContext(host, port, useSSL, useStartTLS, dn,
1207          pwd, getConnectTimeout(),
1208          userData.getTrustManager());
1209
1210      ADSContext adsContext = new ADSContext(ctx);
1211      if (interactive && userData.getTrustManager() == null)
1212      {
1213        // This is required when the user did  connect to the server using SSL
1214        // or Start TLS in interactive mode.  In this case
1215        // LDAPConnectionInteraction.run does not initialize the keystore and
1216        // the trust manager is null.
1217        forceTrustManagerInitialization();
1218        updateTrustManager(userData, ci);
1219      }
1220      logger.info(LocalizableMessage.raw("Reloading topology"));
1221      TopologyCache cache = new TopologyCache(adsContext,
1222          userData.getTrustManager(), getConnectTimeout());
1223      cache.getFilter().setSearchMonitoringInformation(false);
1224      cache.reloadTopology();
1225
1226      accepted = handleTopologyCache(cache, userData);
1227
1228      exceptionOccurred = false;
1229    }
1230    catch (NamingException ne)
1231    {
1232      logger.warn(LocalizableMessage.raw("Error connecting to server: "+ne, ne));
1233      if (isCertificateException(ne))
1234      {
1235        String details = ne.getMessage() != null ?
1236            ne.getMessage() : ne.toString();
1237        exceptionMsg = INFO_ERROR_READING_CONFIG_LDAP_CERTIFICATE.get(details);
1238      }
1239      else
1240      {
1241        exceptionMsg = getThrowableMsg(INFO_ERROR_CONNECTING_TO_LOCAL.get(), ne);
1242      }
1243    } catch (TopologyCacheException te)
1244    {
1245      logger.warn(LocalizableMessage.raw("Error connecting to server: "+te, te));
1246      exceptionMsg = Utils.getMessage(te);
1247
1248    } catch (ClientException ce)
1249    {
1250      throw ce;
1251
1252    } catch (Throwable t)
1253    {
1254      logger.warn(LocalizableMessage.raw("Error connecting to server: "+t, t));
1255      exceptionMsg = getThrowableMsg(INFO_BUG_MSG.get(), t);
1256    }
1257    finally
1258    {
1259      StaticUtils.close(ctx);
1260    }
1261    if (exceptionOccurred)
1262    {
1263      if (!interactive)
1264      {
1265        if (forceOnError)
1266        {
1267          println();
1268          printErrorMessage(ERR_UNINSTALL_ERROR_UPDATING_REMOTE_FORCE.get(
1269              "--"+parser.getSecureArgsList().adminUidArg.getLongIdentifier(),
1270              "--"+OPTION_LONG_BINDPWD,
1271              "--"+OPTION_LONG_BINDPWD_FILE,
1272              exceptionMsg));
1273        }
1274        else
1275        {
1276          println();
1277          throw new UserDataException(null,
1278              ERR_UNINSTALL_ERROR_UPDATING_REMOTE_NO_FORCE.get(
1279                  "--"+
1280                  parser.getSecureArgsList().adminUidArg.getLongIdentifier(),
1281                  "--"+OPTION_LONG_BINDPWD,
1282                  "--"+OPTION_LONG_BINDPWD_FILE,
1283                  "--"+parser.forceOnErrorArg.getLongIdentifier(),
1284                  exceptionMsg));
1285        }
1286      }
1287      else
1288      {
1289        try
1290        {
1291          accepted = askConfirmation(
1292              ERR_UNINSTALL_NOT_UPDATE_REMOTE_PROMPT.get(),
1293              false, logger);
1294        }
1295        catch (ClientException ce)
1296        {
1297          throw new UserDataException(null, ce.getMessageObject(), ce);
1298        }
1299      }
1300    }
1301    userData.setUpdateRemoteReplication(accepted);
1302    logger.info(LocalizableMessage.raw("accepted: "+accepted));
1303    return accepted;
1304  }
1305
1306  /**
1307   * Method that interacts with the user depending on what errors where
1308   * encountered in the TopologyCache object.  This method assumes that the
1309   * TopologyCache has been reloaded.
1310   * Returns <CODE>true</CODE> if the user accepts all the problems encountered
1311   * and <CODE>false</CODE> otherwise.
1312   * @param userData the user data.
1313   * @throws UserDataException if there is an error with the information
1314   * provided by the user when we are in non-interactive mode.
1315   * @throws ClientException if there is an error processing data in
1316   * non-interactive mode and an error must be thrown (not in force on error
1317   * mode).
1318   */
1319  private boolean handleTopologyCache(TopologyCache cache,
1320      UninstallUserData userData) throws UserDataException, ClientException
1321  {
1322    boolean returnValue;
1323    boolean stopProcessing = false;
1324    boolean reloadTopologyCache = false;
1325
1326    logger.info(LocalizableMessage.raw("Handle topology cache."));
1327
1328    Set<TopologyCacheException> exceptions = new HashSet<>();
1329    /* Analyze if we had any exception while loading servers.  For the moment
1330     * only throw the exception found if the user did not provide the
1331     * Administrator DN and this caused a problem authenticating in one server
1332     * or if there is a certificate problem.
1333     */
1334    Set<ServerDescriptor> servers = cache.getServers();
1335    userData.setRemoteServers(servers);
1336    for (ServerDescriptor server : servers)
1337    {
1338      TopologyCacheException e = server.getLastException();
1339      if (e != null)
1340      {
1341        exceptions.add(e);
1342      }
1343    }
1344    Set<LocalizableMessage> exceptionMsgs = new LinkedHashSet<>();
1345    /* Check the exceptions and see if we throw them or not. */
1346    for (TopologyCacheException e : exceptions)
1347    {
1348      logger.info(LocalizableMessage.raw("Analyzing exception: "+e, e));
1349      if (stopProcessing)
1350      {
1351        break;
1352      }
1353      switch (e.getType())
1354      {
1355      case NOT_GLOBAL_ADMINISTRATOR:
1356        println();
1357        printErrorMessage(INFO_NOT_GLOBAL_ADMINISTRATOR_PROVIDED.get());
1358        stopProcessing = true;
1359        break;
1360      case GENERIC_CREATING_CONNECTION:
1361        if (isCertificateException(e.getCause()))
1362        {
1363          if (isInteractive())
1364          {
1365            println();
1366            stopProcessing = true;
1367            if (ci.promptForCertificateConfirmation(e.getCause(),
1368                e.getTrustManager(), e.getLdapUrl(), logger))
1369            {
1370              reloadTopologyCache = true;
1371              updateTrustManager(userData, ci);
1372            }
1373          }
1374          else
1375          {
1376            exceptionMsgs.add(
1377                INFO_ERROR_READING_CONFIG_LDAP_CERTIFICATE_SERVER.get(
1378                e.getHostPort(), e.getCause().getMessage()));
1379          }
1380        }
1381        else
1382        {
1383          exceptionMsgs.add(Utils.getMessage(e));
1384        }
1385        break;
1386      default:
1387        exceptionMsgs.add(Utils.getMessage(e));
1388      }
1389    }
1390    if (isInteractive())
1391    {
1392      if (!stopProcessing && !exceptionMsgs.isEmpty())
1393      {
1394        println();
1395        try
1396        {
1397          returnValue = askConfirmation(
1398            ERR_UNINSTALL_READING_REGISTERED_SERVERS_CONFIRM_UPDATE_REMOTE.get(
1399                Utils.getMessageFromCollection(exceptionMsgs,
1400                  Constants.LINE_SEPARATOR)), true, logger);
1401        }
1402        catch (ClientException ce)
1403        {
1404          throw new UserDataException(null, ce.getMessageObject(), ce);
1405        }
1406      }
1407      else if (reloadTopologyCache)
1408      {
1409       returnValue = updateUserUninstallDataWithRemoteServers(userData);
1410      }
1411      else
1412      {
1413        returnValue = !stopProcessing;
1414      }
1415    }
1416    else
1417    {
1418      logger.info(LocalizableMessage.raw("exceptionMsgs: "+exceptionMsgs));
1419      if (!exceptionMsgs.isEmpty())
1420      {
1421        if (parser.isForceOnError())
1422        {
1423          LocalizableMessage msg = Utils.getMessageFromCollection(exceptionMsgs,
1424              Constants.LINE_SEPARATOR);
1425          println();
1426          printErrorMessage(msg);
1427          returnValue = false;
1428        }
1429        else
1430        {
1431          LocalizableMessage msg =
1432            ERR_UNINSTALL_ERROR_UPDATING_REMOTE_NO_FORCE.get(
1433              "--"+
1434              parser.getSecureArgsList().adminUidArg.getLongIdentifier(),
1435              "--"+OPTION_LONG_BINDPWD,
1436              "--"+OPTION_LONG_BINDPWD_FILE,
1437              "--"+parser.forceOnErrorArg.getLongIdentifier(),
1438              Utils.getMessageFromCollection(exceptionMsgs,
1439                  Constants.LINE_SEPARATOR));
1440          throw new ClientException(ReturnCode.APPLICATION_ERROR, msg);
1441        }
1442      }
1443      else
1444      {
1445        returnValue = true;
1446      }
1447    }
1448    logger.info(LocalizableMessage.raw("Return value: "+returnValue));
1449    return returnValue;
1450  }
1451
1452  /** {@inheritDoc} */
1453  @Override
1454  public boolean isAdvancedMode() {
1455    return false;
1456  }
1457
1458
1459
1460  /** {@inheritDoc} */
1461  @Override
1462  public boolean isInteractive() {
1463    return !forceNonInteractive && parser.isInteractive();
1464  }
1465
1466
1467
1468  /** {@inheritDoc} */
1469  @Override
1470  public boolean isMenuDrivenMode() {
1471    return true;
1472  }
1473
1474
1475
1476  /** {@inheritDoc} */
1477  @Override
1478  public boolean isQuiet() {
1479    return false;
1480  }
1481
1482
1483
1484  /** {@inheritDoc} */
1485  @Override
1486  public boolean isScriptFriendly() {
1487    return false;
1488  }
1489
1490
1491
1492  /** {@inheritDoc} */
1493  @Override
1494  public boolean isVerbose() {
1495    return true;
1496  }
1497
1498  /**
1499   * Commodity method to update the user data with the trust manager in the
1500   * LDAPConnectionConsoleInteraction object.
1501   * @param userData the user data to be updated.
1502   * @param ci the LDAPConnectionConsoleInteraction object to be used to update
1503   * the user data object.
1504   */
1505   private void updateTrustManager(UninstallUserData userData,
1506       LDAPConnectionConsoleInteraction ci)
1507   {
1508     ApplicationTrustManager trust = null;
1509     TrustManager t = ci.getTrustManager();
1510     if (t != null)
1511     {
1512       if (t instanceof ApplicationTrustManager)
1513       {
1514         trust = (ApplicationTrustManager)t;
1515       }
1516       else
1517       {
1518         trust = new ApplicationTrustManager(ci.getKeyStore());
1519       }
1520     }
1521     userData.setTrustManager(trust);
1522   }
1523
1524
1525
1526   /**
1527    * Forces the initialization of the trust manager in the
1528    * LDAPConnectionInteraction object.
1529    */
1530   private void forceTrustManagerInitialization()
1531   {
1532     forceNonInteractive = true;
1533     try
1534     {
1535       ci.initializeTrustManagerIfRequired();
1536     }
1537     catch (ArgumentException ae)
1538     {
1539       logger.warn(LocalizableMessage.raw("Error initializing trust store: "+ae, ae));
1540     }
1541     forceNonInteractive = false;
1542   }
1543
1544   private void printErrorMessage(LocalizableMessage msg)
1545   {
1546     super.println(msg);
1547     logger.warn(LocalizableMessage.raw(msg));
1548   }
1549
1550   /**
1551    * Returns the timeout to be used to connect in milliseconds.  The method
1552    * must be called after parsing the arguments.
1553    * @return the timeout to be used to connect in milliseconds.  Returns
1554    * {@code 0} if there is no timeout.
1555    * @throw {@code IllegalStateException} if the method is called before
1556    * parsing the arguments.
1557    */
1558   private int getConnectTimeout()
1559   {
1560     try
1561     {
1562       return parser.getSecureArgsList().connectTimeoutArg.getIntValue();
1563     }
1564     catch (ArgumentException ae)
1565     {
1566       throw new IllegalStateException("Argument parser is not parsed: "+ae,
1567           ae);
1568     }
1569   }
1570}