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