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 2011-2016 ForgeRock AS.
016 */
017package org.opends.quicksetup.installer;
018
019import static com.forgerock.opendj.cli.ArgumentConstants.*;
020import static com.forgerock.opendj.cli.Utils.*;
021import static com.forgerock.opendj.util.OperatingSystem.*;
022
023import static org.forgerock.util.Utils.*;
024import static org.opends.admin.ads.ServerDescriptor.*;
025import static org.opends.admin.ads.ServerDescriptor.ServerProperty.*;
026import static org.opends.admin.ads.util.ConnectionUtils.*;
027import static org.opends.admin.ads.util.PreferredConnection.Type.*;
028import static org.opends.messages.QuickSetupMessages.*;
029import static org.opends.quicksetup.Step.*;
030import static org.opends.quicksetup.installer.DataReplicationOptions.Type.*;
031import static org.opends.quicksetup.installer.InstallProgressStep.*;
032import static org.opends.quicksetup.util.Utils.*;
033
034import java.awt.event.WindowEvent;
035import java.io.BufferedWriter;
036import java.io.File;
037import java.io.FileWriter;
038import java.io.IOException;
039import java.io.PrintStream;
040import java.net.URI;
041import java.security.KeyStoreException;
042import java.util.ArrayList;
043import java.util.Collection;
044import java.util.Collections;
045import java.util.HashMap;
046import java.util.HashSet;
047import java.util.LinkedHashSet;
048import java.util.LinkedList;
049import java.util.List;
050import java.util.Map;
051import java.util.Set;
052
053import javax.naming.NameAlreadyBoundException;
054import javax.naming.NameNotFoundException;
055import javax.naming.NamingEnumeration;
056import javax.naming.NamingException;
057import javax.naming.NamingSecurityException;
058import javax.naming.directory.Attribute;
059import javax.naming.directory.BasicAttribute;
060import javax.naming.directory.BasicAttributes;
061import javax.naming.directory.DirContext;
062import javax.naming.directory.SearchControls;
063import javax.naming.directory.SearchResult;
064import javax.naming.ldap.InitialLdapContext;
065import javax.naming.ldap.Rdn;
066import javax.swing.JPanel;
067
068import org.forgerock.i18n.LocalizableMessage;
069import org.forgerock.i18n.LocalizableMessageBuilder;
070import org.forgerock.i18n.LocalizableMessageDescriptor.Arg0;
071import org.forgerock.i18n.slf4j.LocalizedLogger;
072import org.forgerock.opendj.config.ManagedObjectDefinition;
073import org.forgerock.opendj.server.config.client.BackendCfgClient;
074import org.forgerock.opendj.server.config.server.BackendCfg;
075import org.opends.admin.ads.ADSContext;
076import org.opends.admin.ads.ADSContextException;
077import org.opends.admin.ads.ReplicaDescriptor;
078import org.opends.admin.ads.ServerDescriptor;
079import org.opends.admin.ads.SuffixDescriptor;
080import org.opends.admin.ads.TopologyCache;
081import org.opends.admin.ads.TopologyCacheException;
082import org.opends.admin.ads.TopologyCacheFilter;
083import org.opends.admin.ads.util.ApplicationTrustManager;
084import org.opends.admin.ads.util.ConnectionWrapper;
085import org.opends.admin.ads.util.PreferredConnection;
086import org.opends.quicksetup.ApplicationException;
087import org.opends.quicksetup.ButtonName;
088import org.opends.quicksetup.Constants;
089import org.opends.quicksetup.Installation;
090import org.opends.quicksetup.JavaArguments;
091import org.opends.quicksetup.LicenseFile;
092import org.opends.quicksetup.ProgressStep;
093import org.opends.quicksetup.ReturnCode;
094import org.opends.quicksetup.SecurityOptions;
095import org.opends.quicksetup.Step;
096import org.opends.quicksetup.UserData;
097import org.opends.quicksetup.UserDataCertificateException;
098import org.opends.quicksetup.UserDataConfirmationException;
099import org.opends.quicksetup.UserDataException;
100import org.opends.quicksetup.WizardStep;
101import org.opends.quicksetup.event.ButtonActionListener;
102import org.opends.quicksetup.event.ButtonEvent;
103import org.opends.quicksetup.installer.ui.DataOptionsPanel;
104import org.opends.quicksetup.installer.ui.DataReplicationPanel;
105import org.opends.quicksetup.installer.ui.GlobalAdministratorPanel;
106import org.opends.quicksetup.installer.ui.InstallLicensePanel;
107import org.opends.quicksetup.installer.ui.InstallReviewPanel;
108import org.opends.quicksetup.installer.ui.InstallWelcomePanel;
109import org.opends.quicksetup.installer.ui.RemoteReplicationPortsPanel;
110import org.opends.quicksetup.installer.ui.RuntimeOptionsPanel;
111import org.opends.quicksetup.installer.ui.ServerSettingsPanel;
112import org.opends.quicksetup.installer.ui.SuffixesToReplicatePanel;
113import org.opends.quicksetup.ui.FieldName;
114import org.opends.quicksetup.ui.FinishedPanel;
115import org.opends.quicksetup.ui.GuiApplication;
116import org.opends.quicksetup.ui.ProgressPanel;
117import org.opends.quicksetup.ui.QuickSetup;
118import org.opends.quicksetup.ui.QuickSetupDialog;
119import org.opends.quicksetup.ui.QuickSetupErrorPanel;
120import org.opends.quicksetup.ui.QuickSetupStepPanel;
121import org.opends.quicksetup.ui.UIFactory;
122import org.opends.quicksetup.util.FileManager;
123import org.opends.quicksetup.util.IncompatibleVersionException;
124import org.opends.quicksetup.util.ServerController;
125import org.opends.quicksetup.util.Utils;
126import org.opends.server.tools.BackendTypeHelper;
127import org.opends.server.tools.BackendTypeHelper.BackendTypeUIAdapter;
128import org.opends.server.types.HostPort;
129import org.opends.server.util.CertificateManager;
130import org.opends.server.util.CollectionUtils;
131import org.opends.server.util.DynamicConstants;
132import org.opends.server.util.Platform.KeyType;
133import org.opends.server.util.SetupUtils;
134import org.opends.server.util.StaticUtils;
135
136import com.forgerock.opendj.util.OperatingSystem;
137
138/**
139 * This is an abstract class that is in charge of actually performing the
140 * installation.
141 *
142 * It just takes a UserData object and based on that installs OpenDJ.
143 *
144 * When there is an update during the installation it will notify the
145 * ProgressUpdateListener objects that have been added to it.  The
146 * notification will send a ProgressUpdateEvent.
147 *
148 * This class is supposed to be fully independent of the graphical layout.
149 *
150 * Note that we can use freely the class org.opends.server.util.SetupUtils as
151 * it is included in quicksetup.jar.
152 */
153public class Installer extends GuiApplication
154{
155  /** The minimum integer value that can be used for a port. */
156  public static final int MIN_PORT_VALUE = 1;
157  /** The maximum integer value that can be used for a port. */
158  public static final int MAX_PORT_VALUE = 65535;
159
160  /** The name of the backend created on setup. */
161  public static final String ROOT_BACKEND_NAME = "userRoot";
162
163  /** Constants used to do checks. */
164  private static final int MIN_DIRECTORY_MANAGER_PWD = 1;
165
166  private static final int MIN_NUMBER_ENTRIES = 1;
167  private static final int MAX_NUMBER_ENTRIES = 10000000;
168
169  /**
170   * If the user decides to import more than this number of entries, the import
171   * process of automatically generated data will be verbose.
172   */
173  private static final int THRESHOLD_AUTOMATIC_DATA_VERBOSE = 20000;
174
175  /**
176   * If the user decides to import a number of entries higher than this
177   * threshold, the start process will be verbose.
178   */
179  private static final int THRESHOLD_VERBOSE_START = 100000;
180
181  private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
182
183  private TopologyCache lastLoadedCache;
184
185  /** Indicates that we've detected that there is something installed. */
186  private boolean forceToDisplaySetup;
187
188  /** When true indicates that the user has canceled this operation. */
189  private boolean canceled;
190  private boolean javaVersionCheckFailed;
191
192  /** Map containing information about what has been configured remotely. */
193  private final Map<ServerDescriptor, ConfiguredReplication> hmConfiguredRemoteReplication = new HashMap<>();
194
195  /** Set of progress steps that have been completed. */
196  private final Set<InstallProgressStep> completedProgress = new HashSet<>();
197  private final List<WizardStep> listSteps = new ArrayList<>();
198  private final Set<WizardStep> SUBSTEPS = CollectionUtils.<WizardStep> newHashSet(
199      Step.CREATE_GLOBAL_ADMINISTRATOR,
200      Step.SUFFIXES_OPTIONS,
201      Step.NEW_SUFFIX_OPTIONS,
202      Step.REMOTE_REPLICATION_PORTS);
203
204  private final Map<WizardStep, WizardStep> hmPreviousSteps = new HashMap<>();
205
206  private char[] selfSignedCertPw;
207
208  private boolean registeredNewServerOnRemote;
209  private boolean createdAdministrator;
210  private boolean createdRemoteAds;
211  private String lastImportProgress;
212
213  /** Aliases of self-signed certificates. */
214  private static final String[] SELF_SIGNED_CERT_ALIASES = {
215    SecurityOptions.SELF_SIGNED_CERT_ALIAS,
216    SecurityOptions.SELF_SIGNED_EC_CERT_ALIAS
217  };
218
219  /**
220   * The threshold in minutes used to know whether we must display a warning
221   * informing that there is a server clock difference between two servers whose
222   * contents are being replicated.
223   */
224  public static final int THRESHOLD_CLOCK_DIFFERENCE_WARNING = 5;
225
226  /** This map contains the ratio associated with each step. */
227  private final Map<ProgressStep, Integer> hmRatio = new HashMap<>();
228  /** This map contains the summary associated with each step. */
229  private final Map<ProgressStep, LocalizableMessage> hmSummary = new HashMap<>();
230
231  private ApplicationException applicationException;
232
233  /** Actually performs the install in this thread. The thread is blocked. */
234  @Override
235  public void run()
236  {
237    applicationException = null;
238    PrintStream origErr = System.err;
239    PrintStream origOut = System.out;
240    try
241    {
242      initMaps();
243      System.setErr(getApplicationErrorStream());
244      System.setOut(getApplicationOutputStream());
245      checkAbort();
246
247      setCurrentProgressStep(InstallProgressStep.CONFIGURING_SERVER);
248      configureServer();
249      checkAbort();
250
251      LicenseFile.createFileLicenseApproved(getInstallationPath());
252      checkAbort();
253
254      createData();
255      checkAbort();
256
257      if (isWindows() && getUserData().getEnableWindowsService())
258      {
259        showStepStarted(InstallProgressStep.ENABLING_WINDOWS_SERVICE);
260        enableWindowsService();
261        checkAbort();
262      }
263
264      if (mustStart())
265      {
266        startServer();
267      }
268
269      if (mustCreateAds())
270      {
271        showStepStarted(InstallProgressStep.CONFIGURING_ADS);
272        updateADS();
273        checkAbort();
274      }
275
276      if (mustConfigureReplication())
277      {
278        showStepStarted(InstallProgressStep.CONFIGURING_REPLICATION);
279        createReplicatedBackendsIfRequired();
280        configureReplication();
281        checkAbort();
282      }
283
284      if (mustInitializeSuffixes())
285      {
286        showStepStarted(InstallProgressStep.INITIALIZE_REPLICATED_SUFFIXES);
287        initializeSuffixes();
288        checkAbort();
289      }
290
291      if (mustStop())
292      {
293        showStepStarted(InstallProgressStep.STOPPING_SERVER);
294        stopServer(new ServerController(this));
295      }
296
297      checkAbort();
298      updateSummaryWithServerState(hmSummary, true);
299      setCurrentProgressStep(InstallProgressStep.FINISHED_SUCCESSFULLY);
300      notifyListeners(null);
301      tempLogFile.deleteLogFileAfterSuccess();
302    }
303    catch (final ApplicationException ex)
304    {
305      logger.error(LocalizableMessage.raw("Caught exception: "+ex, ex));
306      if (ReturnCode.CANCELED.equals(ex.getType())) {
307        uninstall();
308        setCurrentProgressStep(InstallProgressStep.FINISHED_CANCELED);
309        notifyListeners(null);
310      } else {
311        handleInstallationError(ex);
312      }
313      applicationException = ex;
314    }
315    catch (final Throwable t)
316    {
317      final ApplicationException ex =
318          new ApplicationException(ReturnCode.BUG, getThrowableMsg(INFO_BUG_MSG.get(), t), t);
319      handleInstallationError(ex);
320      applicationException = ex;
321    }
322    finally
323    {
324      System.setErr(origErr);
325      System.setOut(origOut);
326    }
327  }
328
329  private void showStepStarted(final InstallProgressStep step)
330  {
331    if (isVerbose())
332    {
333      notifyListeners(getTaskSeparator());
334    }
335    setCurrentProgressStep(step);
336  }
337
338  private void startServer() throws ApplicationException
339  {
340    final boolean verbose = isStartVerbose();
341    if (verbose)
342    {
343      notifyListeners(getTaskSeparator());
344    }
345    setCurrentProgressStep(InstallProgressStep.STARTING_SERVER);
346    final PointAdder pointAdder = new PointAdder();
347    if (!verbose)
348    {
349      notifyListeners(getFormattedProgress(INFO_PROGRESS_STARTING_NON_VERBOSE.get()));
350      pointAdder.start();
351    }
352    try
353    {
354      new ServerController(this).startServer(!verbose);
355    }
356    finally
357    {
358      if (!verbose)
359      {
360        pointAdder.stop();
361      }
362    }
363    notifyListeners(verbose ? getLineBreak() : getFormattedDoneWithLineBreak());
364    checkAbort();
365  }
366
367  private void handleInstallationError(final ApplicationException exception)
368  {
369    stopServerIfNeeded();
370    notifyListeners(getLineBreak());
371    updateSummaryWithServerState(hmSummary, true);
372    setCurrentProgressStep(InstallProgressStep.FINISHED_WITH_ERROR);
373    notifyListeners(getFormattedError(exception, true));
374    logger.error(LocalizableMessage.raw("Error installing.", exception));
375    notifyListeners(getLineBreak());
376    notifyListenersOfExistingLogFile();
377  }
378
379  private void stopServerIfNeeded()
380  {
381    final Installation installation = getInstallation();
382    if (installation.getStatus().isServerRunning())
383    {
384      try
385      {
386        stopServer(new ServerController(installation));
387      }
388      catch (final ApplicationException t)
389      {
390        logger.info(LocalizableMessage.raw("error stopping server", t));
391      }
392    }
393  }
394
395  private void stopServer(final ServerController serverController) throws ApplicationException
396  {
397    if (isVerbose())
398    {
399      serverController.stopServer(false);
400    }
401    else
402    {
403      notifyListeners(getFormattedWithPoints(INFO_PROGRESS_STOPPING_NON_VERBOSE.get()));
404      serverController.stopServer(true);
405      notifyListeners(getFormattedDoneWithLineBreak());
406    }
407  }
408
409  @Override
410  public Integer getRatio(ProgressStep status)
411  {
412    return hmRatio.get(status);
413  }
414
415  @Override
416  public LocalizableMessage getSummary(ProgressStep status)
417  {
418    return hmSummary.get(status);
419  }
420
421  /**
422   * Returns the exception from the run() method, if any.
423   * @return the ApplicationException raised during the run() method, if any.
424   *         null otherwise.
425   */
426  public ApplicationException getApplicationException()
427  {
428    return applicationException;
429  }
430
431  private void uninstall() {
432    notifyListeners(getTaskSeparator());
433    if (!isVerbose())
434    {
435      notifyListeners(getFormattedWithPoints(INFO_PROGRESS_CANCELING.get()));
436    }
437    else
438    {
439      notifyListeners(
440          getFormattedProgressWithLineBreak(INFO_SUMMARY_CANCELING.get()));
441    }
442    Installation installation = getInstallation();
443    FileManager fm = new FileManager(this);
444
445    stopServerIfNeeded();
446    uninstallServices();
447    revertToBaseConfiguration(installation, fm);
448    cleanupSSLIfNeeded(installation, fm);
449
450    // Remove the databases
451    try {
452      fm.deleteChildren(installation.getDatabasesDirectory());
453    } catch (ApplicationException e) {
454      logger.info(LocalizableMessage.raw("Error deleting databases", e));
455    }
456
457    if (!isVerbose())
458    {
459      notifyListeners(getFormattedDoneWithLineBreak());
460    }
461  }
462
463  private void revertToBaseConfiguration(final Installation installation, final FileManager fm)
464  {
465    try
466    {
467      File newConfig = fm.copy(installation.getBaseConfigurationFile(),
468          installation.getConfigurationDirectory(), true);
469      fm.rename(newConfig, installation.getCurrentConfigurationFile());
470    }
471    catch (ApplicationException ae)
472    {
473      logger.info(LocalizableMessage.raw("failed to restore base configuration", ae));
474    }
475  }
476
477  private void cleanupSSLIfNeeded(final Installation installation, final FileManager fm)
478  {
479    final SecurityOptions sec = getUserData().getSecurityOptions();
480    if (sec.getEnableSSL() || sec.getEnableStartTLS())
481    {
482      if (SecurityOptions.CertificateType.SELF_SIGNED_CERTIFICATE.equals(sec.getCertificateType()))
483      {
484        final CertificateManager cm = new CertificateManager(
485            getSelfSignedKeystorePath(), CertificateManager.KEY_STORE_TYPE_JKS, getSelfSignedCertificatePwd());
486        try
487        {
488          for (final String alias : SELF_SIGNED_CERT_ALIASES)
489          {
490            if (cm.aliasInUse(alias))
491            {
492              cm.removeCertificate(alias);
493            }
494          }
495        }
496        catch (KeyStoreException e)
497        {
498          logger.info(LocalizableMessage.raw("Error deleting self signed certification", e));
499        }
500      }
501
502      final File configDir = installation.getConfigurationDirectory();
503      removeFileIfExists(fm, configDir, "keystore");
504      removeFileIfExists(fm, configDir, "keystore.pin");
505      removeFileIfExists(fm, configDir, "truststore");
506    }
507  }
508
509  private void removeFileIfExists(final FileManager fileManager, final File configDir, final String fileName)
510  {
511    final File file = new File(configDir, fileName);
512    if (file.exists())
513    {
514      try
515      {
516        fileManager.delete(file);
517      }
518      catch (ApplicationException e)
519      {
520        logger.info(LocalizableMessage.raw("Failed to delete " + fileName, e));
521      }
522    }
523  }
524
525  private void initMaps()
526  {
527    initSummaryMap(hmSummary, true);
528
529    final List<InstallProgressStep> steps = new ArrayList<>();
530    steps.add(InstallProgressStep.CONFIGURING_SERVER);
531    if (createNotReplicatedSuffix())
532    {
533      switch (getUserData().getNewSuffixOptions().getType())
534      {
535      case CREATE_BASE_ENTRY:
536        steps.add(InstallProgressStep.CREATING_BASE_ENTRY);
537        break;
538      case IMPORT_FROM_LDIF_FILE:
539        steps.add(InstallProgressStep.IMPORTING_LDIF);
540        break;
541      case IMPORT_AUTOMATICALLY_GENERATED_DATA:
542        steps.add(InstallProgressStep.IMPORTING_AUTOMATICALLY_GENERATED);
543        break;
544      }
545    }
546
547    if (isWindows() && getUserData().getEnableWindowsService())
548    {
549      steps.add(InstallProgressStep.ENABLING_WINDOWS_SERVICE);
550    }
551
552    if (mustStart())
553    {
554      steps.add(InstallProgressStep.STARTING_SERVER);
555    }
556
557    if (mustCreateAds())
558    {
559      steps.add(InstallProgressStep.CONFIGURING_ADS);
560    }
561
562    if (mustConfigureReplication())
563    {
564      steps.add(InstallProgressStep.CONFIGURING_REPLICATION);
565    }
566
567    if (mustInitializeSuffixes())
568    {
569      steps.add(InstallProgressStep.INITIALIZE_REPLICATED_SUFFIXES);
570    }
571
572    if (mustStop())
573    {
574      steps.add(InstallProgressStep.STOPPING_SERVER);
575    }
576
577    int totalTime = 0;
578    for (final InstallProgressStep step : steps) {
579      totalTime += step.getRelativeDuration();
580    }
581
582    int cumulatedTime = 0;
583    for (InstallProgressStep s : steps)
584    {
585      Integer statusTime = s.getRelativeDuration();
586      hmRatio.put(s, (100 * cumulatedTime) / totalTime);
587      cumulatedTime += statusTime;
588    }
589    hmRatio.put(InstallProgressStep.FINISHED_SUCCESSFULLY, 100);
590    hmRatio.put(InstallProgressStep.FINISHED_WITH_ERROR, 100);
591    hmRatio.put(InstallProgressStep.FINISHED_CANCELED, 100);
592  }
593
594  @Override
595  public String getInstallationPath()
596  {
597    return Utils.getInstallPathFromClasspath();
598  }
599
600  @Override
601  public String getInstancePath()
602  {
603    String installPath =  Utils.getInstallPathFromClasspath();
604    return Utils.getInstancePathFromInstallPath(installPath);
605  }
606
607  private void notifyListenersOfExistingLogFile()
608  {
609    if (tempLogFile.isEnabled())
610    {
611      final String tempLogFilePath = tempLogFile.getPath();
612      notifyListeners(getFormattedProgress(INFO_GENERAL_PROVIDE_LOG_IN_ERROR.get(tempLogFilePath)));
613      notifyListeners(getLineBreak());
614    }
615  }
616
617  /** Creates a default instance. */
618  public Installer()
619  {
620    addStepsInOrder(listSteps, LicenseFile.exists());
621  }
622
623  @Override
624  public boolean isCancellable()
625  {
626    return true;
627  }
628
629  @Override
630  public UserData createUserData()
631  {
632    UserData ud = new UserData();
633    ud.setServerLocation(getDefaultServerLocation());
634    initializeUserDataWithUserArguments(ud, getUserArguments());
635    return ud;
636  }
637
638  private void initializeUserDataWithUserArguments(UserData ud, String[] userArguments)
639  {
640    for (int i = 0; i < userArguments.length; i++)
641    {
642      if ("--connectTimeout".equalsIgnoreCase(userArguments[i]))
643      {
644        if (i < userArguments.length - 1)
645        {
646          String sTimeout = userArguments[i + 1];
647          try
648          {
649            ud.setConnectTimeout(Integer.valueOf(sTimeout));
650          }
651          catch (Throwable t)
652          {
653            logger.warn(LocalizableMessage.raw("Error getting connect timeout: " + t, t));
654          }
655        }
656        break;
657      }
658    }
659  }
660
661  @Override
662  public void forceToDisplay()
663  {
664    forceToDisplaySetup = true;
665  }
666
667  @Override
668  public boolean canGoBack(WizardStep step)
669  {
670    return step != WELCOME && step != PROGRESS && step != FINISHED;
671  }
672
673  @Override
674  public boolean canGoForward(WizardStep step)
675  {
676    return step != REVIEW && step != PROGRESS && step != FINISHED;
677  }
678
679  @Override
680  public boolean canFinish(WizardStep step)
681  {
682    return step == REVIEW;
683  }
684
685    @Override
686  public boolean isSubStep(WizardStep step)
687  {
688    return SUBSTEPS.contains(step);
689  }
690
691  @Override
692  public boolean isVisible(WizardStep step, UserData userData)
693  {
694    if (step == CREATE_GLOBAL_ADMINISTRATOR)
695    {
696      return userData.mustCreateAdministrator();
697    }
698    else if (step == NEW_SUFFIX_OPTIONS)
699    {
700      SuffixesToReplicateOptions suf = userData.getSuffixesToReplicateOptions();
701      return suf != null && suf.getType() != SuffixesToReplicateOptions.Type.REPLICATE_WITH_EXISTING_SUFFIXES;
702    }
703    else if (step == SUFFIXES_OPTIONS)
704    {
705      DataReplicationOptions repl = userData.getReplicationOptions();
706      return repl != null && repl.getType() != DataReplicationOptions.Type.STANDALONE
707          && repl.getType() != DataReplicationOptions.Type.FIRST_IN_TOPOLOGY;
708    }
709    else if (step == REMOTE_REPLICATION_PORTS)
710    {
711      return isVisible(SUFFIXES_OPTIONS, userData)
712          && !userData.getRemoteWithNoReplicationPort().isEmpty()
713          && userData.getSuffixesToReplicateOptions().getType() ==
714              SuffixesToReplicateOptions.Type.REPLICATE_WITH_EXISTING_SUFFIXES;
715    }
716    return true;
717  }
718
719  @Override
720  public boolean isVisible(WizardStep step, QuickSetup qs)
721  {
722    return isVisible(step, getUserData());
723  }
724
725  @Override
726  public boolean finishClicked(final WizardStep cStep, final QuickSetup qs)
727  {
728    if (cStep != Step.REVIEW)
729    {
730      throw new IllegalStateException("Cannot click on finish when we are not in the Review window");
731    }
732
733    updateUserDataForReviewPanel(qs);
734    qs.launch();
735    qs.setCurrentStep(Step.PROGRESS);
736    // Installer responsible for updating the user data and launching
737    return false;
738  }
739
740    @Override
741  public void nextClicked(WizardStep cStep, QuickSetup qs)
742  {
743    if (cStep == PROGRESS)
744    {
745      throw new IllegalStateException("Cannot click on next from progress step");
746    }
747    else if (cStep == REVIEW)
748    {
749      throw new IllegalStateException("Cannot click on next from review step");
750    }
751    else if (cStep == FINISHED)
752    {
753      throw new IllegalStateException("Cannot click on next from finished step");
754    }
755  }
756
757  @Override
758  public void closeClicked(WizardStep cStep, QuickSetup qs)
759  {
760    if (cStep == PROGRESS)
761    {
762      if (isFinished()
763          || qs.displayConfirmation(INFO_CONFIRM_CLOSE_INSTALL_MSG.get(), INFO_CONFIRM_CLOSE_INSTALL_TITLE.get()))
764      {
765        qs.quit();
766      }
767    }
768    else if (cStep == FINISHED)
769    {
770      qs.quit();
771    }
772    else
773    {
774      throw new IllegalStateException("Close only can be clicked on PROGRESS step");
775    }
776  }
777
778  @Override
779  public boolean isFinished()
780  {
781    return getCurrentProgressStep() == InstallProgressStep.FINISHED_SUCCESSFULLY
782        || getCurrentProgressStep() == InstallProgressStep.FINISHED_CANCELED
783        || getCurrentProgressStep() == InstallProgressStep.FINISHED_WITH_ERROR;
784  }
785
786  @Override
787  public void cancel()
788  {
789    setCurrentProgressStep(InstallProgressStep.WAITING_TO_CANCEL);
790    notifyListeners(null);
791    this.canceled = true;
792  }
793
794  @Override
795  public void quitClicked(WizardStep cStep, QuickSetup qs)
796  {
797    if (cStep == FINISHED)
798    {
799      qs.quit();
800    }
801    else if (cStep == PROGRESS)
802    {
803      throw new IllegalStateException("Cannot click on quit from progress step");
804    }
805    else if (installStatus.isInstalled())
806    {
807      qs.quit();
808    }
809    else if (javaVersionCheckFailed)
810    {
811      qs.quit();
812    }
813    else if (qs.displayConfirmation(INFO_CONFIRM_QUIT_INSTALL_MSG.get(), INFO_CONFIRM_QUIT_INSTALL_TITLE.get()))
814    {
815      qs.quit();
816    }
817  }
818
819  @Override
820  public ButtonName getInitialFocusButtonName()
821  {
822    if (!installStatus.isInstalled() || forceToDisplaySetup)
823    {
824      return ButtonName.NEXT;
825    }
826    else if (installStatus.canOverwriteCurrentInstall())
827    {
828      return ButtonName.CONTINUE_INSTALL;
829    }
830    else
831    {
832      return ButtonName.QUIT;
833    }
834  }
835
836  @Override
837  public JPanel createFramePanel(QuickSetupDialog dlg)
838  {
839    JPanel p;
840    javaVersionCheckFailed = true;
841    try
842    {
843      Utils.checkJavaVersion();
844      javaVersionCheckFailed = false;
845      if (installStatus.isInstalled() && !forceToDisplaySetup)
846      {
847        p = dlg.getInstalledPanel();
848      }
849      else
850      {
851        p = super.createFramePanel(dlg);
852      }
853    }
854    catch (IncompatibleVersionException ijv)
855    {
856      LocalizableMessageBuilder sb = new LocalizableMessageBuilder();
857      sb.append(Utils.breakHtmlString(Utils.getHtml(ijv.getMessageObject().toString()),
858          Constants.MAX_CHARS_PER_LINE_IN_DIALOG));
859      QuickSetupErrorPanel errPanel = new QuickSetupErrorPanel(this, sb.toMessage());
860      final QuickSetupDialog fDlg = dlg;
861      errPanel.addButtonActionListener(new ButtonActionListener()
862      {
863        @Override
864        public void buttonActionPerformed(ButtonEvent ev)
865        {
866          // assumes that we are called in the event thread.
867          // Simulate a close button event
868          fDlg.notifyButtonEvent(ButtonName.QUIT);
869        }
870      });
871      p = errPanel;
872    }
873    return p;
874  }
875
876  @Override
877  public Set<? extends WizardStep> getWizardSteps()
878  {
879    return Collections.unmodifiableSet(new HashSet<WizardStep>(listSteps));
880  }
881
882  @Override
883  public QuickSetupStepPanel createWizardStepPanel(WizardStep step)
884  {
885    if (step instanceof Step)
886    {
887      switch ((Step) step)
888      {
889      case WELCOME:
890        return new InstallWelcomePanel(this);
891      case LICENSE:
892        return new InstallLicensePanel(this);
893      case SERVER_SETTINGS:
894        return new ServerSettingsPanel(this);
895      case REPLICATION_OPTIONS:
896        return new DataReplicationPanel(this);
897      case CREATE_GLOBAL_ADMINISTRATOR:
898        return new GlobalAdministratorPanel(this);
899      case SUFFIXES_OPTIONS:
900        return new SuffixesToReplicatePanel(this);
901      case REMOTE_REPLICATION_PORTS:
902        return new RemoteReplicationPortsPanel(this);
903      case NEW_SUFFIX_OPTIONS:
904        return new DataOptionsPanel(this);
905      case RUNTIME_OPTIONS:
906        return new RuntimeOptionsPanel(this);
907      case REVIEW:
908        return new InstallReviewPanel(this);
909      case PROGRESS:
910        return new ProgressPanel(this);
911      case FINISHED:
912        return new FinishedPanel(this);
913      }
914    }
915    return null;
916  }
917
918  @Override
919  public void windowClosing(QuickSetupDialog dlg, WindowEvent evt)
920  {
921    if (installStatus.isInstalled() && forceToDisplaySetup)
922    {
923      // Simulate a close button event
924      dlg.notifyButtonEvent(ButtonName.QUIT);
925    }
926    else if (dlg.getDisplayedStep() == Step.PROGRESS)
927    {
928      // Simulate a close button event
929      dlg.notifyButtonEvent(ButtonName.CLOSE);
930    }
931    else
932    {
933      // Simulate a quit button event
934      dlg.notifyButtonEvent(ButtonName.QUIT);
935    }
936  }
937
938  @Override
939  public LocalizableMessage getCloseButtonToolTip()
940  {
941    return INFO_CLOSE_BUTTON_INSTALL_TOOLTIP.get();
942  }
943
944  @Override
945  public LocalizableMessage getQuitButtonToolTip()
946  {
947    return INFO_QUIT_BUTTON_INSTALL_TOOLTIP.get();
948  }
949
950  @Override
951  public LocalizableMessage getFinishButtonToolTip()
952  {
953    return INFO_FINISH_BUTTON_INSTALL_TOOLTIP.get();
954  }
955
956  @Override
957  public int getExtraDialogHeight()
958  {
959    return UIFactory.EXTRA_DIALOG_HEIGHT;
960  }
961
962  @Override
963  public void previousClicked(WizardStep cStep, QuickSetup qs)
964  {
965    if (cStep == WELCOME)
966    {
967      throw new IllegalStateException("Cannot click on previous from progress step");
968    }
969    else if (cStep == PROGRESS)
970    {
971      throw new IllegalStateException("Cannot click on previous from progress step");
972    }
973    else if (cStep == FINISHED)
974    {
975      throw new IllegalStateException("Cannot click on previous from finished step");
976    }
977  }
978
979  @Override
980  public LocalizableMessage getFrameTitle()
981  {
982    return Utils.getCustomizedObject("INFO_FRAME_INSTALL_TITLE", INFO_FRAME_INSTALL_TITLE
983        .get(DynamicConstants.PRODUCT_NAME), LocalizableMessage.class);
984  }
985
986  /** Indicates the current progress step. */
987  private InstallProgressStep currentProgressStep = InstallProgressStep.NOT_STARTED;
988
989  @Override
990  public void setWizardDialogState(QuickSetupDialog dlg, UserData userData, WizardStep step)
991  {
992    if (!installStatus.isInstalled() || forceToDisplaySetup)
993    {
994      // Set the default button for the frame
995      if (step == REVIEW)
996      {
997        dlg.setFocusOnButton(ButtonName.FINISH);
998        dlg.setDefaultButton(ButtonName.FINISH);
999      }
1000      else if (step == WELCOME)
1001      {
1002        dlg.setDefaultButton(ButtonName.NEXT);
1003        dlg.setFocusOnButton(ButtonName.NEXT);
1004      }
1005      else if (step == PROGRESS || step == FINISHED)
1006      {
1007        dlg.setDefaultButton(ButtonName.CLOSE);
1008        dlg.setFocusOnButton(ButtonName.CLOSE);
1009      }
1010      else
1011      {
1012        dlg.setDefaultButton(ButtonName.NEXT);
1013      }
1014    }
1015  }
1016
1017  @Override
1018  public ProgressStep getCurrentProgressStep()
1019  {
1020    return currentProgressStep;
1021  }
1022
1023  @Override
1024  public WizardStep getFirstWizardStep()
1025  {
1026    return WELCOME;
1027  }
1028
1029  @Override
1030  public WizardStep getNextWizardStep(WizardStep step)
1031  {
1032    WizardStep next = getNextWizardStep0(step);
1033    if (next != null)
1034    {
1035      hmPreviousSteps.put(next, step);
1036    }
1037    return next;
1038  }
1039
1040  private WizardStep getNextWizardStep0(WizardStep step)
1041  {
1042    if (step == Step.REPLICATION_OPTIONS)
1043    {
1044      if (getUserData().mustCreateAdministrator())
1045      {
1046        return Step.CREATE_GLOBAL_ADMINISTRATOR;
1047      }
1048
1049      switch (getUserData().getReplicationOptions().getType())
1050      {
1051      case FIRST_IN_TOPOLOGY:
1052      case STANDALONE:
1053        return Step.NEW_SUFFIX_OPTIONS;
1054      default:
1055        return Step.SUFFIXES_OPTIONS;
1056      }
1057    }
1058    else if (step == Step.SUFFIXES_OPTIONS)
1059    {
1060      switch (getUserData().getSuffixesToReplicateOptions().getType())
1061      {
1062      case REPLICATE_WITH_EXISTING_SUFFIXES:
1063        if (!getUserData().getRemoteWithNoReplicationPort().isEmpty())
1064        {
1065          return Step.REMOTE_REPLICATION_PORTS;
1066        }
1067        return Step.RUNTIME_OPTIONS;
1068      default:
1069        return Step.NEW_SUFFIX_OPTIONS;
1070      }
1071    }
1072    else if (step == Step.REMOTE_REPLICATION_PORTS)
1073    {
1074      return Step.RUNTIME_OPTIONS;
1075    }
1076    else
1077    {
1078      int i = listSteps.indexOf(step);
1079      if (i != -1 && i + 1 < listSteps.size())
1080      {
1081        return listSteps.get(i + 1);
1082      }
1083    }
1084    return null;
1085  }
1086
1087  @Override
1088  public LinkedHashSet<WizardStep> getOrderedSteps()
1089  {
1090    LinkedHashSet<WizardStep> orderedSteps = new LinkedHashSet<>();
1091    addStepsInOrder(orderedSteps, listSteps.contains(LICENSE));
1092    return orderedSteps;
1093  }
1094
1095  private void addStepsInOrder(Collection<WizardStep> steps, boolean licenseExists)
1096  {
1097    steps.add(WELCOME);
1098    if (licenseExists)
1099    {
1100      steps.add(LICENSE);
1101    }
1102    steps.add(SERVER_SETTINGS);
1103    steps.add(REPLICATION_OPTIONS);
1104    steps.add(CREATE_GLOBAL_ADMINISTRATOR);
1105    steps.add(SUFFIXES_OPTIONS);
1106    steps.add(REMOTE_REPLICATION_PORTS);
1107    steps.add(NEW_SUFFIX_OPTIONS);
1108    steps.add(RUNTIME_OPTIONS);
1109    steps.add(REVIEW);
1110    steps.add(PROGRESS);
1111    steps.add(FINISHED);
1112  }
1113
1114  @Override
1115  public WizardStep getPreviousWizardStep(WizardStep step)
1116  {
1117    //  Try with the steps calculated in method getNextWizardStep.
1118    WizardStep prev = hmPreviousSteps.get(step);
1119
1120    if (prev == null)
1121    {
1122      int i = listSteps.indexOf(step);
1123      if (i != -1 && i > 0)
1124      {
1125        prev = listSteps.get(i - 1);
1126      }
1127    }
1128    return prev;
1129  }
1130
1131  @Override
1132  public WizardStep getFinishedStep()
1133  {
1134    return Step.FINISHED;
1135  }
1136
1137  /**
1138   * Uninstalls installed services. This is to be used when the user has elected
1139   * to cancel an installation.
1140   */
1141  private void uninstallServices()
1142  {
1143    if (completedProgress.contains(InstallProgressStep.ENABLING_WINDOWS_SERVICE))
1144    {
1145      try
1146      {
1147        new InstallerHelper().disableWindowsService();
1148      }
1149      catch (ApplicationException ae)
1150      {
1151        logger.info(LocalizableMessage.raw("Error disabling Windows service", ae));
1152      }
1153    }
1154
1155    unconfigureRemote();
1156  }
1157
1158  /**
1159   * Creates the template files based in the contents of the UserData object.
1160   * These templates files are used to generate automatically data. To generate
1161   * the template file the code will basically take into account the value of
1162   * the base dn and the number of entries to be generated.
1163   *
1164   * @return a list of file objects pointing to the create template files.
1165   * @throws ApplicationException
1166   *           if an error occurs.
1167   */
1168  private File createTemplateFile() throws ApplicationException
1169  {
1170    try
1171    {
1172      Set<String> baseDNs = new LinkedHashSet<>(getUserData().getNewSuffixOptions().getBaseDns());
1173      int nEntries = getUserData().getNewSuffixOptions().getNumberEntries();
1174      return SetupUtils.createTemplateFile(baseDNs, nEntries);
1175    }
1176    catch (IOException ioe)
1177    {
1178      LocalizableMessage failedMsg = getThrowableMsg(INFO_ERROR_CREATING_TEMP_FILE.get(), ioe);
1179      throw new ApplicationException(ReturnCode.FILE_SYSTEM_ACCESS_ERROR, failedMsg, ioe);
1180    }
1181  }
1182
1183  /**
1184   * This methods configures the server based on the contents of the UserData
1185   * object provided in the constructor.
1186   *
1187   * @throws ApplicationException
1188   *           if something goes wrong.
1189   */
1190  private void configureServer() throws ApplicationException
1191  {
1192    notifyListeners(getFormattedWithPoints(INFO_PROGRESS_CONFIGURING.get()));
1193    copyTemplateInstance();
1194    writeOpenDSJavaHome();
1195    writeHostName();
1196    checkAbort();
1197
1198    List<String> argList = CollectionUtils.newArrayList(
1199        "-c", getConfigurationFile(),
1200        "-h", getUserData().getHostName(),
1201        "-p", String.valueOf(getUserData().getServerPort()),
1202        "--adminConnectorPort", String.valueOf(getUserData().getAdminConnectorPort()));
1203
1204    final SecurityOptions sec = getUserData().getSecurityOptions();
1205    // TODO: even if the user does not configure SSL maybe we should choose
1206    // a secure port that is not being used and that we can actually use.
1207    if (sec.getEnableSSL())
1208    {
1209      argList.add("-P");
1210      argList.add(String.valueOf(sec.getSslPort()));
1211    }
1212
1213    if (sec.getEnableStartTLS())
1214    {
1215      argList.add("-q");
1216    }
1217
1218    addCertificateArguments(sec, argList);
1219    // For the moment do not enable JMX
1220    if (getUserData().getServerJMXPort() > 0)
1221    {
1222      argList.add("-x");
1223      argList.add(String.valueOf(getUserData().getServerJMXPort()));
1224    }
1225
1226    argList.add("-D");
1227    argList.add(getUserData().getDirectoryManagerDn());
1228
1229    argList.add("-w");
1230    argList.add(getUserData().getDirectoryManagerPwd());
1231
1232    final ManagedObjectDefinition<? extends BackendCfgClient, ? extends BackendCfg> backendType =
1233        getUserData().getBackendType();
1234    if (backendType != null)
1235    {
1236      argList.add("--" + OPTION_LONG_BACKEND_TYPE);
1237      argList.add(BackendTypeHelper.filterSchemaBackendName(backendType.getName()));
1238    }
1239
1240    if (createNotReplicatedSuffix())
1241    {
1242      for (String baseDn : getUserData().getNewSuffixOptions().getBaseDns())
1243      {
1244        argList.add("-b");
1245        argList.add(baseDn);
1246      }
1247    }
1248
1249    argList.add("-R");
1250    argList.add(getInstallation().getRootDirectory().getAbsolutePath());
1251
1252    final String[] args = new String[argList.size()];
1253    argList.toArray(args);
1254    StringBuilder cmd = new StringBuilder();
1255    boolean nextPassword = false;
1256    for (String s : argList)
1257    {
1258      if (cmd.length() > 0)
1259      {
1260        cmd.append(" ");
1261      }
1262      if (nextPassword)
1263      {
1264        cmd.append("{rootUserPassword}");
1265      }
1266      else
1267      {
1268        cmd.append(s);
1269      }
1270      nextPassword = "-w".equals(s);
1271    }
1272    logger.info(LocalizableMessage.raw("configure DS cmd: " + cmd));
1273    final InstallerHelper helper = new InstallerHelper();
1274    setNotifyListeners(false);
1275    InvokeThread thread = new InvokeThread()
1276    {
1277      @Override
1278      public void run()
1279      {
1280        try
1281        {
1282          if (helper.invokeConfigureServer(args) != 0)
1283          {
1284            ae = new ApplicationException(ReturnCode.CONFIGURATION_ERROR, INFO_ERROR_CONFIGURING.get(), null);
1285          }
1286          else if (getUserData().getNewSuffixOptions().getBaseDns().isEmpty())
1287          {
1288            helper.deleteBackend(ROOT_BACKEND_NAME);
1289          }
1290        }
1291        catch (ApplicationException aex)
1292        {
1293          ae = aex;
1294        }
1295        catch (Throwable t)
1296        {
1297          ae = new ApplicationException(
1298              ReturnCode.CONFIGURATION_ERROR, getThrowableMsg(INFO_ERROR_CONFIGURING.get(), t), t);
1299        }
1300        finally
1301        {
1302          setNotifyListeners(true);
1303        }
1304        isOver = true;
1305      }
1306
1307      @Override
1308      public void abort()
1309      {
1310        // TODO: implement the abort
1311      }
1312    };
1313    invokeLongOperation(thread);
1314    notifyListeners(getFormattedDoneWithLineBreak());
1315    checkAbort();
1316    configureCertificate(sec);
1317  }
1318
1319  private void configureCertificate(SecurityOptions sec) throws ApplicationException
1320  {
1321    try
1322    {
1323      SecurityOptions.CertificateType certType = sec.getCertificateType();
1324      if (certType != SecurityOptions.CertificateType.NO_CERTIFICATE)
1325      {
1326        notifyListeners(getFormattedWithPoints(INFO_PROGRESS_UPDATING_CERTIFICATES.get()));
1327      }
1328
1329      switch (certType)
1330      {
1331      case NO_CERTIFICATE:
1332        // Nothing to do
1333        break;
1334      case SELF_SIGNED_CERTIFICATE:
1335        String pwd = getSelfSignedCertificatePwd();
1336        final CertificateManager certManager =
1337            new CertificateManager(getSelfSignedKeystorePath(), CertificateManager.KEY_STORE_TYPE_JKS, pwd);
1338        for (String alias : sec.getAliasesToUse())
1339        {
1340          final KeyType keyType = KeyType.getTypeOrDefault(alias);
1341          certManager.generateSelfSignedCertificate(keyType, alias, getSelfSignedCertificateSubjectDN(keyType),
1342              getSelfSignedCertificateValidity());
1343          SetupUtils.exportCertificate(certManager, alias, getTemporaryCertificatePath());
1344          configureTrustStore(CertificateManager.KEY_STORE_TYPE_JKS, alias, pwd);
1345        }
1346        break;
1347
1348      case JKS:
1349        configureKeyAndTrustStore(sec.getKeystorePath(), CertificateManager.KEY_STORE_TYPE_JKS,
1350            CertificateManager.KEY_STORE_TYPE_JKS, sec);
1351        break;
1352
1353      case JCEKS:
1354        configureKeyAndTrustStore(sec.getKeystorePath(), CertificateManager.KEY_STORE_TYPE_JCEKS,
1355            CertificateManager.KEY_STORE_TYPE_JCEKS, sec);
1356        break;
1357
1358      case PKCS12:
1359        configureKeyAndTrustStore(sec.getKeystorePath(), CertificateManager.KEY_STORE_TYPE_PKCS12,
1360            CertificateManager.KEY_STORE_TYPE_JKS, sec);
1361        break;
1362
1363      case PKCS11:
1364        configureKeyAndTrustStore(CertificateManager.KEY_STORE_PATH_PKCS11, CertificateManager.KEY_STORE_TYPE_PKCS11,
1365            CertificateManager.KEY_STORE_TYPE_JKS, sec);
1366        break;
1367
1368      default:
1369        throw new IllegalStateException("Unknown certificate type: " + certType);
1370      }
1371
1372      if (certType != SecurityOptions.CertificateType.NO_CERTIFICATE)
1373      {
1374        notifyListeners(getFormattedDoneWithLineBreak());
1375      }
1376    }
1377    catch (Throwable t)
1378    {
1379      logger.error(LocalizableMessage.raw("Error configuring certificate: " + t, t));
1380      throw new ApplicationException(
1381          ReturnCode.CONFIGURATION_ERROR, getThrowableMsg(INFO_ERROR_CONFIGURING_CERTIFICATE.get(), t), t);
1382    }
1383  }
1384
1385  private void configureKeyAndTrustStore(final String keyStorePath, final String keyStoreType,
1386      final String trustStoreType, final SecurityOptions sec) throws Exception
1387  {
1388    final String keystorePassword = sec.getKeystorePassword();
1389    CertificateManager certManager = new CertificateManager(keyStorePath, keyStoreType, keystorePassword);
1390    for (String keyStoreAlias : sec.getAliasesToUse())
1391    {
1392      SetupUtils.exportCertificate(certManager, keyStoreAlias, getTemporaryCertificatePath());
1393      configureTrustStore(trustStoreType, keyStoreAlias, keystorePassword);
1394    }
1395  }
1396
1397  private void configureTrustStore(final String type, final String keyStoreAlias, final String password)
1398      throws Exception
1399  {
1400    final String alias = keyStoreAlias != null ? keyStoreAlias : SELF_SIGNED_CERT_ALIASES[0];
1401    final CertificateManager trustMgr = new CertificateManager(getTrustManagerPath(), type, password);
1402    trustMgr.addCertificate(alias, new File(getTemporaryCertificatePath()));
1403
1404    createProtectedFile(getKeystorePinPath(), password);
1405    final File f = new File(getTemporaryCertificatePath());
1406    f.delete();
1407  }
1408
1409  private void addCertificateArguments(SecurityOptions sec, List<String> argList)
1410  {
1411    final Collection<String> aliasInKeyStore = sec.getAliasesToUse();
1412
1413    switch (sec.getCertificateType())
1414    {
1415    case SELF_SIGNED_CERTIFICATE:
1416      argList.add("-k");
1417      argList.add("cn=JKS,cn=Key Manager Providers,cn=config");
1418      argList.add("-t");
1419      argList.add("cn=JKS,cn=Trust Manager Providers,cn=config");
1420      break;
1421    case JKS:
1422      addCertificateArguments(argList, sec, aliasInKeyStore, "cn=JKS,cn=Key Manager Providers,cn=config",
1423          "cn=JKS,cn=Trust Manager Providers,cn=config");
1424      break;
1425    case JCEKS:
1426      addCertificateArguments(argList, sec, aliasInKeyStore, "cn=JCEKS,cn=Key Manager Providers,cn=config",
1427          "cn=JCEKS,cn=Trust Manager Providers,cn=config");
1428      break;
1429    case PKCS12:
1430      addCertificateArguments(argList, sec, aliasInKeyStore, "cn=PKCS12,cn=Key Manager Providers,cn=config",
1431          "cn=JKS,cn=Trust Manager Providers,cn=config");
1432      break;
1433    case PKCS11:
1434      addCertificateArguments(argList, null, aliasInKeyStore, "cn=PKCS11,cn=Key Manager Providers,cn=config",
1435          "cn=JKS,cn=Trust Manager Providers,cn=config");
1436      break;
1437    case NO_CERTIFICATE:
1438      // Nothing to do.
1439      break;
1440    default:
1441      throw new IllegalStateException("Unknown certificate type: " + sec.getCertificateType());
1442    }
1443  }
1444
1445  private static void addCertificateArguments(List<String> argList, SecurityOptions sec,
1446      Collection<String> aliasesInKeyStore, String keyStoreDN, String trustStoreDN)
1447  {
1448    argList.add("-k");
1449    argList.add(keyStoreDN);
1450    argList.add("-t");
1451    argList.add(trustStoreDN);
1452    if (sec != null)
1453    {
1454      argList.add("-m");
1455      argList.add(sec.getKeystorePath());
1456    }
1457    for(String alias : aliasesInKeyStore)
1458    {
1459      argList.add("-a");
1460      argList.add(alias);
1461    }
1462  }
1463
1464  /**
1465   * This methods creates the base entry for the suffix based on the contents of
1466   * the UserData object provided in the constructor.
1467   *
1468   * @throws ApplicationException
1469   *           if something goes wrong.
1470   */
1471  private void createBaseEntry() throws ApplicationException
1472  {
1473    LinkedList<String> baseDns = getUserData().getNewSuffixOptions().getBaseDns();
1474    if (baseDns.size() == 1)
1475    {
1476      notifyListeners(getFormattedWithPoints(INFO_PROGRESS_CREATING_BASE_ENTRY.get(baseDns.getFirst())));
1477    }
1478    else
1479    {
1480      notifyListeners(getFormattedWithPoints(INFO_PROGRESS_CREATING_BASE_ENTRIES.get()));
1481    }
1482
1483    final InstallerHelper helper = new InstallerHelper();
1484
1485    LinkedList<File> ldifFiles = new LinkedList<>();
1486
1487    for (String baseDn : baseDns)
1488    {
1489      ldifFiles.add(helper.createBaseEntryTempFile(baseDn));
1490    }
1491    checkAbort();
1492
1493    List<String> argList = new ArrayList<>();
1494    argList.add("-n");
1495    argList.add(ROOT_BACKEND_NAME);
1496    for (File f : ldifFiles)
1497    {
1498      argList.add("-l");
1499      argList.add(f.getAbsolutePath());
1500    }
1501    argList.add("-F");
1502    argList.add("-Q");
1503    argList.add("--noPropertiesFile");
1504
1505    final String[] args = new String[argList.size()];
1506    argList.toArray(args);
1507
1508    setNotifyListeners(false);
1509
1510    InvokeThread thread = new InvokeThread()
1511    {
1512      @Override
1513      public void run()
1514      {
1515        try
1516        {
1517          int result = helper.invokeImportLDIF(Installer.this, args);
1518
1519          if (result != 0)
1520          {
1521            ae = new ApplicationException(ReturnCode.IMPORT_ERROR, INFO_ERROR_CREATING_BASE_ENTRY.get(), null);
1522          }
1523        }
1524        catch (Throwable t)
1525        {
1526          ae =
1527              new ApplicationException(ReturnCode.IMPORT_ERROR,
1528                  getThrowableMsg(INFO_ERROR_CREATING_BASE_ENTRY.get(), t), t);
1529        }
1530        finally
1531        {
1532          setNotifyListeners(true);
1533        }
1534        isOver = true;
1535      }
1536
1537      @Override
1538      public void abort()
1539      {
1540        // TODO: implement the abort
1541      }
1542    };
1543    invokeLongOperation(thread);
1544    notifyListeners(getFormattedDoneWithLineBreak());
1545  }
1546
1547  /**
1548   * This methods imports the contents of an LDIF file based on the contents of
1549   * the UserData object provided in the constructor.
1550   *
1551   * @throws ApplicationException
1552   *           if something goes wrong.
1553   */
1554  private void importLDIF() throws ApplicationException
1555  {
1556    LinkedList<String> ldifPaths = getUserData().getNewSuffixOptions().getLDIFPaths();
1557    LocalizableMessageBuilder mb = new LocalizableMessageBuilder();
1558    if (ldifPaths.size() > 1)
1559    {
1560      if (isVerbose())
1561      {
1562        mb.append(getFormattedProgress(INFO_PROGRESS_IMPORTING_LDIFS.get(joinAsString(", ", ldifPaths))));
1563        mb.append(getLineBreak());
1564      }
1565      else
1566      {
1567        mb.append(getFormattedProgress(INFO_PROGRESS_IMPORTING_LDIFS_NON_VERBOSE.get(joinAsString(", ", ldifPaths))));
1568      }
1569    }
1570    else if (isVerbose())
1571    {
1572      mb.append(getFormattedProgress(INFO_PROGRESS_IMPORTING_LDIF.get(ldifPaths.getFirst())));
1573      mb.append(getLineBreak());
1574    }
1575    else
1576    {
1577      mb.append(getFormattedProgress(INFO_PROGRESS_IMPORTING_LDIF_NON_VERBOSE.get(ldifPaths.getFirst())));
1578    }
1579    notifyListeners(mb.toMessage());
1580
1581    final PointAdder pointAdder = new PointAdder();
1582
1583    if (!isVerbose())
1584    {
1585      setNotifyListeners(false);
1586      pointAdder.start();
1587    }
1588
1589    List<String> argList = new ArrayList<>();
1590    argList.add("-n");
1591    argList.add(ROOT_BACKEND_NAME);
1592    for (String ldifPath : ldifPaths)
1593    {
1594      argList.add("-l");
1595      argList.add(ldifPath);
1596    }
1597    argList.add("-F");
1598    String rejectedFile = getUserData().getNewSuffixOptions().getRejectedFile();
1599    if (rejectedFile != null)
1600    {
1601      argList.add("-R");
1602      argList.add(rejectedFile);
1603    }
1604    String skippedFile = getUserData().getNewSuffixOptions().getSkippedFile();
1605    if (skippedFile != null)
1606    {
1607      argList.add("--skipFile");
1608      argList.add(skippedFile);
1609    }
1610
1611    argList.add("--noPropertiesFile");
1612
1613    final String[] args = new String[argList.size()];
1614    argList.toArray(args);
1615
1616    InvokeThread thread = new InvokeThread()
1617    {
1618      @Override
1619      public void run()
1620      {
1621        try
1622        {
1623          InstallerHelper helper = new InstallerHelper();
1624          int result = helper.invokeImportLDIF(Installer.this, args);
1625
1626          if (result != 0)
1627          {
1628            ae = new ApplicationException(ReturnCode.IMPORT_ERROR, INFO_ERROR_IMPORTING_LDIF.get(), null);
1629          }
1630        }
1631        catch (Throwable t)
1632        {
1633          ae = new ApplicationException(
1634              ReturnCode.IMPORT_ERROR, getThrowableMsg(INFO_ERROR_IMPORTING_LDIF.get(), t), t);
1635        }
1636        finally
1637        {
1638          if (!isVerbose())
1639          {
1640            setNotifyListeners(true);
1641            pointAdder.stop();
1642          }
1643        }
1644        isOver = true;
1645      }
1646
1647      @Override
1648      public void abort()
1649      {
1650        // TODO: implement the abort
1651      }
1652    };
1653    try
1654    {
1655      invokeLongOperation(thread);
1656    }
1657    catch (ApplicationException ae)
1658    {
1659      if (!isVerbose() && lastImportProgress != null)
1660      {
1661        notifyListeners(getFormattedProgress(LocalizableMessage.raw(lastImportProgress)));
1662        notifyListeners(getLineBreak());
1663      }
1664      throw ae;
1665    }
1666    if (!isVerbose())
1667    {
1668      if (lastImportProgress == null)
1669      {
1670        notifyListeners(getFormattedDoneWithLineBreak());
1671      }
1672      else
1673      {
1674        notifyListeners(getFormattedProgress(LocalizableMessage.raw(lastImportProgress)));
1675        notifyListeners(getLineBreak());
1676      }
1677    }
1678  }
1679
1680  /**
1681   * This methods imports automatically generated data based on the contents of
1682   * the UserData object provided in the constructor.
1683   *
1684   * @throws ApplicationException
1685   *           if something goes wrong.
1686   */
1687  private void importAutomaticallyGenerated() throws ApplicationException
1688  {
1689    File templatePath = createTemplateFile();
1690    int nEntries = getUserData().getNewSuffixOptions().getNumberEntries();
1691    LocalizableMessageBuilder mb = new LocalizableMessageBuilder();
1692    if (isVerbose() || nEntries > THRESHOLD_AUTOMATIC_DATA_VERBOSE)
1693    {
1694      mb.append(getFormattedProgress(INFO_PROGRESS_IMPORT_AUTOMATICALLY_GENERATED.get(nEntries)));
1695      mb.append(getLineBreak());
1696    }
1697    else
1698    {
1699      mb.append(getFormattedProgress(INFO_PROGRESS_IMPORT_AUTOMATICALLY_GENERATED_NON_VERBOSE.get(nEntries)));
1700    }
1701    notifyListeners(mb.toMessage());
1702
1703    final PointAdder pointAdder = new PointAdder();
1704    if (!isVerbose())
1705    {
1706      pointAdder.start();
1707    }
1708
1709    if (!isVerbose())
1710    {
1711      setNotifyListeners(false);
1712    }
1713    final List<String> argList = new ArrayList<>();
1714    argList.add("-n");
1715    argList.add(ROOT_BACKEND_NAME);
1716    argList.add("-A");
1717    argList.add(templatePath.getAbsolutePath());
1718    argList.add("-s"); // seed
1719    argList.add("0");
1720    argList.add("-F");
1721    argList.add("--noPropertiesFile");
1722
1723    final String[] args = new String[argList.size()];
1724    argList.toArray(args);
1725
1726    InvokeThread thread = new InvokeThread()
1727    {
1728      @Override
1729      public void run()
1730      {
1731        try
1732        {
1733          InstallerHelper helper = new InstallerHelper();
1734          int result = helper.invokeImportLDIF(Installer.this, args);
1735
1736          if (result != 0)
1737          {
1738            ae = new ApplicationException(
1739                ReturnCode.IMPORT_ERROR, INFO_ERROR_IMPORT_LDIF_TOOL_RETURN_CODE.get(result), null);
1740          }
1741        }
1742        catch (Throwable t)
1743        {
1744          ae = new ApplicationException(ReturnCode.IMPORT_ERROR, getThrowableMsg(
1745                      INFO_ERROR_IMPORT_AUTOMATICALLY_GENERATED.get(joinAsString(" ", argList),
1746                      t.getLocalizedMessage()), t), t);
1747        }
1748        finally
1749        {
1750          if (!isVerbose())
1751          {
1752            setNotifyListeners(true);
1753            if (ae != null)
1754            {
1755              pointAdder.stop();
1756            }
1757          }
1758        }
1759        isOver = true;
1760      }
1761
1762      @Override
1763      public void abort()
1764      {
1765        // TODO: implement the abort
1766      }
1767    };
1768    invokeLongOperation(thread);
1769    if (!isVerbose())
1770    {
1771      pointAdder.stop();
1772      notifyListeners(getFormattedDoneWithLineBreak());
1773    }
1774  }
1775
1776  /**
1777   * This method undoes the modifications made in other servers in terms of
1778   * replication. This method assumes that we are aborting the Installer and
1779   * that is why it does not call checkAbort.
1780   */
1781  private void unconfigureRemote()
1782  {
1783    if (registeredNewServerOnRemote || createdAdministrator || createdRemoteAds)
1784    {
1785      // Try to connect
1786      DataReplicationOptions repl = getUserData().getReplicationOptions();
1787      AuthenticationData auth = repl.getAuthenticationData();
1788      if (isVerbose())
1789      {
1790        notifyListeners(getFormattedWithPoints(INFO_PROGRESS_UNCONFIGURING_ADS_ON_REMOTE.get(auth.getHostPort())));
1791      }
1792      try (ConnectionWrapper connectionWrapper = createConnection(auth))
1793      {
1794        ADSContext adsContext = new ADSContext(connectionWrapper);
1795        if (createdRemoteAds)
1796        {
1797          adsContext.removeAdminData(true);
1798        }
1799        else
1800        {
1801          if (registeredNewServerOnRemote)
1802          {
1803            try
1804            {
1805              adsContext.unregisterServer(getNewServerAdsProperties(getUserData()));
1806            }
1807            catch (ADSContextException ace)
1808            {
1809              if (ace.getError() != ADSContextException.ErrorType.NOT_YET_REGISTERED)
1810              {
1811                throw ace;
1812              }
1813              // Else, nothing to do: this may occur if the new server has been
1814              // unregistered on another server and the modification has been
1815              // already propagated by replication.
1816            }
1817          }
1818          if (createdAdministrator)
1819          {
1820            adsContext.deleteAdministrator(getAdministratorProperties(getUserData()));
1821          }
1822        }
1823        if (isVerbose())
1824        {
1825          notifyListeners(getFormattedDoneWithLineBreak());
1826        }
1827      }
1828      catch (Throwable t)
1829      {
1830        notifyListeners(getFormattedError(t, true));
1831      }
1832    }
1833    InstallerHelper helper = new InstallerHelper();
1834    for (ServerDescriptor server : hmConfiguredRemoteReplication.keySet())
1835    {
1836      notifyListeners(getFormattedWithPoints(INFO_PROGRESS_UNCONFIGURING_REPLICATION_REMOTE.get(getHostPort(server))));
1837      try (ConnectionWrapper connectionWrapper = getRemoteConnection(server))
1838      {
1839        helper.unconfigureReplication(connectionWrapper, hmConfiguredRemoteReplication.get(server));
1840      }
1841      catch (ApplicationException ae)
1842      {
1843        notifyListeners(getFormattedError(ae, true));
1844      }
1845      notifyListeners(getFormattedDoneWithLineBreak());
1846    }
1847  }
1848
1849  /**
1850   * This method configures the backends and suffixes that must be replicated.
1851   * The setup uses the same backend names as in the remote servers. If userRoot
1852   * is not one of the backends defined in the remote servers, it deletes it
1853   * from the configuration. NOTE: this method assumes that the server is
1854   * running.
1855   *
1856   * @throws ApplicationException
1857   *           if something goes wrong.
1858   */
1859  private void createReplicatedBackendsIfRequired() throws ApplicationException
1860  {
1861    if (FIRST_IN_TOPOLOGY == getUserData().getReplicationOptions().getType())
1862    {
1863      return;
1864    }
1865    notifyListeners(getFormattedWithPoints(INFO_PROGRESS_CREATING_REPLICATED_BACKENDS.get()));
1866
1867    // The keys are the backend IDs and the values the list of base DNs.
1868    final Map<String, Set<String>> hmBackendSuffix = new HashMap<>();
1869    final SuffixesToReplicateOptions suffixData = getUserData().getSuffixesToReplicateOptions();
1870    populateBackendsToCreate(hmBackendSuffix, suffixData.getSuffixes());
1871    createReplicatedBackends(hmBackendSuffix, suffixData.getSuffixBackendTypes());
1872    notifyListeners(getFormattedDoneWithLineBreak());
1873    checkAbort();
1874  }
1875
1876  /**
1877   * The criteria to choose the name of the backend is to try to have the
1878   * configuration of the other server. The algorithm consists on putting the
1879   * remote servers in a list and pick the backend as they appear on the list.
1880   */
1881  private void populateBackendsToCreate(Map<String, Set<String>> hmBackendSuffix, Set<SuffixDescriptor> suffixes)
1882  {
1883    Set<ServerDescriptor> serverList = getServerListFromSuffixes(suffixes);
1884    for (SuffixDescriptor suffix : suffixes)
1885    {
1886      final ReplicaDescriptor replica = retrieveReplicaForSuffix(serverList, suffix);
1887      if (replica != null)
1888      {
1889        final String backendNameKey = getOrAddBackend(hmBackendSuffix, replica.getBackendName());
1890        hmBackendSuffix.get(backendNameKey).add(suffix.getDN());
1891      }
1892    }
1893  }
1894
1895  private Set<ServerDescriptor> getServerListFromSuffixes(Set<SuffixDescriptor> suffixes)
1896  {
1897    Set<ServerDescriptor> serverList = new LinkedHashSet<>();
1898    for (SuffixDescriptor suffix : suffixes)
1899    {
1900      for (ReplicaDescriptor replica : suffix.getReplicas())
1901      {
1902        serverList.add(replica.getServer());
1903      }
1904    }
1905    return serverList;
1906  }
1907
1908  private ReplicaDescriptor retrieveReplicaForSuffix(Set<ServerDescriptor> serverList, SuffixDescriptor suffix)
1909  {
1910    for (ServerDescriptor server : serverList)
1911    {
1912      for (ReplicaDescriptor replica : suffix.getReplicas())
1913      {
1914        if (replica.getServer() == server)
1915        {
1916          return replica;
1917        }
1918      }
1919    }
1920    return null;
1921  }
1922
1923  private String getOrAddBackend(Map<String, Set<String>> hmBackendSuffix, String backendName)
1924  {
1925    for (String storedBackend : hmBackendSuffix.keySet())
1926    {
1927      if (storedBackend.equalsIgnoreCase(backendName))
1928      {
1929        return storedBackend;
1930      }
1931    }
1932    hmBackendSuffix.put(backendName, new HashSet<String>());
1933    return backendName;
1934  }
1935
1936  private void createReplicatedBackends(final Map<String, Set<String>> hmBackendSuffix,
1937      final Map<String, BackendTypeUIAdapter> backendTypes) throws ApplicationException
1938  {
1939    try (ConnectionWrapper connection = createLocalConnection())
1940    {
1941      final InstallerHelper helper = new InstallerHelper();
1942      for (String backendName : hmBackendSuffix.keySet())
1943      {
1944        helper.createBackend(connection, backendName, hmBackendSuffix.get(backendName),
1945            backendTypes.get(backendName).getBackend());
1946      }
1947    }
1948    catch (NamingException ne)
1949    {
1950      LocalizableMessage failedMsg = getThrowableMsg(INFO_ERROR_CONNECTING_TO_LOCAL.get(), ne);
1951      throw new ApplicationException(ReturnCode.CONFIGURATION_ERROR, failedMsg, ne);
1952    }
1953  }
1954
1955  /**
1956   * This method creates the replication configuration for the suffixes on the
1957   * the local server (and eventually in the remote servers) to synchronize
1958   * things. NOTE: this method assumes that the server is running.
1959   *
1960   * @throws ApplicationException
1961   *           if something goes wrong.
1962   */
1963  private void configureReplication() throws ApplicationException
1964  {
1965    notifyListeners(getFormattedWithPoints(INFO_PROGRESS_CONFIGURING_REPLICATION.get()));
1966
1967    InstallerHelper helper = new InstallerHelper();
1968    Set<Integer> knownServerIds = new HashSet<>();
1969    Set<Integer> knownReplicationServerIds = new HashSet<>();
1970    if (lastLoadedCache != null)
1971    {
1972      for (SuffixDescriptor suffix : lastLoadedCache.getSuffixes())
1973      {
1974        for (ReplicaDescriptor replica : suffix.getReplicas())
1975        {
1976          knownServerIds.add(replica.getReplicationId());
1977        }
1978      }
1979      for (ServerDescriptor server : lastLoadedCache.getServers())
1980      {
1981        Object v = server.getServerProperties().get(REPLICATION_SERVER_ID);
1982        if (v != null)
1983        {
1984          knownReplicationServerIds.add((Integer) v);
1985        }
1986      }
1987    }
1988    else
1989    {
1990      /* There is no ADS anywhere. Just use the SuffixDescriptors we found */
1991      for (SuffixDescriptor suffix : getUserData().getSuffixesToReplicateOptions().getAvailableSuffixes())
1992      {
1993        for (ReplicaDescriptor replica : suffix.getReplicas())
1994        {
1995          knownServerIds.add(replica.getReplicationId());
1996          Object v = replica.getServer().getServerProperties().get(REPLICATION_SERVER_ID);
1997          if (v != null)
1998          {
1999            knownReplicationServerIds.add((Integer) v);
2000          }
2001        }
2002      }
2003    }
2004
2005    /*
2006     * For each suffix specified by the user, create a map from the suffix DN to
2007     * the set of replication servers. The initial instance in a topology is a
2008     * degenerate case. Also, collect a set of all observed replication servers
2009     * as the set of ADS suffix replicas (all instances hosting the replication
2010     * server also replicate ADS).
2011     */
2012    Map<String, Set<String>> replicationServers = new HashMap<>();
2013    Set<String> adsServers = new HashSet<>();
2014
2015    if (getUserData().getReplicationOptions().getType() == DataReplicationOptions.Type.FIRST_IN_TOPOLOGY)
2016    {
2017      List<String> baseDns = getUserData().getNewSuffixOptions().getBaseDns();
2018      Set<String> h = new HashSet<>();
2019      h.add(getLocalReplicationServer());
2020      adsServers.add(getLocalReplicationServer());
2021      for (String dn : baseDns)
2022      {
2023        replicationServers.put(dn, h);
2024      }
2025    }
2026    else
2027    {
2028      Set<SuffixDescriptor> suffixes = getUserData().getSuffixesToReplicateOptions().getSuffixes();
2029      for (SuffixDescriptor suffix : suffixes)
2030      {
2031        Set<String> h = new HashSet<>(suffix.getReplicationServers());
2032        adsServers.addAll(suffix.getReplicationServers());
2033        h.add(getLocalReplicationServer());
2034        adsServers.add(getLocalReplicationServer());
2035        for (ReplicaDescriptor replica : suffix.getReplicas())
2036        {
2037          ServerDescriptor server = replica.getServer();
2038          AuthenticationData repPort = getUserData().getRemoteWithNoReplicationPort().get(server);
2039          if (repPort != null)
2040          {
2041            String serverDisplay = server.getHostName() + ":" + repPort.getPort();
2042            h.add(serverDisplay);
2043            adsServers.add(serverDisplay);
2044          }
2045        }
2046        replicationServers.put(suffix.getDN(), h);
2047      }
2048    }
2049    replicationServers.put(ADSContext.getAdministrationSuffixDN(), adsServers);
2050    replicationServers.put(Constants.SCHEMA_DN, new HashSet<String>(adsServers));
2051
2052    long localTime = -1;
2053    long localTimeMeasureTime = -1;
2054    HostPort localServerDisplay = null;
2055    try (ConnectionWrapper conn = createLocalConnection())
2056    {
2057      helper.configureReplication(conn, replicationServers,
2058          getUserData().getReplicationOptions().getReplicationPort(),
2059          getUserData().getReplicationOptions().useSecureReplication(),
2060          knownReplicationServerIds,
2061          knownServerIds);
2062      localTimeMeasureTime = System.currentTimeMillis();
2063      localTime = Utils.getServerClock(conn.getLdapContext());
2064      localServerDisplay = conn.getHostPort();
2065    }
2066    catch (NamingException ne)
2067    {
2068      LocalizableMessage failedMsg = getThrowableMsg(INFO_ERROR_CONNECTING_TO_LOCAL.get(), ne);
2069      throw new ApplicationException(ReturnCode.CONFIGURATION_ERROR, failedMsg, ne);
2070    }
2071    notifyListeners(getFormattedDoneWithLineBreak());
2072    checkAbort();
2073
2074    if (getUserData().getReplicationOptions().getType() == DataReplicationOptions.Type.IN_EXISTING_TOPOLOGY)
2075    {
2076      Map<ServerDescriptor, Set<ReplicaDescriptor>> hm = new HashMap<>();
2077      for (SuffixDescriptor suffix : getUserData().getSuffixesToReplicateOptions().getSuffixes())
2078      {
2079        for (ReplicaDescriptor replica : suffix.getReplicas())
2080        {
2081          Set<ReplicaDescriptor> replicas = hm.get(replica.getServer());
2082          if (replicas == null)
2083          {
2084            replicas = new HashSet<>();
2085            hm.put(replica.getServer(), replicas);
2086          }
2087          replicas.add(replica);
2088        }
2089      }
2090      for (ServerDescriptor server : hm.keySet())
2091      {
2092        notifyListeners(getFormattedWithPoints(INFO_PROGRESS_CONFIGURING_REPLICATION_REMOTE.get(getHostPort(server))));
2093        Integer v = (Integer) server.getServerProperties().get(REPLICATION_SERVER_PORT);
2094        int replicationPort;
2095        boolean enableSecureReplication;
2096        if (v != null)
2097        {
2098          replicationPort = v;
2099          enableSecureReplication = false;
2100        }
2101        else
2102        {
2103          AuthenticationData authData = getUserData().getRemoteWithNoReplicationPort().get(server);
2104          if (authData != null)
2105          {
2106            replicationPort = authData.getPort();
2107            enableSecureReplication = authData.useSecureConnection();
2108          }
2109          else
2110          {
2111            replicationPort = Constants.DEFAULT_REPLICATION_PORT;
2112            enableSecureReplication = false;
2113            logger.warn(LocalizableMessage.raw("Could not find replication port for: " + getHostPort(server)));
2114          }
2115        }
2116        Set<String> dns = new HashSet<>();
2117        for (ReplicaDescriptor replica : hm.get(server))
2118        {
2119          dns.add(replica.getSuffix().getDN());
2120        }
2121        dns.add(ADSContext.getAdministrationSuffixDN());
2122        dns.add(Constants.SCHEMA_DN);
2123        Map<String, Set<String>> remoteReplicationServers = new HashMap<>();
2124        for (String dn : dns)
2125        {
2126          Set<String> repServer = replicationServers.get(dn);
2127          if (repServer == null)
2128          {
2129            // Do the comparison manually
2130            for (String dn1 : replicationServers.keySet())
2131            {
2132              if (Utils.areDnsEqual(dn, dn1))
2133              {
2134                repServer = replicationServers.get(dn1);
2135                dn = dn1;
2136                break;
2137              }
2138            }
2139          }
2140          if (repServer != null)
2141          {
2142            remoteReplicationServers.put(dn, repServer);
2143          }
2144          else
2145          {
2146            logger.warn(LocalizableMessage.raw("Could not find replication server for: " + dn));
2147          }
2148        }
2149
2150        try (ConnectionWrapper conn = getRemoteConnection(server))
2151        {
2152          ConfiguredReplication repl = helper.configureReplication(
2153              conn, remoteReplicationServers, replicationPort, enableSecureReplication,
2154              knownReplicationServerIds, knownServerIds);
2155          long remoteTimeMeasureTime = System.currentTimeMillis();
2156          long remoteTime = Utils.getServerClock(conn.getLdapContext());
2157          if (localTime != -1
2158              && remoteTime != -1
2159              && Math.abs(localTime - remoteTime - localTimeMeasureTime + remoteTimeMeasureTime) >
2160          THRESHOLD_CLOCK_DIFFERENCE_WARNING * 60 * 1000)
2161          {
2162            notifyListeners(getFormattedWarning(INFO_WARNING_SERVERS_CLOCK_DIFFERENCE.get(
2163                localServerDisplay, conn.getHostPort(), THRESHOLD_CLOCK_DIFFERENCE_WARNING)));
2164          }
2165
2166          hmConfiguredRemoteReplication.put(server, repl);
2167        }
2168
2169        notifyListeners(getFormattedDoneWithLineBreak());
2170        checkAbort();
2171      }
2172    }
2173  }
2174
2175  /**
2176   * This methods enables this server as a Windows service.
2177   *
2178   * @throws ApplicationException
2179   *           if something goes wrong.
2180   */
2181  private void enableWindowsService() throws ApplicationException
2182  {
2183    notifyListeners(getFormattedWithPoints(INFO_PROGRESS_ENABLING_WINDOWS_SERVICE.get()));
2184    InstallerHelper helper = new InstallerHelper();
2185    helper.enableWindowsService();
2186    notifyListeners(getLineBreak());
2187  }
2188
2189  /**
2190   * Updates the contents of the provided map with the localized summary
2191   * strings.
2192   *
2193   * @param hmSummary
2194   *          the Map to be updated.
2195   * @param isCli
2196   *          a boolean to indicate if the install is using CLI or GUI
2197   */
2198  private void initSummaryMap(Map<ProgressStep, LocalizableMessage> hmSummary, boolean isCli)
2199  {
2200    put(hmSummary, NOT_STARTED, INFO_SUMMARY_INSTALL_NOT_STARTED);
2201    put(hmSummary, CONFIGURING_SERVER, INFO_SUMMARY_CONFIGURING);
2202    put(hmSummary, CREATING_BASE_ENTRY, INFO_SUMMARY_CREATING_BASE_ENTRY);
2203    put(hmSummary, IMPORTING_LDIF, INFO_SUMMARY_IMPORTING_LDIF);
2204    put(hmSummary, IMPORTING_AUTOMATICALLY_GENERATED, INFO_SUMMARY_IMPORTING_AUTOMATICALLY_GENERATED);
2205    put(hmSummary, CONFIGURING_REPLICATION, INFO_SUMMARY_CONFIGURING_REPLICATION);
2206    put(hmSummary, STARTING_SERVER, INFO_SUMMARY_STARTING);
2207    put(hmSummary, STOPPING_SERVER, INFO_SUMMARY_STOPPING);
2208    put(hmSummary, CONFIGURING_ADS, INFO_SUMMARY_CONFIGURING_ADS);
2209    put(hmSummary, INITIALIZE_REPLICATED_SUFFIXES, INFO_SUMMARY_INITIALIZE_REPLICATED_SUFFIXES);
2210    put(hmSummary, ENABLING_WINDOWS_SERVICE, INFO_SUMMARY_ENABLING_WINDOWS_SERVICE);
2211    put(hmSummary, WAITING_TO_CANCEL, INFO_SUMMARY_WAITING_TO_CANCEL);
2212    put(hmSummary, CANCELING, INFO_SUMMARY_CANCELING);
2213
2214    Installation installation = getInstallation();
2215    String cmd = Utils.addWordBreaks(getPath(installation.getControlPanelCommandFile()), 60, 5);
2216    if (!isCli)
2217    {
2218      cmd = UIFactory.applyFontToHtml(cmd, UIFactory.INSTRUCTIONS_MONOSPACE_FONT);
2219    }
2220    String formattedPath =
2221        Utils.addWordBreaks(formatter.getFormattedText(LocalizableMessage.raw(getPath(new File(getInstancePath()))))
2222            .toString(), 60, 5);
2223    LocalizableMessage successMessage =
2224        Utils.getCustomizedObject("INFO_SUMMARY_INSTALL_FINISHED_SUCCESSFULLY",
2225            INFO_SUMMARY_INSTALL_FINISHED_SUCCESSFULLY.get(DynamicConstants.PRODUCT_NAME,
2226                DynamicConstants.PRODUCT_NAME, formattedPath, INFO_GENERAL_SERVER_STOPPED.get(),
2227                DynamicConstants.DOC_QUICK_REFERENCE_GUIDE, DynamicConstants.PRODUCT_NAME, cmd),
2228            LocalizableMessage.class);
2229    hmSummary.put(FINISHED_SUCCESSFULLY, getFormattedSuccess(successMessage));
2230    hmSummary.put(FINISHED_CANCELED, getFormattedSuccess(INFO_SUMMARY_INSTALL_FINISHED_CANCELED.get()));
2231    hmSummary.put(FINISHED_WITH_ERROR,
2232        getFormattedError(INFO_SUMMARY_INSTALL_FINISHED_WITH_ERROR.get(INFO_GENERAL_SERVER_STOPPED.get(), cmd)));
2233  }
2234
2235  private void put(Map<ProgressStep, LocalizableMessage> hmSummary, InstallProgressStep step, Arg0 msg)
2236  {
2237    hmSummary.put(step, getFormattedSummary(msg.get()));
2238  }
2239
2240  /**
2241   * Updates the messages in the summary with the state of the server.
2242   *
2243   * @param hmSummary
2244   *          the Map containing the messages.
2245   * @param isCli
2246   *          a boolean to indicate if the install is using CLI or GUI
2247   */
2248  private void updateSummaryWithServerState(Map<ProgressStep, LocalizableMessage> hmSummary, Boolean isCli)
2249  {
2250    Installation installation = getInstallation();
2251    String cmd = getPath(installation.getControlPanelCommandFile());
2252    if (!isCli)
2253    {
2254      cmd = Utils.addWordBreaks(UIFactory.applyFontToHtml(cmd, UIFactory.INSTRUCTIONS_MONOSPACE_FONT), 60, 5);
2255    }
2256    LocalizableMessage status;
2257    if (installation.getStatus().isServerRunning())
2258    {
2259      status = INFO_GENERAL_SERVER_STARTED.get();
2260    }
2261    else
2262    {
2263      status = INFO_GENERAL_SERVER_STOPPED.get();
2264    }
2265    String formattedPath =
2266        Utils.addWordBreaks(formatter.getFormattedText(LocalizableMessage.raw(getPath(new File(getInstancePath()))))
2267            .toString(), 60, 5);
2268    LocalizableMessage successMessage =
2269        Utils.getCustomizedObject("INFO_SUMMARY_INSTALL_FINISHED_SUCCESSFULLY",
2270            INFO_SUMMARY_INSTALL_FINISHED_SUCCESSFULLY.get(DynamicConstants.PRODUCT_NAME,
2271                DynamicConstants.PRODUCT_NAME, formattedPath, status, DynamicConstants.DOC_QUICK_REFERENCE_GUIDE,
2272                DynamicConstants.PRODUCT_NAME, cmd), LocalizableMessage.class);
2273    hmSummary.put(InstallProgressStep.FINISHED_SUCCESSFULLY, getFormattedSuccess(successMessage));
2274    hmSummary.put(InstallProgressStep.FINISHED_WITH_ERROR, getFormattedError(INFO_SUMMARY_INSTALL_FINISHED_WITH_ERROR
2275        .get(status, cmd)));
2276  }
2277
2278  /**
2279   * Checks the value of <code>canceled</code> field and throws an
2280   * ApplicationException if true. This indicates that the user has canceled
2281   * this operation and the process of aborting should begin as soon as
2282   * possible.
2283   *
2284   * @throws ApplicationException
2285   *           thrown if <code>canceled</code>
2286   */
2287  @Override
2288  public void checkAbort() throws ApplicationException
2289  {
2290    if (canceled)
2291    {
2292      setCurrentProgressStep(InstallProgressStep.CANCELING);
2293      notifyListeners(null);
2294      throw new ApplicationException(ReturnCode.CANCELED, INFO_INSTALL_CANCELED.get(), null);
2295    }
2296  }
2297
2298  /**
2299   * Writes the host name to a file that will be used by the server to generate
2300   * a self-signed certificate.
2301   */
2302  private void writeHostName()
2303  {
2304    try (BufferedWriter writer = new BufferedWriter(new FileWriter(getHostNameFile(), false)))
2305    {
2306      writer.append(getUserData().getHostName());
2307    }
2308    catch (IOException ioe)
2309    {
2310      logger.warn(LocalizableMessage.raw("Error writing host name file: " + ioe, ioe));
2311    }
2312  }
2313
2314  /**
2315   * Returns the file path where the host name is to be written.
2316   *
2317   * @return the file path where the host name is to be written.
2318   */
2319  private String getHostNameFile()
2320  {
2321    return Utils.getPath(getInstallation().getRootDirectory().getAbsolutePath(), SetupUtils.HOST_NAME_FILE);
2322  }
2323
2324  /**
2325   * Writes the java home that we are using for the setup in a file. This way we
2326   * can use this java home even if the user has not set OPENDJ_JAVA_HOME when
2327   * running the different scripts.
2328   */
2329  private void writeOpenDSJavaHome()
2330  {
2331    try
2332    {
2333      // This isn't likely to happen, and it's not a serious problem even if
2334      // it does.
2335      InstallerHelper helper = new InstallerHelper();
2336      helper.writeSetOpenDSJavaHome(getUserData(), getInstallationPath());
2337    }
2338    catch (Exception e)
2339    {
2340      logger.warn(LocalizableMessage.raw("Error writing OpenDJ Java Home file: " + e, e));
2341    }
2342  }
2343
2344  /**
2345   * These methods validate the data provided by the user in the panels and
2346   * update the userData object according to that content.
2347   *
2348   * @param cStep
2349   *          the current step of the wizard
2350   * @param qs
2351   *          QuickStart controller
2352   * @throws UserDataException
2353   *           if the data provided by the user is not valid.
2354   */
2355  @Override
2356  public void updateUserData(WizardStep cStep, QuickSetup qs) throws UserDataException
2357  {
2358    if (cStep == SERVER_SETTINGS)
2359    {
2360      updateUserDataForServerSettingsPanel(qs);
2361    }
2362    else if (cStep == REPLICATION_OPTIONS)
2363    {
2364      updateUserDataForReplicationOptionsPanel(qs);
2365    }
2366    else if (cStep == CREATE_GLOBAL_ADMINISTRATOR)
2367    {
2368      updateUserDataForCreateAdministratorPanel(qs);
2369    }
2370    else if (cStep == SUFFIXES_OPTIONS)
2371    {
2372      updateUserDataForSuffixesOptionsPanel(qs);
2373    }
2374    else if (cStep == REMOTE_REPLICATION_PORTS)
2375    {
2376      updateUserDataForRemoteReplicationPorts(qs);
2377    }
2378    else if (cStep == NEW_SUFFIX_OPTIONS)
2379    {
2380      updateUserDataForNewSuffixOptionsPanel(qs);
2381    }
2382    else if (cStep == RUNTIME_OPTIONS)
2383    {
2384      updateUserDataForRuntimeOptionsPanel(qs);
2385    }
2386    else if (cStep == REVIEW)
2387    {
2388      updateUserDataForReviewPanel(qs);
2389    }
2390  }
2391
2392  /**
2393   * Sets the current progress step of the installation process.
2394   *
2395   * @param currentProgressStep
2396   *          the current progress step of the installation process.
2397   */
2398  private void setCurrentProgressStep(InstallProgressStep currentProgressStep)
2399  {
2400    if (currentProgressStep != null)
2401    {
2402      this.completedProgress.add(currentProgressStep);
2403    }
2404    this.currentProgressStep = currentProgressStep;
2405  }
2406
2407  /**
2408   * This methods updates the data on the server based on the contents of the
2409   * UserData object provided in the constructor.
2410   *
2411   * @throws ApplicationException
2412   *           if something goes wrong.
2413   */
2414  private void createData() throws ApplicationException
2415  {
2416    if (createNotReplicatedSuffix()
2417        && NewSuffixOptions.Type.LEAVE_DATABASE_EMPTY != getUserData().getNewSuffixOptions().getType())
2418    {
2419      currentProgressStep = getUserData().getNewSuffixOptions().getInstallProgressStep();
2420      if (isVerbose())
2421      {
2422        notifyListeners(getTaskSeparator());
2423      }
2424
2425      switch (getUserData().getNewSuffixOptions().getType())
2426      {
2427      case CREATE_BASE_ENTRY:
2428        createBaseEntry();
2429        break;
2430      case IMPORT_FROM_LDIF_FILE:
2431        importLDIF();
2432        break;
2433      case IMPORT_AUTOMATICALLY_GENERATED_DATA:
2434        importAutomaticallyGenerated();
2435        break;
2436      default:
2437        break;
2438      }
2439    }
2440  }
2441
2442  /**
2443   * This method initialize the contents of the synchronized servers with the
2444   * contents of the first server we find.
2445   *
2446   * @throws ApplicationException
2447   *           if something goes wrong.
2448   */
2449  private void initializeSuffixes() throws ApplicationException
2450  {
2451    ConnectionWrapper conn = null;
2452    try
2453    {
2454      conn = createLocalConnection();
2455    }
2456    catch (Throwable t)
2457    {
2458      LocalizableMessage failedMsg = getThrowableMsg(INFO_ERROR_CONNECTING_TO_LOCAL.get(), t);
2459      StaticUtils.close(conn);
2460      throw new ApplicationException(ReturnCode.CONFIGURATION_ERROR, failedMsg, t);
2461    }
2462
2463    Set<SuffixDescriptor> suffixes = getUserData().getSuffixesToReplicateOptions().getSuffixes();
2464
2465    /* Initialize local ADS and schema contents using any replica. */
2466    {
2467      ServerDescriptor server = suffixes.iterator().next().getReplicas().iterator().next().getServer();
2468      try (ConnectionWrapper remoteConn = getRemoteConnection(server))
2469      {
2470        TopologyCacheFilter filter = new TopologyCacheFilter();
2471        filter.setSearchMonitoringInformation(false);
2472        filter.addBaseDNToSearch(ADSContext.getAdministrationSuffixDN());
2473        filter.addBaseDNToSearch(Constants.SCHEMA_DN);
2474        ServerDescriptor s = createStandalone(remoteConn.getLdapContext(), filter);
2475        for (ReplicaDescriptor replica : s.getReplicas())
2476        {
2477          String dn = replica.getSuffix().getDN();
2478          if (areDnsEqual(dn, ADSContext.getAdministrationSuffixDN()))
2479          {
2480            suffixes.add(replica.getSuffix());
2481          }
2482          else if (areDnsEqual(dn, Constants.SCHEMA_DN))
2483          {
2484            suffixes.add(replica.getSuffix());
2485          }
2486        }
2487      }
2488      catch (NamingException ne)
2489      {
2490        LocalizableMessage msg;
2491        if (isCertificateException(ne))
2492        {
2493          msg = INFO_ERROR_READING_CONFIG_LDAP_CERTIFICATE_SERVER.get(getHostPort(server), ne.toString(true));
2494        }
2495        else
2496        {
2497          msg = INFO_CANNOT_CONNECT_TO_REMOTE_GENERIC.get(getHostPort(server), ne.toString(true));
2498        }
2499        throw new ApplicationException(ReturnCode.CONFIGURATION_ERROR, msg, ne);
2500      }
2501    }
2502
2503    for (SuffixDescriptor suffix : suffixes)
2504    {
2505      String dn = suffix.getDN();
2506
2507      ReplicaDescriptor replica = suffix.getReplicas().iterator().next();
2508      ServerDescriptor server = replica.getServer();
2509      HostPort hostPort = getHostPort(server);
2510
2511      boolean isADS = areDnsEqual(dn, ADSContext.getAdministrationSuffixDN());
2512      boolean isSchema = areDnsEqual(dn, Constants.SCHEMA_DN);
2513      if (isADS)
2514      {
2515        if (isVerbose())
2516        {
2517          notifyListeners(getFormattedWithPoints(INFO_PROGRESS_INITIALIZING_ADS.get()));
2518        }
2519      }
2520      else if (isSchema)
2521      {
2522        if (isVerbose())
2523        {
2524          notifyListeners(getFormattedWithPoints(INFO_PROGRESS_INITIALIZING_SCHEMA.get()));
2525        }
2526      }
2527      else
2528      {
2529        notifyListeners(getFormattedProgress(INFO_PROGRESS_INITIALIZING_SUFFIX.get(dn, hostPort)));
2530        notifyListeners(getLineBreak());
2531      }
2532      try
2533      {
2534        int replicationId = replica.getReplicationId();
2535        if (replicationId == -1)
2536        {
2537          // This occurs if the remote server had not replication configured.
2538          try (ConnectionWrapper remoteConn = getRemoteConnection(server))
2539          {
2540            TopologyCacheFilter filter = new TopologyCacheFilter();
2541            filter.setSearchMonitoringInformation(false);
2542            filter.addBaseDNToSearch(dn);
2543            ServerDescriptor s = createStandalone(remoteConn.getLdapContext(), filter);
2544            for (ReplicaDescriptor r : s.getReplicas())
2545            {
2546              if (areDnsEqual(r.getSuffix().getDN(), dn))
2547              {
2548                replicationId = r.getReplicationId();
2549              }
2550            }
2551          }
2552          catch (NamingException ne)
2553          {
2554            LocalizableMessage msg;
2555            if (isCertificateException(ne))
2556            {
2557              msg = INFO_ERROR_READING_CONFIG_LDAP_CERTIFICATE_SERVER.get(getHostPort(server), ne.toString(true));
2558            }
2559            else
2560            {
2561              msg = INFO_CANNOT_CONNECT_TO_REMOTE_GENERIC.get(getHostPort(server), ne.toString(true));
2562            }
2563            throw new ApplicationException(ReturnCode.CONFIGURATION_ERROR, msg, ne);
2564          }
2565        }
2566        if (replicationId == -1)
2567        {
2568          throw new ApplicationException(ReturnCode.APPLICATION_ERROR, ERR_COULD_NOT_FIND_REPLICATIONID.get(dn), null);
2569        }
2570        StaticUtils.sleep(3000);
2571        int nTries = 5;
2572        boolean initDone = false;
2573        while (!initDone)
2574        {
2575          try
2576          {
2577            logger.info(LocalizableMessage.raw("Calling initializeSuffix with base DN: " + dn));
2578            logger.info(LocalizableMessage.raw("Try number: " + (6 - nTries)));
2579            logger.info(LocalizableMessage.raw("replicationId of source replica: " + replicationId));
2580            initializeSuffix(conn.getLdapContext(), replicationId, dn, !isADS && !isSchema, hostPort);
2581            initDone = true;
2582          }
2583          catch (PeerNotFoundException pnfe)
2584          {
2585            logger.info(LocalizableMessage.raw("Peer could not be found"));
2586            if (nTries == 1)
2587            {
2588              throw new ApplicationException(ReturnCode.APPLICATION_ERROR, pnfe.getMessageObject(), null);
2589            }
2590            StaticUtils.sleep((5 - nTries) * 3000);
2591          }
2592          nTries--;
2593        }
2594      }
2595      catch (ApplicationException ae)
2596      {
2597        StaticUtils.close(conn);
2598        throw ae;
2599      }
2600      if ((isADS || isSchema) && isVerbose())
2601      {
2602        notifyListeners(getFormattedDone());
2603        notifyListeners(getLineBreak());
2604      }
2605      checkAbort();
2606    }
2607  }
2608
2609  /**
2610   * This method updates the ADS contents (and creates the according suffixes).
2611   * If the user specified an existing topology, the new instance is registered
2612   * with that ADS (the ADS might need to be created), and the local ADS will be
2613   * populated when the local server is added to the remote server's ADS
2614   * replication domain in a subsequent step. Otherwise, an ADS is created on
2615   * the new instance and the server is registered with the new ADS. NOTE: this
2616   * method assumes that the local server and any remote server are running.
2617   *
2618   * @throws ApplicationException
2619   *           if something goes wrong.
2620   */
2621  private void updateADS() throws ApplicationException
2622  {
2623    DataReplicationOptions repl = getUserData().getReplicationOptions();
2624    boolean isRemoteServer = repl.getType() == DataReplicationOptions.Type.IN_EXISTING_TOPOLOGY;
2625    AuthenticationData auth = isRemoteServer ? repl.getAuthenticationData() : null;
2626    ConnectionWrapper remoteConn = null; // Bound to remote ADS host (if any).
2627    ConnectionWrapper localConn = null; // Bound to local server.
2628    ADSContext adsContext = null; // Bound to ADS host (via one of above).
2629
2630    /*
2631     * Outer try-catch-finally to convert occurrences of NamingException and
2632     * ADSContextException to ApplicationException and clean up JNDI contexts.
2633     */
2634    try
2635    {
2636      if (isRemoteServer)
2637      {
2638        remoteConn = createConnection(auth);
2639        adsContext = new ADSContext(remoteConn); // adsContext owns remoteCtx
2640
2641        /*
2642         * Check the remote server for ADS. If it does not exist, create the
2643         * initial ADS there and register the server with itself.
2644         */
2645        if (!adsContext.hasAdminData())
2646        {
2647          if (isVerbose())
2648          {
2649            notifyListeners(getFormattedWithPoints(INFO_PROGRESS_CREATING_ADS_ON_REMOTE.get(auth.getHostPort())));
2650          }
2651
2652          adsContext.createAdminData(null);
2653          TopologyCacheFilter filter = new TopologyCacheFilter();
2654          filter.setSearchMonitoringInformation(false);
2655          filter.setSearchBaseDNInformation(false);
2656          ServerDescriptor server = createStandalone(remoteConn.getLdapContext(), filter);
2657          server.updateAdsPropertiesWithServerProperties();
2658          adsContext.registerServer(server.getAdsProperties());
2659          createdRemoteAds = true;
2660          if (isVerbose())
2661          {
2662            notifyListeners(getFormattedDoneWithLineBreak());
2663          }
2664          checkAbort();
2665        }
2666      }
2667
2668      /* Act on local server depending on if using remote or local ADS */
2669      if (isVerbose())
2670      {
2671        notifyListeners(getFormattedWithPoints(INFO_PROGRESS_CREATING_ADS.get()));
2672      }
2673      localConn = createLocalConnection();
2674      if (!isRemoteServer)
2675      {
2676        /* Configure local server to have an ADS */
2677        adsContext = new ADSContext(localConn); // adsContext owns localCtx
2678        adsContext.createAdminData(null);
2679      }
2680      /* Register new server in ADS. */
2681      TopologyCacheFilter filter = new TopologyCacheFilter();
2682      filter.setSearchMonitoringInformation(false);
2683      filter.setSearchBaseDNInformation(false);
2684      ServerDescriptor server = createStandalone(localConn.getLdapContext(), filter);
2685      server.updateAdsPropertiesWithServerProperties();
2686      if (0 == adsContext.registerOrUpdateServer(server.getAdsProperties()))
2687      {
2688        if (isRemoteServer)
2689        {
2690          registeredNewServerOnRemote = true;
2691        }
2692      }
2693      else
2694      {
2695        logger.warn(LocalizableMessage.raw("Server was already registered. Updating " + "server registration."));
2696      }
2697      if (isRemoteServer)
2698      {
2699        seedAdsTrustStore(localConn.getLdapContext(), adsContext.getTrustedCertificates());
2700      }
2701      if (isVerbose())
2702      {
2703        notifyListeners(getFormattedDoneWithLineBreak());
2704      }
2705      checkAbort();
2706
2707      /* Add global administrator if the user specified one. */
2708      if (getUserData().mustCreateAdministrator())
2709      {
2710        try
2711        {
2712          if (isVerbose())
2713          {
2714            notifyListeners(getFormattedWithPoints(INFO_PROGRESS_CREATING_ADMINISTRATOR.get()));
2715          }
2716          adsContext.createAdministrator(getAdministratorProperties(getUserData()));
2717          if (isRemoteServer && !createdRemoteAds)
2718          {
2719            createdAdministrator = true;
2720          }
2721          if (isVerbose())
2722          {
2723            notifyListeners(getFormattedDoneWithLineBreak());
2724          }
2725          checkAbort();
2726        }
2727        catch (ADSContextException ade)
2728        {
2729          if (ade.getError() == ADSContextException.ErrorType.ALREADY_REGISTERED)
2730          {
2731            notifyListeners(getFormattedWarning(INFO_ADMINISTRATOR_ALREADY_REGISTERED.get()));
2732            adsContext.unregisterServer(server.getAdsProperties());
2733            adsContext.registerServer(server.getAdsProperties());
2734          }
2735          else
2736          {
2737            throw ade;
2738          }
2739        }
2740      }
2741    }
2742    catch (NamingException ne)
2743    {
2744      LocalizableMessage msg;
2745      if (isRemoteServer)
2746      {
2747        msg = getMessageForException(ne, auth.getHostPort().toString());
2748      }
2749      else
2750      {
2751        msg = Utils.getMessageForException(ne);
2752      }
2753      throw new ApplicationException(ReturnCode.CONFIGURATION_ERROR, msg, ne);
2754    }
2755    catch (ADSContextException ace)
2756    {
2757      throw new ApplicationException(ReturnCode.CONFIGURATION_ERROR, (isRemoteServer ? INFO_REMOTE_ADS_EXCEPTION.get(
2758          auth.getHostPort(), ace.getMessageObject()) : INFO_ADS_EXCEPTION.get(ace)), ace);
2759    }
2760    finally
2761    {
2762      StaticUtils.close(remoteConn, localConn);
2763    }
2764  }
2765
2766  private ConnectionWrapper createConnection(AuthenticationData auth) throws NamingException
2767  {
2768    String ldapUrl = auth.getLdapUrl();
2769    String dn = auth.getDn();
2770    String pwd = auth.getPwd();
2771
2772    if (auth.useSecureConnection())
2773    {
2774      ApplicationTrustManager trustManager = getTrustManager();
2775      trustManager.setHost(auth.getHostPort().getHost());
2776      return new ConnectionWrapper(ldapUrl, LDAPS, dn, pwd, getConnectTimeout(), getTrustManager());
2777    }
2778    else
2779    {
2780      return new ConnectionWrapper(ldapUrl, LDAP, dn, pwd, getConnectTimeout(), getTrustManager());
2781    }
2782  }
2783
2784  /**
2785   * Tells whether we must create a suffix that we are not going to replicate
2786   * with other servers or not.
2787   *
2788   * @return {@code true} if we must create a new suffix and {@code false} otherwise.
2789   */
2790  private boolean createNotReplicatedSuffix()
2791  {
2792    DataReplicationOptions repl = getUserData().getReplicationOptions();
2793
2794    SuffixesToReplicateOptions suf = getUserData().getSuffixesToReplicateOptions();
2795
2796    return repl.getType() == DataReplicationOptions.Type.FIRST_IN_TOPOLOGY
2797        || repl.getType() == DataReplicationOptions.Type.STANDALONE
2798        || suf.getType() == SuffixesToReplicateOptions.Type.NEW_SUFFIX_IN_TOPOLOGY;
2799  }
2800
2801  /**
2802   * Returns whether we must configure replication.
2803   *
2804   * @return {@code true} if we must configure replication and {@code false} otherwise.
2805   */
2806  private boolean mustConfigureReplication()
2807  {
2808    return getUserData().getReplicationOptions().getType() != DataReplicationOptions.Type.STANDALONE;
2809  }
2810
2811  /**
2812   * Returns whether we must create the ADS.
2813   *
2814   * @return {@code true} if we must create the ADS and {@code false} otherwise.
2815   */
2816  private boolean mustCreateAds()
2817  {
2818    return getUserData().getReplicationOptions().getType() != DataReplicationOptions.Type.STANDALONE;
2819  }
2820
2821  /**
2822   * Returns whether we must start the server.
2823   *
2824   * @return {@code true} if we must start the server and {@code false} otherwise.
2825   */
2826  private boolean mustStart()
2827  {
2828    return getUserData().getStartServer() || mustCreateAds();
2829  }
2830
2831  /**
2832   * Returns whether the start server must be launched in verbose mode.
2833   * <p>
2834   * The verbose flag is not enough because in the case where many entries have been imported,
2835   * the startup phase can take long.
2836   *
2837   * @return {@code true} if the start server must be launched in verbose mode and {@code false} otherwise.
2838   */
2839  private boolean isStartVerbose()
2840  {
2841    if (isVerbose())
2842    {
2843      return true;
2844    }
2845    boolean manyEntriesToImport = false;
2846    NewSuffixOptions.Type type = getUserData().getNewSuffixOptions().getType();
2847    if (type == NewSuffixOptions.Type.IMPORT_FROM_LDIF_FILE)
2848    {
2849      long mbTotalSize = 0;
2850      LinkedList<String> ldifPaths = getUserData().getNewSuffixOptions().getLDIFPaths();
2851      for (String ldifPath : ldifPaths)
2852      {
2853        File f = new File(ldifPath);
2854        mbTotalSize += f.length();
2855      }
2856      // Assume entries of 1kb
2857      if (mbTotalSize > THRESHOLD_VERBOSE_START * 1024)
2858      {
2859        manyEntriesToImport = true;
2860      }
2861    }
2862    else if (type == NewSuffixOptions.Type.IMPORT_AUTOMATICALLY_GENERATED_DATA)
2863    {
2864      int nEntries = getUserData().getNewSuffixOptions().getNumberEntries();
2865      if (nEntries > THRESHOLD_VERBOSE_START)
2866      {
2867        manyEntriesToImport = true;
2868      }
2869    }
2870    return manyEntriesToImport;
2871  }
2872
2873  /**
2874   * Returns whether we must stop the server.
2875   * <p>
2876   * The server might be stopped if the user asked not to start it at the end
2877   * of the installation and it was started temporarily to update its configuration.
2878   *
2879   * @return {@code true} if we must stop the server and {@code false} otherwise.
2880   */
2881  private boolean mustStop()
2882  {
2883    return !getUserData().getStartServer() && mustCreateAds();
2884  }
2885
2886  /**
2887   * Returns whether we must initialize suffixes.
2888   *
2889   * @return {@code true} if we must initialize suffixes and {@code false} otherwise.
2890   */
2891  private boolean mustInitializeSuffixes()
2892  {
2893    return getUserData().getReplicationOptions().getType() == DataReplicationOptions.Type.IN_EXISTING_TOPOLOGY;
2894  }
2895
2896  /**
2897   * Returns the list of preferred URLs to connect to remote servers. In fact it
2898   * returns only the URL to the remote server specified by the user in the
2899   * replication options panel. The method returns a list for convenience with
2900   * other interfaces.
2901   * <p>
2902   * NOTE: this method assumes that the UserData object has
2903   * already been updated with the host and port of the remote server.
2904   *
2905   * @return the list of preferred URLs to connect to remote servers.
2906   */
2907  private Set<PreferredConnection> getPreferredConnections()
2908  {
2909    Set<PreferredConnection> cnx = new LinkedHashSet<>();
2910    DataReplicationOptions repl = getUserData().getReplicationOptions();
2911    if (repl.getType() == DataReplicationOptions.Type.IN_EXISTING_TOPOLOGY)
2912    {
2913      AuthenticationData auth = repl.getAuthenticationData();
2914      if (auth != null)
2915      {
2916        PreferredConnection.Type type;
2917        if (auth.useSecureConnection())
2918        {
2919          type = PreferredConnection.Type.LDAPS;
2920        }
2921        else
2922        {
2923          type = PreferredConnection.Type.LDAP;
2924        }
2925        cnx.add(new PreferredConnection(auth.getLdapUrl(), type));
2926      }
2927    }
2928    return cnx;
2929  }
2930
2931  private Map<ADSContext.ServerProperty, Object> getNewServerAdsProperties(UserData userData)
2932  {
2933    Map<ADSContext.ServerProperty, Object> serverProperties = new HashMap<>();
2934    serverProperties.put(ADSContext.ServerProperty.HOST_NAME, userData.getHostName());
2935    serverProperties.put(ADSContext.ServerProperty.LDAP_PORT, String.valueOf(userData.getServerPort()));
2936    serverProperties.put(ADSContext.ServerProperty.LDAP_ENABLED, "true");
2937
2938    // TODO: even if the user does not configure SSL maybe we should choose
2939    // a secure port that is not being used and that we can actually use.
2940    SecurityOptions sec = userData.getSecurityOptions();
2941    if (sec.getEnableSSL())
2942    {
2943      serverProperties.put(ADSContext.ServerProperty.LDAPS_PORT, String.valueOf(sec.getSslPort()));
2944      serverProperties.put(ADSContext.ServerProperty.LDAPS_ENABLED, "true");
2945    }
2946    else
2947    {
2948      serverProperties.put(ADSContext.ServerProperty.LDAPS_PORT, "636");
2949      serverProperties.put(ADSContext.ServerProperty.LDAPS_ENABLED, "false");
2950    }
2951
2952    if (sec.getEnableStartTLS())
2953    {
2954      serverProperties.put(ADSContext.ServerProperty.STARTTLS_ENABLED, "true");
2955    }
2956    else
2957    {
2958      serverProperties.put(ADSContext.ServerProperty.STARTTLS_ENABLED, "false");
2959    }
2960
2961    serverProperties.put(ADSContext.ServerProperty.JMX_PORT, "1689");
2962    serverProperties.put(ADSContext.ServerProperty.JMX_ENABLED, "false");
2963
2964    serverProperties.put(ADSContext.ServerProperty.INSTANCE_PATH, getInstallPathFromClasspath());
2965
2966    String serverID = serverProperties.get(ADSContext.ServerProperty.HOST_NAME) + ":" + userData.getServerPort();
2967
2968    /* TODO: do we want to ask this specifically to the user? */
2969    serverProperties.put(ADSContext.ServerProperty.ID, serverID);
2970    serverProperties.put(ADSContext.ServerProperty.HOST_OS, OperatingSystem.getOperatingSystem().toString());
2971
2972    return serverProperties;
2973  }
2974
2975  private Map<ADSContext.AdministratorProperty, Object> getAdministratorProperties(UserData userData)
2976  {
2977    Map<ADSContext.AdministratorProperty, Object> adminProperties = new HashMap<>();
2978    adminProperties.put(ADSContext.AdministratorProperty.UID, userData.getGlobalAdministratorUID());
2979    adminProperties.put(ADSContext.AdministratorProperty.PASSWORD, userData.getGlobalAdministratorPassword());
2980    adminProperties.put(ADSContext.AdministratorProperty.DESCRIPTION,
2981                        INFO_GLOBAL_ADMINISTRATOR_DESCRIPTION.get().toString());
2982    return adminProperties;
2983  }
2984
2985  /**
2986   * Validate the data provided by the user in the server settings panel and
2987   * update the userData object according to that content.
2988   *
2989   * @throws UserDataException
2990   *           if the data provided by the user is not valid.
2991   */
2992  private void updateUserDataForServerSettingsPanel(QuickSetup qs) throws UserDataException
2993  {
2994    List<LocalizableMessage> errorMsgs = new ArrayList<>();
2995
2996    // Check the host is not empty.
2997    // TODO: check that the host name is valid...
2998    String hostName = qs.getFieldStringValue(FieldName.HOST_NAME);
2999    if (hostName == null || hostName.trim().length() == 0)
3000    {
3001      errorMsgs.add(INFO_EMPTY_HOST_NAME.get());
3002      qs.displayFieldInvalid(FieldName.HOST_NAME, true);
3003    }
3004    else
3005    {
3006      qs.displayFieldInvalid(FieldName.HOST_NAME, false);
3007      getUserData().setHostName(hostName);
3008    }
3009
3010    // Check the port
3011    String sPort = qs.getFieldStringValue(FieldName.SERVER_PORT);
3012    int port = -1;
3013    try
3014    {
3015      port = Integer.parseInt(sPort);
3016      if (port < MIN_PORT_VALUE || port > MAX_PORT_VALUE)
3017      {
3018        errorMsgs.add(INFO_INVALID_PORT_VALUE_RANGE.get(MIN_PORT_VALUE, MAX_PORT_VALUE));
3019        qs.displayFieldInvalid(FieldName.SERVER_PORT, true);
3020      }
3021      else if (!canUseAsPort(port))
3022      {
3023        errorMsgs.add(getCannotBindErrorMessage(port));
3024        qs.displayFieldInvalid(FieldName.SERVER_PORT, true);
3025      }
3026      else
3027      {
3028        getUserData().setServerPort(port);
3029        qs.displayFieldInvalid(FieldName.SERVER_PORT, false);
3030      }
3031    }
3032    catch (NumberFormatException nfe)
3033    {
3034      errorMsgs.add(INFO_INVALID_PORT_VALUE_RANGE.get(MIN_PORT_VALUE, MAX_PORT_VALUE));
3035      qs.displayFieldInvalid(FieldName.SERVER_PORT, true);
3036    }
3037
3038    //  Check the admin connector port
3039    sPort = qs.getFieldStringValue(FieldName.ADMIN_CONNECTOR_PORT);
3040    int adminConnectorPort = -1;
3041    try
3042    {
3043      adminConnectorPort = Integer.parseInt(sPort);
3044      if (adminConnectorPort < MIN_PORT_VALUE || adminConnectorPort > MAX_PORT_VALUE)
3045      {
3046        errorMsgs.add(INFO_INVALID_PORT_VALUE_RANGE.get(MIN_PORT_VALUE, MAX_PORT_VALUE));
3047        qs.displayFieldInvalid(FieldName.ADMIN_CONNECTOR_PORT, true);
3048      }
3049      else if (!canUseAsPort(adminConnectorPort))
3050      {
3051        errorMsgs.add(getCannotBindErrorMessage(adminConnectorPort));
3052        qs.displayFieldInvalid(FieldName.ADMIN_CONNECTOR_PORT, true);
3053      }
3054      else if (adminConnectorPort == port)
3055      {
3056        errorMsgs.add(INFO_ADMIN_CONNECTOR_VALUE_SEVERAL_TIMES.get());
3057        qs.displayFieldInvalid(FieldName.SERVER_PORT, true);
3058        qs.displayFieldInvalid(FieldName.ADMIN_CONNECTOR_PORT, true);
3059      }
3060      else
3061      {
3062        getUserData().setAdminConnectorPort(adminConnectorPort);
3063        qs.displayFieldInvalid(FieldName.ADMIN_CONNECTOR_PORT, false);
3064      }
3065    }
3066    catch (NumberFormatException nfe)
3067    {
3068      errorMsgs.add(INFO_INVALID_PORT_VALUE_RANGE.get(MIN_PORT_VALUE, MAX_PORT_VALUE));
3069      qs.displayFieldInvalid(FieldName.ADMIN_CONNECTOR_PORT, true);
3070    }
3071
3072    // Check the secure port
3073    SecurityOptions sec = (SecurityOptions) qs.getFieldValue(FieldName.SECURITY_OPTIONS);
3074    int securePort = sec.getSslPort();
3075    if (sec.getEnableSSL())
3076    {
3077      if (securePort < MIN_PORT_VALUE || securePort > MAX_PORT_VALUE)
3078      {
3079        errorMsgs.add(INFO_INVALID_SECURE_PORT_VALUE_RANGE.get(MIN_PORT_VALUE, MAX_PORT_VALUE));
3080        qs.displayFieldInvalid(FieldName.SECURITY_OPTIONS, true);
3081      }
3082      else if (!canUseAsPort(securePort))
3083      {
3084        errorMsgs.add(getCannotBindErrorMessage(securePort));
3085        qs.displayFieldInvalid(FieldName.SECURITY_OPTIONS, true);
3086      }
3087      else if (port == securePort)
3088      {
3089        errorMsgs.add(INFO_EQUAL_PORTS.get());
3090        qs.displayFieldInvalid(FieldName.SECURITY_OPTIONS, true);
3091        qs.displayFieldInvalid(FieldName.SERVER_PORT, true);
3092      }
3093      else if (adminConnectorPort == securePort)
3094      {
3095        errorMsgs.add(INFO_ADMIN_CONNECTOR_VALUE_SEVERAL_TIMES.get());
3096        qs.displayFieldInvalid(FieldName.SECURITY_OPTIONS, true);
3097        qs.displayFieldInvalid(FieldName.ADMIN_CONNECTOR_PORT, true);
3098      }
3099      else
3100      {
3101        getUserData().setSecurityOptions(sec);
3102        qs.displayFieldInvalid(FieldName.SECURITY_OPTIONS, false);
3103      }
3104    }
3105    else
3106    {
3107      getUserData().setSecurityOptions(sec);
3108      qs.displayFieldInvalid(FieldName.SECURITY_OPTIONS, false);
3109    }
3110
3111    // Check the Directory Manager DN
3112    String dmDn = qs.getFieldStringValue(FieldName.DIRECTORY_MANAGER_DN);
3113
3114    if (dmDn == null || dmDn.trim().length() == 0)
3115    {
3116      errorMsgs.add(INFO_EMPTY_DIRECTORY_MANAGER_DN.get());
3117      qs.displayFieldInvalid(FieldName.DIRECTORY_MANAGER_DN, true);
3118    }
3119    else if (!isDN(dmDn))
3120    {
3121      errorMsgs.add(INFO_NOT_A_DIRECTORY_MANAGER_DN.get());
3122      qs.displayFieldInvalid(FieldName.DIRECTORY_MANAGER_DN, true);
3123    }
3124    else if (isConfigurationDn(dmDn))
3125    {
3126      errorMsgs.add(INFO_DIRECTORY_MANAGER_DN_IS_CONFIG_DN.get());
3127      qs.displayFieldInvalid(FieldName.DIRECTORY_MANAGER_DN, true);
3128    }
3129    else
3130    {
3131      getUserData().setDirectoryManagerDn(dmDn);
3132      qs.displayFieldInvalid(FieldName.DIRECTORY_MANAGER_DN, false);
3133    }
3134
3135    // Check the provided passwords
3136    String pwd1 = qs.getFieldStringValue(FieldName.DIRECTORY_MANAGER_PWD);
3137    String pwd2 = qs.getFieldStringValue(FieldName.DIRECTORY_MANAGER_PWD_CONFIRM);
3138    if (pwd1 == null)
3139    {
3140      pwd1 = "";
3141    }
3142
3143    boolean pwdValid = true;
3144    if (!pwd1.equals(pwd2))
3145    {
3146      errorMsgs.add(INFO_NOT_EQUAL_PWD.get());
3147      qs.displayFieldInvalid(FieldName.DIRECTORY_MANAGER_PWD_CONFIRM, true);
3148      pwdValid = false;
3149    }
3150    if (pwd1.length() < MIN_DIRECTORY_MANAGER_PWD)
3151    {
3152      errorMsgs.add(INFO_PWD_TOO_SHORT.get(MIN_DIRECTORY_MANAGER_PWD));
3153      qs.displayFieldInvalid(FieldName.DIRECTORY_MANAGER_PWD, true);
3154      if (pwd2 == null || pwd2.length() < MIN_DIRECTORY_MANAGER_PWD)
3155      {
3156        qs.displayFieldInvalid(FieldName.DIRECTORY_MANAGER_PWD_CONFIRM, true);
3157      }
3158      pwdValid = false;
3159    }
3160
3161    if (pwdValid)
3162    {
3163      getUserData().setDirectoryManagerPwd(pwd1);
3164      qs.displayFieldInvalid(FieldName.DIRECTORY_MANAGER_PWD, false);
3165      qs.displayFieldInvalid(FieldName.DIRECTORY_MANAGER_PWD_CONFIRM, false);
3166    }
3167
3168    // For the moment do not enable JMX
3169    int defaultJMXPort = UserData.getDefaultJMXPort(new int[] { port, securePort });
3170    if (defaultJMXPort != -1)
3171    {
3172      //getUserData().setServerJMXPort(defaultJMXPort);
3173      getUserData().setServerJMXPort(-1);
3174    }
3175
3176    if (!errorMsgs.isEmpty())
3177    {
3178      throw new UserDataException(Step.SERVER_SETTINGS, getMessageFromCollection(errorMsgs, "\n"));
3179    }
3180  }
3181
3182  private LocalizableMessage getCannotBindErrorMessage(int port)
3183  {
3184    if (isPrivilegedPort(port))
3185    {
3186      return INFO_CANNOT_BIND_PRIVILEDGED_PORT.get(port);
3187    }
3188    return INFO_CANNOT_BIND_PORT.get(port);
3189  }
3190
3191  /**
3192   * Validate the data provided by the user in the data options panel and update
3193   * the userData object according to that content.
3194   *
3195   * @throws UserDataException
3196   *           if the data provided by the user is not valid.
3197   */
3198  private void updateUserDataForReplicationOptionsPanel(QuickSetup qs) throws UserDataException
3199  {
3200    boolean hasGlobalAdministrators = false;
3201    int replicationPort = -1;
3202    boolean secureReplication = false;
3203    Integer port = null;
3204    List<LocalizableMessage> errorMsgs = new ArrayList<>();
3205
3206    DataReplicationOptions.Type type = (DataReplicationOptions.Type) qs.getFieldValue(FieldName.REPLICATION_OPTIONS);
3207    String host = qs.getFieldStringValue(FieldName.REMOTE_SERVER_HOST);
3208    String dn = qs.getFieldStringValue(FieldName.REMOTE_SERVER_DN);
3209    String pwd = qs.getFieldStringValue(FieldName.REMOTE_SERVER_PWD);
3210
3211    if (type != DataReplicationOptions.Type.STANDALONE)
3212    {
3213      // Check replication port
3214      replicationPort = checkReplicationPort(qs, errorMsgs);
3215      secureReplication = (Boolean) qs.getFieldValue(FieldName.REPLICATION_SECURE);
3216    }
3217
3218    UserDataConfirmationException confirmEx = null;
3219    switch (type)
3220    {
3221    case IN_EXISTING_TOPOLOGY:
3222    {
3223      String sPort = qs.getFieldStringValue(FieldName.REMOTE_SERVER_PORT);
3224      checkRemoteHostPortDnAndPwd(host, sPort, dn, pwd, qs, errorMsgs);
3225
3226      if (errorMsgs.isEmpty())
3227      {
3228        port = Integer.parseInt(sPort);
3229        // Try to connect
3230        boolean[] globalAdmin = { hasGlobalAdministrators };
3231        String[] effectiveDn = { dn };
3232        try
3233        {
3234          updateUserDataWithADS(host, port, dn, pwd, qs, errorMsgs, globalAdmin, effectiveDn);
3235        }
3236        catch (UserDataConfirmationException e)
3237        {
3238          confirmEx = e;
3239        }
3240        hasGlobalAdministrators = globalAdmin[0];
3241        dn = effectiveDn[0];
3242      }
3243      break;
3244    }
3245    case STANDALONE:
3246    {
3247      getUserData().setSuffixesToReplicateOptions(
3248          new SuffixesToReplicateOptions(SuffixesToReplicateOptions.Type.NO_SUFFIX_TO_REPLICATE,
3249              new HashSet<SuffixDescriptor>(), new HashSet<SuffixDescriptor>()));
3250      break;
3251    }
3252    case FIRST_IN_TOPOLOGY:
3253    {
3254      getUserData().setSuffixesToReplicateOptions(
3255          new SuffixesToReplicateOptions(SuffixesToReplicateOptions.Type.NEW_SUFFIX_IN_TOPOLOGY,
3256              new HashSet<SuffixDescriptor>(), new HashSet<SuffixDescriptor>()));
3257      break;
3258    }
3259    default:
3260      throw new IllegalStateException("Do not know what to do with type: " + type);
3261    }
3262
3263    if (errorMsgs.isEmpty())
3264    {
3265      AuthenticationData auth = new AuthenticationData();
3266      auth.setHostPort(new HostPort("".equals(host) ? null : host, port != null ? port : 0));
3267      auth.setDn(dn);
3268      auth.setPwd(pwd);
3269      auth.setUseSecureConnection(true);
3270
3271      getUserData().setReplicationOptions(createDataReplicationOptions(replicationPort, secureReplication, type, auth));
3272      getUserData().createAdministrator(
3273          !hasGlobalAdministrators && type == DataReplicationOptions.Type.IN_EXISTING_TOPOLOGY);
3274    }
3275    if (!errorMsgs.isEmpty())
3276    {
3277      throw new UserDataException(Step.REPLICATION_OPTIONS, getMessageFromCollection(errorMsgs, "\n"));
3278    }
3279    if (confirmEx != null)
3280    {
3281      throw confirmEx;
3282    }
3283  }
3284
3285  private DataReplicationOptions createDataReplicationOptions(int replicationPort, boolean secureReplication,
3286      DataReplicationOptions.Type type, AuthenticationData auth)
3287  {
3288    switch (type)
3289    {
3290    case IN_EXISTING_TOPOLOGY:
3291      return DataReplicationOptions.createInExistingTopology(auth, replicationPort, secureReplication);
3292    case STANDALONE:
3293      return DataReplicationOptions.createStandalone();
3294    case FIRST_IN_TOPOLOGY:
3295      return DataReplicationOptions.createFirstInTopology(replicationPort, secureReplication);
3296    default:
3297      throw new IllegalStateException("Do not know what to do with type: " + type);
3298    }
3299  }
3300
3301  private int checkReplicationPort(QuickSetup qs, List<LocalizableMessage> errorMsgs)
3302  {
3303    int replicationPort = -1;
3304    String sPort = qs.getFieldStringValue(FieldName.REPLICATION_PORT);
3305    try
3306    {
3307      replicationPort = Integer.parseInt(sPort);
3308      if (replicationPort < MIN_PORT_VALUE || replicationPort > MAX_PORT_VALUE)
3309      {
3310        errorMsgs.add(INFO_INVALID_REPLICATION_PORT_VALUE_RANGE.get(MIN_PORT_VALUE, MAX_PORT_VALUE));
3311        qs.displayFieldInvalid(FieldName.SERVER_PORT, true);
3312      }
3313      else if (!canUseAsPort(replicationPort))
3314      {
3315        errorMsgs.add(getCannotBindErrorMessage(replicationPort));
3316        qs.displayFieldInvalid(FieldName.REPLICATION_PORT, true);
3317      }
3318      else
3319      {
3320        /* Check that we did not chose this port for another protocol */
3321        SecurityOptions sec = getUserData().getSecurityOptions();
3322        if (replicationPort == getUserData().getServerPort() || replicationPort == getUserData().getServerJMXPort()
3323            || (replicationPort == sec.getSslPort() && sec.getEnableSSL()))
3324        {
3325          errorMsgs.add(INFO_REPLICATION_PORT_ALREADY_CHOSEN_FOR_OTHER_PROTOCOL.get());
3326          qs.displayFieldInvalid(FieldName.REPLICATION_PORT, true);
3327        }
3328        else
3329        {
3330          qs.displayFieldInvalid(FieldName.REPLICATION_PORT, false);
3331        }
3332      }
3333    }
3334    catch (NumberFormatException nfe)
3335    {
3336      errorMsgs.add(INFO_INVALID_REPLICATION_PORT_VALUE_RANGE.get(MIN_PORT_VALUE, MAX_PORT_VALUE));
3337      qs.displayFieldInvalid(FieldName.REPLICATION_PORT, true);
3338    }
3339    return replicationPort;
3340  }
3341
3342  private void checkRemoteHostPortDnAndPwd(String host, String sPort, String dn, String pwd, QuickSetup qs,
3343      List<LocalizableMessage> errorMsgs)
3344  {
3345    // Check host
3346    if (host == null || host.length() == 0)
3347    {
3348      errorMsgs.add(INFO_EMPTY_REMOTE_HOST.get());
3349      qs.displayFieldInvalid(FieldName.REMOTE_SERVER_HOST, true);
3350    }
3351    else
3352    {
3353      qs.displayFieldInvalid(FieldName.REMOTE_SERVER_HOST, false);
3354    }
3355
3356    // Check port
3357    try
3358    {
3359      Integer.parseInt(sPort);
3360      qs.displayFieldInvalid(FieldName.REMOTE_SERVER_PORT, false);
3361    }
3362    catch (Throwable t)
3363    {
3364      errorMsgs.add(INFO_INVALID_REMOTE_PORT.get());
3365      qs.displayFieldInvalid(FieldName.REMOTE_SERVER_PORT, true);
3366    }
3367
3368    // Check dn
3369    if (dn == null || dn.length() == 0)
3370    {
3371      errorMsgs.add(INFO_EMPTY_REMOTE_DN.get());
3372      qs.displayFieldInvalid(FieldName.REMOTE_SERVER_DN, true);
3373    }
3374    else
3375    {
3376      qs.displayFieldInvalid(FieldName.REMOTE_SERVER_DN, false);
3377    }
3378
3379    // Check password
3380    if (pwd == null || pwd.length() == 0)
3381    {
3382      errorMsgs.add(INFO_EMPTY_REMOTE_PWD.get());
3383      qs.displayFieldInvalid(FieldName.REMOTE_SERVER_PWD, true);
3384    }
3385    else
3386    {
3387      qs.displayFieldInvalid(FieldName.REMOTE_SERVER_PWD, false);
3388    }
3389  }
3390
3391  private void updateUserDataWithADS(String host, int port, String dn, String pwd, QuickSetup qs,
3392      List<LocalizableMessage> errorMsgs, boolean[] hasGlobalAdministrators, String[] effectiveDn)
3393      throws UserDataException
3394  {
3395    host = getHostNameForLdapUrl(host);
3396    HostPort hostPort = new HostPort(host, port);
3397
3398    ApplicationTrustManager trustManager = getTrustManager();
3399    trustManager.setHost(host);
3400    trustManager.resetLastRefusedItems();
3401    try (ConnectionWrapper conn = newConnectionWrapper(dn, pwd, effectiveDn, hostPort, trustManager))
3402    {
3403      ADSContext adsContext = new ADSContext(conn);
3404      if (adsContext.hasAdminData())
3405      {
3406        /* Check if there are already global administrators */
3407        Set<?> administrators = adsContext.readAdministratorRegistry();
3408        hasGlobalAdministrators[0] = !administrators.isEmpty();
3409        Set<TopologyCacheException> exceptions = updateUserDataWithSuffixesInADS(adsContext, trustManager);
3410        Set<LocalizableMessage> exceptionMsgs = new LinkedHashSet<>();
3411        /* Check the exceptions and see if we throw them or not. */
3412        for (TopologyCacheException e : exceptions)
3413        {
3414          switch (e.getType())
3415          {
3416          case NOT_GLOBAL_ADMINISTRATOR:
3417            LocalizableMessage errorMsg = INFO_NOT_GLOBAL_ADMINISTRATOR_PROVIDED.get();
3418            throw new UserDataException(Step.REPLICATION_OPTIONS, errorMsg);
3419          case GENERIC_CREATING_CONNECTION:
3420            if (isCertificateException(e.getCause()))
3421            {
3422              UserDataCertificateException.Type excType;
3423              ApplicationTrustManager.Cause cause = null;
3424              if (e.getTrustManager() != null)
3425              {
3426                cause = e.getTrustManager().getLastRefusedCause();
3427              }
3428              logger.info(LocalizableMessage.raw("Certificate exception cause: " + cause));
3429              if (cause == ApplicationTrustManager.Cause.NOT_TRUSTED)
3430              {
3431                excType = UserDataCertificateException.Type.NOT_TRUSTED;
3432              }
3433              else if (cause == ApplicationTrustManager.Cause.HOST_NAME_MISMATCH)
3434              {
3435                excType = UserDataCertificateException.Type.HOST_NAME_MISMATCH;
3436              }
3437              else
3438              {
3439                excType = null;
3440              }
3441              if (excType != null)
3442              {
3443                String h;
3444                int p;
3445                try
3446                {
3447                  URI uri = new URI(e.getLdapUrl());
3448                  h = uri.getHost();
3449                  p = uri.getPort();
3450                }
3451                catch (Throwable t)
3452                {
3453                  logger.warn(LocalizableMessage.raw("Error parsing ldap url of TopologyCacheException.", t));
3454                  h = INFO_NOT_AVAILABLE_LABEL.get().toString();
3455                  p = -1;
3456                }
3457                throw new UserDataCertificateException(Step.REPLICATION_OPTIONS, INFO_CERTIFICATE_EXCEPTION.get(h, p),
3458                    e.getCause(), h, p, e.getTrustManager().getLastRefusedChain(), e.getTrustManager()
3459                        .getLastRefusedAuthType(), excType);
3460              }
3461            }
3462            break;
3463          default:
3464            break;
3465          }
3466          exceptionMsgs.add(getMessage(e));
3467        }
3468        if (!exceptionMsgs.isEmpty())
3469        {
3470          LocalizableMessage confirmationMsg =
3471              INFO_ERROR_READING_REGISTERED_SERVERS_CONFIRM.get(getMessageFromCollection(exceptionMsgs, "\n"));
3472          throw new UserDataConfirmationException(Step.REPLICATION_OPTIONS, confirmationMsg);
3473        }
3474      }
3475      else
3476      {
3477        updateUserDataWithSuffixesInServer(conn.getLdapContext());
3478      }
3479    }
3480    catch (UserDataException ude)
3481    {
3482      throw ude;
3483    }
3484    catch (Throwable t)
3485    {
3486      logger.info(LocalizableMessage.raw("Error connecting to remote server.", t));
3487      if (isCertificateException(t))
3488      {
3489        UserDataCertificateException.Type excType;
3490        ApplicationTrustManager.Cause cause = trustManager.getLastRefusedCause();
3491        logger.info(LocalizableMessage.raw("Certificate exception cause: " + cause));
3492        if (cause == ApplicationTrustManager.Cause.NOT_TRUSTED)
3493        {
3494          excType = UserDataCertificateException.Type.NOT_TRUSTED;
3495        }
3496        else if (cause == ApplicationTrustManager.Cause.HOST_NAME_MISMATCH)
3497        {
3498          excType = UserDataCertificateException.Type.HOST_NAME_MISMATCH;
3499        }
3500        else
3501        {
3502          excType = null;
3503        }
3504
3505        if (excType != null)
3506        {
3507          throw new UserDataCertificateException(Step.REPLICATION_OPTIONS, INFO_CERTIFICATE_EXCEPTION.get(host, port),
3508              t, host, port, trustManager.getLastRefusedChain(), trustManager.getLastRefusedAuthType(), excType);
3509        }
3510        qs.displayFieldInvalid(FieldName.REMOTE_SERVER_HOST, true);
3511        qs.displayFieldInvalid(FieldName.REMOTE_SERVER_PORT, true);
3512        qs.displayFieldInvalid(FieldName.REMOTE_SERVER_DN, true);
3513        qs.displayFieldInvalid(FieldName.REMOTE_SERVER_PWD, true);
3514        errorMsgs.add(INFO_CANNOT_CONNECT_TO_REMOTE_GENERIC.get(host + ":" + port, t));
3515      }
3516      else if (t instanceof NamingException)
3517      {
3518        errorMsgs.add(getMessageForException((NamingException) t, host + ":" + port));
3519        qs.displayFieldInvalid(FieldName.REMOTE_SERVER_DN, true);
3520        qs.displayFieldInvalid(FieldName.REMOTE_SERVER_PWD, true);
3521        if (!(t instanceof NamingSecurityException))
3522        {
3523          qs.displayFieldInvalid(FieldName.REMOTE_SERVER_HOST, true);
3524          qs.displayFieldInvalid(FieldName.REMOTE_SERVER_PORT, true);
3525        }
3526      }
3527      else if (t instanceof ADSContextException)
3528      {
3529        errorMsgs.add(INFO_REMOTE_ADS_EXCEPTION.get(host + ":" + port, t));
3530      }
3531      else
3532      {
3533        throw new UserDataException(Step.REPLICATION_OPTIONS, getThrowableMsg(INFO_BUG_MSG.get(), t));
3534      }
3535    }
3536  }
3537
3538  private ConnectionWrapper newConnectionWrapper(String dn, String pwd, String[] effectiveDn, HostPort hostPort,
3539      ApplicationTrustManager trustManager) throws Throwable
3540  {
3541    try
3542    {
3543      effectiveDn[0] = dn;
3544      return new ConnectionWrapper(hostPort, LDAPS, dn, pwd, getConnectTimeout(), trustManager);
3545    }
3546    catch (Throwable t)
3547    {
3548      if (isCertificateException(t))
3549      {
3550        throw t;
3551      }
3552      // Try using a global administrator
3553      dn = ADSContext.getAdministratorDN(dn);
3554      effectiveDn[0] = dn;
3555      return new ConnectionWrapper(hostPort, LDAPS, dn, pwd, getConnectTimeout(), trustManager);
3556    }
3557  }
3558
3559  /**
3560   * Validate the data provided by the user in the create global administrator
3561   * panel and update the UserInstallData object according to that content.
3562   *
3563   * @throws UserDataException
3564   *           if the data provided by the user is not valid.
3565   */
3566  private void updateUserDataForCreateAdministratorPanel(QuickSetup qs) throws UserDataException
3567  {
3568    List<LocalizableMessage> errorMsgs = new ArrayList<>();
3569
3570    // Check the Global Administrator UID
3571    String uid = qs.getFieldStringValue(FieldName.GLOBAL_ADMINISTRATOR_UID);
3572
3573    if (uid == null || uid.trim().length() == 0)
3574    {
3575      errorMsgs.add(INFO_EMPTY_ADMINISTRATOR_UID.get());
3576      qs.displayFieldInvalid(FieldName.GLOBAL_ADMINISTRATOR_UID, true);
3577    }
3578    else
3579    {
3580      getUserData().setGlobalAdministratorUID(uid);
3581      qs.displayFieldInvalid(FieldName.GLOBAL_ADMINISTRATOR_UID, false);
3582    }
3583
3584    // Check the provided passwords
3585    String pwd1 = qs.getFieldStringValue(FieldName.GLOBAL_ADMINISTRATOR_PWD);
3586    String pwd2 = qs.getFieldStringValue(FieldName.GLOBAL_ADMINISTRATOR_PWD_CONFIRM);
3587    if (pwd1 == null)
3588    {
3589      pwd1 = "";
3590    }
3591
3592    boolean pwdValid = true;
3593    if (!pwd1.equals(pwd2))
3594    {
3595      errorMsgs.add(INFO_NOT_EQUAL_PWD.get());
3596      qs.displayFieldInvalid(FieldName.GLOBAL_ADMINISTRATOR_PWD_CONFIRM, true);
3597      pwdValid = false;
3598    }
3599    if (pwd1.length() < MIN_DIRECTORY_MANAGER_PWD)
3600    {
3601      errorMsgs.add(INFO_PWD_TOO_SHORT.get(MIN_DIRECTORY_MANAGER_PWD));
3602      qs.displayFieldInvalid(FieldName.GLOBAL_ADMINISTRATOR_PWD, true);
3603      if (pwd2 == null || pwd2.length() < MIN_DIRECTORY_MANAGER_PWD)
3604      {
3605        qs.displayFieldInvalid(FieldName.GLOBAL_ADMINISTRATOR_PWD_CONFIRM, true);
3606      }
3607      pwdValid = false;
3608    }
3609
3610    if (pwdValid)
3611    {
3612      getUserData().setGlobalAdministratorPassword(pwd1);
3613      qs.displayFieldInvalid(FieldName.GLOBAL_ADMINISTRATOR_PWD, false);
3614      qs.displayFieldInvalid(FieldName.GLOBAL_ADMINISTRATOR_PWD_CONFIRM, false);
3615    }
3616
3617    if (!errorMsgs.isEmpty())
3618    {
3619      throw new UserDataException(Step.CREATE_GLOBAL_ADMINISTRATOR, getMessageFromCollection(errorMsgs, "\n"));
3620    }
3621  }
3622
3623  /**
3624   * Validate the data provided by the user in the replicate suffixes options
3625   * panel and update the UserInstallData object according to that content.
3626   *
3627   * @throws UserDataException
3628   *           if the data provided by the user is not valid.
3629   */
3630  @SuppressWarnings("unchecked")
3631  private void updateUserDataForSuffixesOptionsPanel(QuickSetup qs) throws UserDataException
3632  {
3633    List<LocalizableMessage> errorMsgs = new ArrayList<>();
3634    if (qs.getFieldValue(FieldName.SUFFIXES_TO_REPLICATE_OPTIONS) ==
3635        SuffixesToReplicateOptions.Type.REPLICATE_WITH_EXISTING_SUFFIXES)
3636    {
3637      Set<?> s = (Set<?>) qs.getFieldValue(FieldName.SUFFIXES_TO_REPLICATE);
3638      if (s.isEmpty())
3639      {
3640        errorMsgs.add(INFO_NO_SUFFIXES_CHOSEN_TO_REPLICATE.get());
3641        qs.displayFieldInvalid(FieldName.SUFFIXES_TO_REPLICATE, true);
3642      }
3643      else
3644      {
3645        Set<SuffixDescriptor> chosen = new HashSet<>();
3646        for (Object o : s)
3647        {
3648          chosen.add((SuffixDescriptor) o);
3649        }
3650        qs.displayFieldInvalid(FieldName.SUFFIXES_TO_REPLICATE, false);
3651        Set<SuffixDescriptor> available = getUserData().getSuffixesToReplicateOptions().getAvailableSuffixes();
3652        Map<String, BackendTypeUIAdapter> suffixesBackendTypes =
3653            (Map<String, BackendTypeUIAdapter>) qs.getFieldValue(FieldName.SUFFIXES_TO_REPLICATE_BACKEND_TYPE);
3654        SuffixesToReplicateOptions options = new SuffixesToReplicateOptions(
3655            SuffixesToReplicateOptions.Type.REPLICATE_WITH_EXISTING_SUFFIXES, available, chosen, suffixesBackendTypes);
3656        getUserData().setSuffixesToReplicateOptions(options);
3657      }
3658      getUserData().setRemoteWithNoReplicationPort(getRemoteWithNoReplicationPort(getUserData()));
3659    }
3660    else
3661    {
3662      Set<SuffixDescriptor> available = getUserData().getSuffixesToReplicateOptions().getAvailableSuffixes();
3663      Set<SuffixDescriptor> chosen = getUserData().getSuffixesToReplicateOptions().getSuffixes();
3664      SuffixesToReplicateOptions options =
3665          new SuffixesToReplicateOptions(SuffixesToReplicateOptions.Type.NEW_SUFFIX_IN_TOPOLOGY, available, chosen);
3666      getUserData().setSuffixesToReplicateOptions(options);
3667    }
3668
3669    if (!errorMsgs.isEmpty())
3670    {
3671      throw new UserDataException(Step.SUFFIXES_OPTIONS, getMessageFromCollection(errorMsgs, "\n"));
3672    }
3673  }
3674
3675  /**
3676   * Validate the data provided by the user in the remote server replication
3677   * port panel and update the userData object according to that content.
3678   *
3679   * @throws UserDataException
3680   *           if the data provided by the user is not valid.
3681   */
3682  private void updateUserDataForRemoteReplicationPorts(QuickSetup qs) throws UserDataException
3683  {
3684    List<LocalizableMessage> errorMsgs = new ArrayList<>();
3685    Map<ServerDescriptor, AuthenticationData> servers = getUserData().getRemoteWithNoReplicationPort();
3686    Map<?, ?> hm = (Map<?, ?>) qs.getFieldValue(FieldName.REMOTE_REPLICATION_PORT);
3687    Map<?, ?> hmSecure = (Map<?, ?>) qs.getFieldValue(FieldName.REMOTE_REPLICATION_SECURE);
3688    for (ServerDescriptor server : servers.keySet())
3689    {
3690      String hostName = server.getHostName();
3691      boolean secureReplication = (Boolean) hmSecure.get(server.getId());
3692      String sPort = (String) hm.get(server.getId());
3693      try
3694      {
3695        int replicationPort = Integer.parseInt(sPort);
3696        if (replicationPort < MIN_PORT_VALUE || replicationPort > MAX_PORT_VALUE)
3697        {
3698          errorMsgs.add(INFO_INVALID_REMOTE_REPLICATION_PORT_VALUE_RANGE.get(getHostPort(server), MIN_PORT_VALUE,
3699              MAX_PORT_VALUE));
3700        }
3701        if (hostName.equalsIgnoreCase(getUserData().getHostName()))
3702        {
3703          int securePort = -1;
3704          if (getUserData().getSecurityOptions().getEnableSSL())
3705          {
3706            securePort = getUserData().getSecurityOptions().getSslPort();
3707          }
3708          if (replicationPort == getUserData().getServerPort() || replicationPort == getUserData().getServerJMXPort()
3709              || replicationPort == getUserData().getReplicationOptions().getReplicationPort()
3710              || replicationPort == securePort)
3711          {
3712            errorMsgs.add(INFO_REMOTE_REPLICATION_PORT_ALREADY_CHOSEN_FOR_OTHER_PROTOCOL.get(getHostPort(server)));
3713          }
3714        }
3715        AuthenticationData authData = new AuthenticationData();
3716        authData.setPort(replicationPort);
3717        authData.setUseSecureConnection(secureReplication);
3718        servers.put(server, authData);
3719      }
3720      catch (NumberFormatException nfe)
3721      {
3722        errorMsgs.add(INFO_INVALID_REMOTE_REPLICATION_PORT_VALUE_RANGE.get(hostName, MIN_PORT_VALUE, MAX_PORT_VALUE));
3723      }
3724    }
3725
3726    if (!errorMsgs.isEmpty())
3727    {
3728      qs.displayFieldInvalid(FieldName.REMOTE_REPLICATION_PORT, true);
3729      throw new UserDataException(Step.REMOTE_REPLICATION_PORTS, getMessageFromCollection(errorMsgs, "\n"));
3730    }
3731    else
3732    {
3733      qs.displayFieldInvalid(FieldName.REMOTE_REPLICATION_PORT, false);
3734      getUserData().setRemoteWithNoReplicationPort(servers);
3735    }
3736  }
3737
3738  /**
3739   * Validate the data provided by the user in the new suffix data options panel
3740   * and update the UserInstallData object according to that content.
3741   *
3742   * @throws UserDataException
3743   *           if the data provided by the user is not valid.
3744   */
3745  @SuppressWarnings("unchecked")
3746  private void updateUserDataForNewSuffixOptionsPanel(final QuickSetup ui) throws UserDataException
3747  {
3748    final List<LocalizableMessage> errorMsgs = new ArrayList<>();
3749    // Singleton list with the provided baseDN (if exists and valid)
3750    List<String> baseDn = new LinkedList<>();
3751    boolean validBaseDn = checkProvidedBaseDn(ui, baseDn, errorMsgs);
3752    final NewSuffixOptions dataOptions = checkImportData(ui, baseDn, validBaseDn, errorMsgs);
3753
3754    if (dataOptions != null)
3755    {
3756      getUserData().setBackendType((ManagedObjectDefinition<? extends BackendCfgClient, ? extends BackendCfg>)
3757          ui.getFieldValue(FieldName.BACKEND_TYPE));
3758      getUserData().setNewSuffixOptions(dataOptions);
3759    }
3760
3761    if (!errorMsgs.isEmpty())
3762    {
3763      throw new UserDataException(Step.NEW_SUFFIX_OPTIONS,
3764          getMessageFromCollection(errorMsgs, Constants.LINE_SEPARATOR));
3765    }
3766  }
3767
3768  private NewSuffixOptions checkImportData(final QuickSetup ui, final List<String> baseDn, final boolean validBaseDn,
3769      final List<LocalizableMessage> errorMsgs)
3770  {
3771    if (baseDn.isEmpty())
3772    {
3773      return NewSuffixOptions.createEmpty(baseDn);
3774    }
3775
3776    final NewSuffixOptions.Type type = (NewSuffixOptions.Type) ui.getFieldValue(FieldName.DATA_OPTIONS);
3777    switch (type)
3778    {
3779    case IMPORT_FROM_LDIF_FILE:
3780      return checkImportLDIFFile(ui, baseDn, validBaseDn, errorMsgs);
3781
3782    case IMPORT_AUTOMATICALLY_GENERATED_DATA:
3783      return checkImportGeneratedData(ui, baseDn, validBaseDn, errorMsgs);
3784
3785    default:
3786      if (validBaseDn)
3787      {
3788        return type == NewSuffixOptions.Type.CREATE_BASE_ENTRY ? NewSuffixOptions.createBaseEntry(baseDn)
3789            : NewSuffixOptions.createEmpty(baseDn);
3790      }
3791    }
3792
3793    return null;
3794  }
3795
3796  private NewSuffixOptions checkImportGeneratedData(final QuickSetup ui, final List<String> baseDn,
3797      final boolean validBaseDn, final List<LocalizableMessage> errorMsgs)
3798  {
3799    boolean fieldIsValid = true;
3800    final List<LocalizableMessage> localErrorMsgs = new LinkedList<>();
3801    final String nEntries = ui.getFieldStringValue(FieldName.NUMBER_ENTRIES);
3802    if (nEntries == null || "".equals(nEntries.trim()))
3803    {
3804      localErrorMsgs.add(INFO_NO_NUMBER_ENTRIES.get());
3805      fieldIsValid = false;
3806    }
3807    else
3808    {
3809      boolean nEntriesValid = false;
3810      try
3811      {
3812        int n = Integer.parseInt(nEntries);
3813        nEntriesValid = n >= MIN_NUMBER_ENTRIES && n <= MAX_NUMBER_ENTRIES;
3814      }
3815      catch (NumberFormatException nfe)
3816      {
3817        /* do nothing */
3818      }
3819
3820      if (!nEntriesValid)
3821      {
3822        localErrorMsgs.add(INFO_INVALID_NUMBER_ENTRIES_RANGE.get(MIN_NUMBER_ENTRIES, MAX_NUMBER_ENTRIES));
3823        fieldIsValid = false;
3824      }
3825    }
3826
3827    ui.displayFieldInvalid(FieldName.NUMBER_ENTRIES, !fieldIsValid);
3828    if (validBaseDn && localErrorMsgs.isEmpty())
3829    {
3830      return NewSuffixOptions.createAutomaticallyGenerated(baseDn, Integer.parseInt(nEntries));
3831    }
3832    errorMsgs.addAll(localErrorMsgs);
3833
3834    return null;
3835  }
3836
3837  private NewSuffixOptions checkImportLDIFFile(final QuickSetup ui, final List<String> baseDn,
3838      final boolean validBaseDn, final List<LocalizableMessage> errorMsgs)
3839  {
3840    final boolean fieldIsValid = false;
3841    final String ldifPath = ui.getFieldStringValue(FieldName.LDIF_PATH);
3842    if (ldifPath == null || ldifPath.trim().isEmpty())
3843    {
3844      errorMsgs.add(INFO_NO_LDIF_PATH.get());
3845    }
3846    else if (!fileExists(ldifPath))
3847    {
3848      errorMsgs.add(INFO_LDIF_FILE_DOES_NOT_EXIST.get());
3849    }
3850    else if (validBaseDn)
3851    {
3852      return NewSuffixOptions.createImportFromLDIF(baseDn, Collections.singletonList(ldifPath), null, null);
3853    }
3854    ui.displayFieldInvalid(FieldName.LDIF_PATH, !fieldIsValid);
3855
3856    return null;
3857  }
3858
3859  private boolean checkProvidedBaseDn(final QuickSetup ui, final List<String> baseDn,
3860      final List<LocalizableMessage> errorMsgs)
3861  {
3862    boolean validBaseDn = true;
3863    String dn = ui.getFieldStringValue(FieldName.DIRECTORY_BASE_DN);
3864    if (dn == null || dn.trim().length() == 0)
3865    {
3866      // Do nothing, the user does not want to provide a base DN.
3867      dn = "";
3868    }
3869    else if (!isDN(dn))
3870    {
3871      validBaseDn = false;
3872      errorMsgs.add(INFO_NOT_A_BASE_DN.get());
3873    }
3874    else if (isConfigurationDn(dn))
3875    {
3876      validBaseDn = false;
3877      errorMsgs.add(INFO_BASE_DN_IS_CONFIGURATION_DN.get());
3878    }
3879    else
3880    {
3881      baseDn.add(dn);
3882    }
3883    ui.displayFieldInvalid(FieldName.DIRECTORY_BASE_DN, !validBaseDn);
3884
3885    return validBaseDn;
3886  }
3887
3888  /** Update the userData object according to the content of the runtime options panel. */
3889  private void updateUserDataForRuntimeOptionsPanel(QuickSetup qs)
3890  {
3891    getUserData().setJavaArguments(UserData.SERVER_SCRIPT_NAME,
3892        (JavaArguments) qs.getFieldValue(FieldName.SERVER_JAVA_ARGUMENTS));
3893    getUserData().setJavaArguments(UserData.IMPORT_SCRIPT_NAME,
3894        (JavaArguments) qs.getFieldValue(FieldName.IMPORT_JAVA_ARGUMENTS));
3895  }
3896
3897  /** Update the userData object according to the content of the review panel. */
3898  private void updateUserDataForReviewPanel(QuickSetup qs)
3899  {
3900    Boolean b = (Boolean) qs.getFieldValue(FieldName.SERVER_START_INSTALLER);
3901    getUserData().setStartServer(b);
3902    b = (Boolean) qs.getFieldValue(FieldName.ENABLE_WINDOWS_SERVICE);
3903    getUserData().setEnableWindowsService(b);
3904  }
3905
3906  /** Update the UserInstallData with the contents we discover in the ADS. */
3907  private Set<TopologyCacheException> updateUserDataWithSuffixesInADS(ADSContext adsContext,
3908      ApplicationTrustManager trustManager) throws TopologyCacheException
3909  {
3910    Set<TopologyCacheException> exceptions = new HashSet<>();
3911    SuffixesToReplicateOptions suf = getUserData().getSuffixesToReplicateOptions();
3912    SuffixesToReplicateOptions.Type type;
3913
3914    if (suf == null || suf.getType() == SuffixesToReplicateOptions.Type.NO_SUFFIX_TO_REPLICATE)
3915    {
3916      type = SuffixesToReplicateOptions.Type.NO_SUFFIX_TO_REPLICATE;
3917    }
3918    else
3919    {
3920      type = SuffixesToReplicateOptions.Type.NEW_SUFFIX_IN_TOPOLOGY;
3921    }
3922    lastLoadedCache = new TopologyCache(adsContext, trustManager, getConnectTimeout());
3923    // We cannot use getPreferredConnections since the user data has not been updated yet.
3924    lastLoadedCache.setPreferredConnections(PreferredConnection.getPreferredConnections(adsContext.getConnection()));
3925    lastLoadedCache.reloadTopology();
3926    Set<SuffixDescriptor> suffixes = lastLoadedCache.getSuffixes();
3927    Set<SuffixDescriptor> moreSuffixes = null;
3928    if (suf != null)
3929    {
3930      moreSuffixes = suf.getSuffixes();
3931    }
3932    getUserData().setSuffixesToReplicateOptions(new SuffixesToReplicateOptions(type, suffixes, moreSuffixes));
3933
3934    /*
3935     * Analyze if we had any exception while loading servers. For the moment
3936     * only throw the exception found if the user did not provide the
3937     * Administrator DN and this caused a problem authenticating in one server
3938     * or if there is a certificate problem.
3939     */
3940    Set<ServerDescriptor> servers = lastLoadedCache.getServers();
3941    for (ServerDescriptor server : servers)
3942    {
3943      TopologyCacheException e = server.getLastException();
3944      if (e != null)
3945      {
3946        exceptions.add(e);
3947      }
3948    }
3949    return exceptions;
3950  }
3951
3952  /**
3953   * Update the UserInstallData object with the contents of the server to which
3954   * we are connected with the provided InitialLdapContext.
3955   */
3956  private void updateUserDataWithSuffixesInServer(InitialLdapContext ctx) throws NamingException
3957  {
3958    SuffixesToReplicateOptions suf = getUserData().getSuffixesToReplicateOptions();
3959    SuffixesToReplicateOptions.Type type;
3960    Set<SuffixDescriptor> suffixes = new HashSet<>();
3961    if (suf != null)
3962    {
3963      type = suf.getType();
3964    }
3965    else
3966    {
3967      type = SuffixesToReplicateOptions.Type.NEW_SUFFIX_IN_TOPOLOGY;
3968    }
3969
3970    ServerDescriptor s = createStandalone(ctx, new TopologyCacheFilter());
3971    Set<ReplicaDescriptor> replicas = s.getReplicas();
3972    for (ReplicaDescriptor replica : replicas)
3973    {
3974      suffixes.add(replica.getSuffix());
3975    }
3976    Set<SuffixDescriptor> moreSuffixes = null;
3977    if (suf != null)
3978    {
3979      moreSuffixes = suf.getSuffixes();
3980    }
3981    getUserData().setSuffixesToReplicateOptions(new SuffixesToReplicateOptions(type, suffixes, moreSuffixes));
3982  }
3983
3984  /**
3985   * Returns the keystore path to be used for generating a self-signed
3986   * certificate.
3987   *
3988   * @return the keystore path to be used for generating a self-signed
3989   *         certificate.
3990   */
3991  private String getSelfSignedKeystorePath()
3992  {
3993    return getPath2("keystore");
3994  }
3995
3996  /**
3997   * Returns the trustmanager path to be used for generating a self-signed
3998   * certificate.
3999   *
4000   * @return the trustmanager path to be used for generating a self-signed
4001   *         certificate.
4002   */
4003  private String getTrustManagerPath()
4004  {
4005    return getPath2("truststore");
4006  }
4007
4008  /**
4009   * Returns the path of the self-signed that we export to be able to create a
4010   * truststore.
4011   *
4012   * @return the path of the self-signed that is exported.
4013   */
4014  private String getTemporaryCertificatePath()
4015  {
4016    return getPath2("server-cert.txt");
4017  }
4018
4019  /**
4020   * Returns the path to be used to store the password of the keystore.
4021   *
4022   * @return the path to be used to store the password of the keystore.
4023   */
4024  private String getKeystorePinPath()
4025  {
4026    return getPath2("keystore.pin");
4027  }
4028
4029  private String getPath2(String relativePath)
4030  {
4031    String parentFile = getPath(getInstancePath(), Installation.CONFIG_PATH_RELATIVE);
4032    return getPath(parentFile, relativePath);
4033  }
4034
4035  /**
4036   * Returns the validity period to be used to generate the self-signed
4037   * certificate.
4038   *
4039   * @return the validity period to be used to generate the self-signed
4040   *         certificate.
4041   */
4042  private int getSelfSignedCertificateValidity()
4043  {
4044    return 20 * 365;
4045  }
4046
4047  /**
4048   * Returns the Subject DN to be used to generate the self-signed certificate.
4049   *
4050   * @return the Subject DN to be used to generate the self-signed certificate.
4051   */
4052  private String getSelfSignedCertificateSubjectDN(KeyType keyType)
4053  {
4054    return "cn=" + Rdn.escapeValue(getUserData().getHostName()) + ",O=OpenDJ " + keyType + " Self-Signed Certificate";
4055  }
4056
4057  /**
4058   * Returns the self-signed certificate password used for this session. This
4059   * method calls <code>createSelfSignedCertificatePwd()</code> the first time
4060   * this method is called.
4061   *
4062   * @return the self-signed certificate password used for this session.
4063   */
4064  private String getSelfSignedCertificatePwd()
4065  {
4066    if (selfSignedCertPw == null)
4067    {
4068      selfSignedCertPw = SetupUtils.createSelfSignedCertificatePwd();
4069    }
4070    return new String(selfSignedCertPw);
4071  }
4072
4073  private Map<ServerDescriptor, AuthenticationData> getRemoteWithNoReplicationPort(UserData userData)
4074  {
4075    Map<ServerDescriptor, AuthenticationData> servers = new HashMap<>();
4076    Set<SuffixDescriptor> suffixes = userData.getSuffixesToReplicateOptions().getSuffixes();
4077    for (SuffixDescriptor suffix : suffixes)
4078    {
4079      for (ReplicaDescriptor replica : suffix.getReplicas())
4080      {
4081        ServerDescriptor server = replica.getServer();
4082        Object v = server.getServerProperties().get(IS_REPLICATION_SERVER);
4083        if (!Boolean.TRUE.equals(v))
4084        {
4085          AuthenticationData authData = new AuthenticationData();
4086          authData.setPort(Constants.DEFAULT_REPLICATION_PORT);
4087          authData.setUseSecureConnection(false);
4088          servers.put(server, authData);
4089        }
4090      }
4091    }
4092    return servers;
4093  }
4094
4095  private ConnectionWrapper createLocalConnection() throws NamingException
4096  {
4097    UserData uData = getUserData();
4098    HostPort hostPort = new HostPort(uData.getHostName(), uData.getAdminConnectorPort());
4099    String dn = uData.getDirectoryManagerDn();
4100    String pwd = uData.getDirectoryManagerPwd();
4101    return new ConnectionWrapper(hostPort, LDAPS, dn, pwd, getConnectTimeout(), null);
4102  }
4103
4104  /**
4105   * Gets a connection based on the information that appears on the
4106   * provided ServerDescriptor.
4107   *
4108   * @param server
4109   *          the object describing the server.
4110   * @return the InitialLdapContext to the remote server.
4111   * @throws ApplicationException
4112   *           if something goes wrong.
4113   */
4114  private ConnectionWrapper getRemoteConnection(ServerDescriptor server) throws ApplicationException
4115  {
4116    Map<ADSContext.ServerProperty, Object> adsProperties;
4117    AuthenticationData auth = getUserData().getReplicationOptions().getAuthenticationData();
4118    if (!server.isRegistered())
4119    {
4120      /*
4121       * Create adsProperties to be able to use the class ServerLoader to get
4122       * the connection. Just update the connection parameters with what the
4123       * user chose in the Topology Options panel (i.e. even if SSL is enabled
4124       * on the remote server, use standard LDAP to connect to the server if the
4125       * user specified the LDAP port: this avoids having an issue with the
4126       * certificate if it has not been accepted previously by the user).
4127       */
4128      adsProperties = new HashMap<>();
4129      adsProperties.put(ADSContext.ServerProperty.HOST_NAME, server.getHostName());
4130      if (auth.useSecureConnection())
4131      {
4132        adsProperties.put(ADSContext.ServerProperty.LDAPS_PORT, String.valueOf(auth.getPort()));
4133        adsProperties.put(ADSContext.ServerProperty.LDAPS_ENABLED, "true");
4134      }
4135      else
4136      {
4137        adsProperties.put(ADSContext.ServerProperty.LDAP_PORT, String.valueOf(auth.getPort()));
4138        adsProperties.put(ADSContext.ServerProperty.LDAP_ENABLED, "true");
4139      }
4140      server.setAdsProperties(adsProperties);
4141    }
4142    return getRemoteConnection(server, auth.getDn(), auth.getPwd(), getConnectTimeout(), getPreferredConnections());
4143  }
4144
4145  /**
4146   * Initializes a suffix with the contents of a replica that has a given
4147   * replication id.
4148   *
4149   * @param ctx
4150   *          the connection to the server whose suffix we want to initialize.
4151   * @param replicaId
4152   *          the replication ID of the replica we want to use to initialize the
4153   *          contents of the suffix.
4154   * @param suffixDn
4155   *          the dn of the suffix.
4156   * @param displayProgress
4157   *          whether we want to display progress or not.
4158   * @param sourceServerDisplay
4159   *          the string to be used to represent the server that contains the
4160   *          data that will be used to initialize the suffix.
4161   * @throws ApplicationException
4162   *           if an unexpected error occurs.
4163   * @throws PeerNotFoundException
4164   *           if the replication mechanism cannot find a peer.
4165   */
4166  public void initializeSuffix(InitialLdapContext ctx, int replicaId, String suffixDn, boolean displayProgress,
4167      HostPort sourceServerDisplay) throws ApplicationException, PeerNotFoundException
4168  {
4169    boolean taskCreated = false;
4170    int i = 1;
4171    boolean isOver = false;
4172    String dn = null;
4173    BasicAttributes attrs = new BasicAttributes();
4174    Attribute oc = new BasicAttribute("objectclass");
4175    oc.add("top");
4176    oc.add("ds-task");
4177    oc.add("ds-task-initialize-from-remote-replica");
4178    attrs.put(oc);
4179    attrs.put("ds-task-class-name", "org.opends.server.tasks.InitializeTask");
4180    attrs.put("ds-task-initialize-domain-dn", suffixDn);
4181    attrs.put("ds-task-initialize-replica-server-id", String.valueOf(replicaId));
4182    while (!taskCreated)
4183    {
4184      checkAbort();
4185      String id = "quicksetup-initialize" + i;
4186      dn = "ds-task-id=" + id + ",cn=Scheduled Tasks,cn=Tasks";
4187      attrs.put("ds-task-id", id);
4188      try
4189      {
4190        DirContext dirCtx = ctx.createSubcontext(dn, attrs);
4191        taskCreated = true;
4192        logger.info(LocalizableMessage.raw("created task entry: " + attrs));
4193        dirCtx.close();
4194      }
4195      catch (NameAlreadyBoundException x)
4196      {
4197        logger.warn(LocalizableMessage.raw("A task with dn: " + dn + " already existed."));
4198      }
4199      catch (NamingException ne)
4200      {
4201        logger.error(LocalizableMessage.raw("Error creating task " + attrs, ne));
4202        throw new ApplicationException(ReturnCode.APPLICATION_ERROR, getThrowableMsg(
4203            INFO_ERROR_LAUNCHING_INITIALIZATION.get(sourceServerDisplay), ne), ne);
4204      }
4205      i++;
4206    }
4207    // Wait until it is over
4208    SearchControls searchControls = new SearchControls();
4209    searchControls.setSearchScope(SearchControls.OBJECT_SCOPE);
4210    String filter = "objectclass=*";
4211    searchControls.setReturningAttributes(new String[] { "ds-task-unprocessed-entry-count",
4212      "ds-task-processed-entry-count", "ds-task-log-message", "ds-task-state" });
4213    LocalizableMessage lastDisplayedMsg = null;
4214    String lastLogMsg = null;
4215    long lastTimeMsgDisplayed = -1;
4216    long lastTimeMsgLogged = -1;
4217    long totalEntries = 0;
4218    while (!isOver)
4219    {
4220      if (canceled)
4221      {
4222        // TODO: we should try to cleanly abort the initialize.  As we have
4223        // aborted the install, the server will be stopped and the remote
4224        // server will receive a connect error.
4225        checkAbort();
4226      }
4227      StaticUtils.sleep(500);
4228      if (canceled)
4229      {
4230        // TODO: we should try to cleanly abort the initialize.  As we have
4231        // aborted the install, the server will be stopped and the remote
4232        // server will receive a connect error.
4233        checkAbort();
4234      }
4235      try
4236      {
4237        NamingEnumeration<SearchResult> res = ctx.search(dn, filter, searchControls);
4238        SearchResult sr = null;
4239        try
4240        {
4241          while (res.hasMore())
4242          {
4243            sr = res.next();
4244          }
4245        }
4246        finally
4247        {
4248          res.close();
4249        }
4250        // Get the number of entries that have been handled and
4251        // a percentage...
4252        LocalizableMessage msg;
4253        String sProcessed = getFirstValue(sr, "ds-task-processed-entry-count");
4254        String sUnprocessed = getFirstValue(sr, "ds-task-unprocessed-entry-count");
4255        long processed = -1;
4256        long unprocessed = -1;
4257        if (sProcessed != null)
4258        {
4259          processed = Integer.parseInt(sProcessed);
4260        }
4261        if (sUnprocessed != null)
4262        {
4263          unprocessed = Integer.parseInt(sUnprocessed);
4264        }
4265        totalEntries = Math.max(totalEntries, processed + unprocessed);
4266
4267        if (processed != -1 && unprocessed != -1)
4268        {
4269          if (processed + unprocessed > 0)
4270          {
4271            long perc = (100 * processed) / (processed + unprocessed);
4272            msg = INFO_INITIALIZE_PROGRESS_WITH_PERCENTAGE.get(sProcessed, perc);
4273          }
4274          else
4275          {
4276            //msg = INFO_NO_ENTRIES_TO_INITIALIZE.get();
4277            msg = null;
4278          }
4279        }
4280        else if (processed != -1)
4281        {
4282          msg = INFO_INITIALIZE_PROGRESS_WITH_PROCESSED.get(sProcessed);
4283        }
4284        else if (unprocessed != -1)
4285        {
4286          msg = INFO_INITIALIZE_PROGRESS_WITH_UNPROCESSED.get(sUnprocessed);
4287        }
4288        else
4289        {
4290          msg = lastDisplayedMsg;
4291        }
4292
4293        if (msg != null)
4294        {
4295          long currentTime = System.currentTimeMillis();
4296          /* Refresh period: to avoid having too many lines in the log */
4297          long minRefreshPeriod;
4298          if (totalEntries < 100)
4299          {
4300            minRefreshPeriod = 0;
4301          }
4302          else if (totalEntries < 1000)
4303          {
4304            minRefreshPeriod = 1000;
4305          }
4306          else if (totalEntries < 10000)
4307          {
4308            minRefreshPeriod = 5000;
4309          }
4310          else
4311          {
4312            minRefreshPeriod = 10000;
4313          }
4314          if (currentTime - minRefreshPeriod > lastTimeMsgLogged)
4315          {
4316            lastTimeMsgLogged = currentTime;
4317            logger.info(LocalizableMessage.raw("Progress msg: " + msg));
4318          }
4319          if (displayProgress && currentTime - minRefreshPeriod > lastTimeMsgDisplayed && !msg.equals(lastDisplayedMsg))
4320          {
4321            notifyListeners(getFormattedProgress(msg));
4322            lastDisplayedMsg = msg;
4323            notifyListeners(getLineBreak());
4324            lastTimeMsgDisplayed = currentTime;
4325          }
4326        }
4327
4328        String logMsg = getFirstValue(sr, "ds-task-log-message");
4329        if (logMsg != null && !logMsg.equals(lastLogMsg))
4330        {
4331          logger.info(LocalizableMessage.raw(logMsg));
4332          lastLogMsg = logMsg;
4333        }
4334        InstallerHelper helper = new InstallerHelper();
4335        String state = getFirstValue(sr, "ds-task-state");
4336
4337        if (helper.isDone(state) || helper.isStoppedByError(state))
4338        {
4339          isOver = true;
4340          LocalizableMessage errorMsg;
4341          logger.info(LocalizableMessage.raw("Last task entry: " + sr));
4342          if (displayProgress && msg != null && !msg.equals(lastDisplayedMsg))
4343          {
4344            notifyListeners(getFormattedProgress(msg));
4345            lastDisplayedMsg = msg;
4346            notifyListeners(getLineBreak());
4347          }
4348
4349          if (lastLogMsg != null)
4350          {
4351            errorMsg =
4352                INFO_ERROR_DURING_INITIALIZATION_LOG.get(sourceServerDisplay, lastLogMsg, state, sourceServerDisplay);
4353          }
4354          else
4355          {
4356            errorMsg = INFO_ERROR_DURING_INITIALIZATION_NO_LOG.get(sourceServerDisplay, state, sourceServerDisplay);
4357          }
4358
4359          logger.warn(LocalizableMessage.raw("Processed errorMsg: " + errorMsg));
4360          if (helper.isCompletedWithErrors(state))
4361          {
4362            if (displayProgress)
4363            {
4364              notifyListeners(getFormattedWarning(errorMsg));
4365            }
4366          }
4367          else if (!helper.isSuccessful(state) || helper.isStoppedByError(state))
4368          {
4369            ApplicationException ae = new ApplicationException(ReturnCode.APPLICATION_ERROR, errorMsg, null);
4370            if (lastLogMsg == null || helper.isPeersNotFoundError(lastLogMsg))
4371            {
4372              logger.warn(LocalizableMessage.raw("Throwing peer not found error.  " + "Last Log Msg: " + lastLogMsg));
4373              // Assume that this is a peer not found error.
4374              throw new PeerNotFoundException(errorMsg);
4375            }
4376            else
4377            {
4378              logger.error(LocalizableMessage.raw("Throwing ApplicationException."));
4379              throw ae;
4380            }
4381          }
4382          else if (displayProgress)
4383          {
4384            logger.info(LocalizableMessage.raw("Initialization completed successfully."));
4385            notifyListeners(getFormattedProgress(INFO_SUFFIX_INITIALIZED_SUCCESSFULLY.get()));
4386            notifyListeners(getLineBreak());
4387          }
4388        }
4389      }
4390      catch (NameNotFoundException x)
4391      {
4392        isOver = true;
4393        logger.info(LocalizableMessage.raw("Initialization entry not found."));
4394        if (displayProgress)
4395        {
4396          notifyListeners(getFormattedProgress(INFO_SUFFIX_INITIALIZED_SUCCESSFULLY.get()));
4397          notifyListeners(getLineBreak());
4398        }
4399      }
4400      catch (NamingException ne)
4401      {
4402        throw new ApplicationException(ReturnCode.APPLICATION_ERROR, getThrowableMsg(INFO_ERROR_POOLING_INITIALIZATION
4403            .get(sourceServerDisplay), ne), ne);
4404      }
4405    }
4406    resetGenerationId(ctx, suffixDn, sourceServerDisplay);
4407  }
4408
4409  /**
4410   * Returns the configuration file path to be used when invoking the
4411   * command-lines.
4412   *
4413   * @return the configuration file path to be used when invoking the
4414   *         command-lines.
4415   */
4416  private String getConfigurationFile()
4417  {
4418    return getPath(getInstallation().getCurrentConfigurationFile());
4419  }
4420
4421  private String getLocalReplicationServer()
4422  {
4423    return getUserData().getHostName() + ":" + getUserData().getReplicationOptions().getReplicationPort();
4424  }
4425
4426  private void resetGenerationId(InitialLdapContext ctx, String suffixDn, HostPort sourceServerDisplay)
4427      throws ApplicationException
4428  {
4429    boolean taskCreated = false;
4430    int i = 1;
4431    boolean isOver = false;
4432    String dn = null;
4433    BasicAttributes attrs = new BasicAttributes();
4434    Attribute oc = new BasicAttribute("objectclass");
4435    oc.add("top");
4436    oc.add("ds-task");
4437    oc.add("ds-task-reset-generation-id");
4438    attrs.put(oc);
4439    attrs.put("ds-task-class-name", "org.opends.server.tasks.SetGenerationIdTask");
4440    attrs.put("ds-task-reset-generation-id-domain-base-dn", suffixDn);
4441    while (!taskCreated)
4442    {
4443      checkAbort();
4444      String id = "quicksetup-reset-generation-id-" + i;
4445      dn = "ds-task-id=" + id + ",cn=Scheduled Tasks,cn=Tasks";
4446      attrs.put("ds-task-id", id);
4447      try
4448      {
4449        DirContext dirCtx = ctx.createSubcontext(dn, attrs);
4450        taskCreated = true;
4451        logger.info(LocalizableMessage.raw("created task entry: " + attrs));
4452        dirCtx.close();
4453      }
4454      catch (NameAlreadyBoundException x)
4455      {
4456      }
4457      catch (NamingException ne)
4458      {
4459        logger.error(LocalizableMessage.raw("Error creating task " + attrs, ne));
4460        throw new ApplicationException(ReturnCode.APPLICATION_ERROR, getThrowableMsg(
4461            INFO_ERROR_LAUNCHING_INITIALIZATION.get(sourceServerDisplay), ne), ne);
4462      }
4463      i++;
4464    }
4465    // Wait until it is over
4466    SearchControls searchControls = new SearchControls();
4467    searchControls.setSearchScope(SearchControls.OBJECT_SCOPE);
4468    String filter = "objectclass=*";
4469    searchControls.setReturningAttributes(new String[] { "ds-task-log-message", "ds-task-state" });
4470    String lastLogMsg = null;
4471    while (!isOver)
4472    {
4473      StaticUtils.sleep(500);
4474      try
4475      {
4476        NamingEnumeration<SearchResult> res = ctx.search(dn, filter, searchControls);
4477        SearchResult sr = null;
4478        try
4479        {
4480          while (res.hasMore())
4481          {
4482            sr = res.next();
4483          }
4484        }
4485        finally
4486        {
4487          res.close();
4488        }
4489        String logMsg = getFirstValue(sr, "ds-task-log-message");
4490        if (logMsg != null && !logMsg.equals(lastLogMsg))
4491        {
4492          logger.info(LocalizableMessage.raw(logMsg));
4493          lastLogMsg = logMsg;
4494        }
4495        InstallerHelper helper = new InstallerHelper();
4496        String state = getFirstValue(sr, "ds-task-state");
4497
4498        if (helper.isDone(state) || helper.isStoppedByError(state))
4499        {
4500          isOver = true;
4501          LocalizableMessage errorMsg = lastLogMsg != null ?
4502              INFO_ERROR_DURING_INITIALIZATION_LOG.get(sourceServerDisplay, lastLogMsg, state, sourceServerDisplay)
4503            : INFO_ERROR_DURING_INITIALIZATION_NO_LOG.get(sourceServerDisplay, state, sourceServerDisplay);
4504
4505          if (helper.isCompletedWithErrors(state))
4506          {
4507            logger.warn(LocalizableMessage.raw("Completed with error: " + errorMsg));
4508            notifyListeners(getFormattedWarning(errorMsg));
4509          }
4510          else if (!helper.isSuccessful(state) || helper.isStoppedByError(state))
4511          {
4512            logger.warn(LocalizableMessage.raw("Error: " + errorMsg));
4513            throw new ApplicationException(ReturnCode.APPLICATION_ERROR, errorMsg, null);
4514          }
4515        }
4516      }
4517      catch (NameNotFoundException x)
4518      {
4519        isOver = true;
4520      }
4521      catch (NamingException ne)
4522      {
4523        throw new ApplicationException(ReturnCode.APPLICATION_ERROR,
4524            getThrowableMsg(INFO_ERROR_POOLING_INITIALIZATION.get(sourceServerDisplay), ne), ne);
4525      }
4526    }
4527  }
4528
4529  /**
4530   * Invokes a long operation in a separate thread and checks whether the user
4531   * canceled the operation or not.
4532   *
4533   * @param thread
4534   *          the Thread that must be launched.
4535   * @throws ApplicationException
4536   *           if there was an error executing the task or if the user canceled
4537   *           the installer.
4538   */
4539  private void invokeLongOperation(InvokeThread thread) throws ApplicationException
4540  {
4541    try
4542    {
4543      thread.start();
4544      while (!thread.isOver() && thread.isAlive())
4545      {
4546        if (canceled)
4547        {
4548          // Try to abort the thread
4549          try
4550          {
4551            thread.abort();
4552          }
4553          catch (Throwable t)
4554          {
4555            logger.warn(LocalizableMessage.raw("Error cancelling thread: " + t, t));
4556          }
4557        }
4558        else if (thread.getException() != null)
4559        {
4560          throw thread.getException();
4561        }
4562        else
4563        {
4564          StaticUtils.sleep(100);
4565        }
4566      }
4567      if (thread.getException() != null)
4568      {
4569        throw thread.getException();
4570      }
4571      if (canceled)
4572      {
4573        checkAbort();
4574      }
4575    }
4576    catch (ApplicationException e)
4577    {
4578      logger.error(LocalizableMessage.raw("Error: " + e, e));
4579      throw e;
4580    }
4581    catch (Throwable t)
4582    {
4583      logger.error(LocalizableMessage.raw("Error: " + t, t));
4584      throw new ApplicationException(ReturnCode.BUG, getThrowableMsg(INFO_BUG_MSG.get(), t), t);
4585    }
4586  }
4587
4588  /**
4589   * Returns the host port representation of the server to be used in progress
4590   * and error messages. It takes into account the fact the host and port
4591   * provided by the user in the replication options panel. NOTE: the code
4592   * assumes that the user data with the contents of the replication options has
4593   * already been updated.
4594   *
4595   * @param server
4596   *          the ServerDescriptor.
4597   * @return the host port string representation of the provided server.
4598   */
4599  private HostPort getHostPort(ServerDescriptor server)
4600  {
4601    HostPort hostPort = null;
4602
4603    for (PreferredConnection connection : getPreferredConnections())
4604    {
4605      String url = connection.getLDAPURL();
4606      if (url.equals(server.getLDAPURL()))
4607      {
4608        hostPort = server.getHostPort(false);
4609      }
4610      else if (url.equals(server.getLDAPsURL()))
4611      {
4612        hostPort = server.getHostPort(true);
4613      }
4614    }
4615    if (hostPort == null)
4616    {
4617      hostPort = server.getHostPort(true);
4618    }
4619    return hostPort;
4620  }
4621
4622  @Override
4623  protected void applicationPrintStreamReceived(String message)
4624  {
4625    InstallerHelper helper = new InstallerHelper();
4626    String parsedMessage = helper.getImportProgressMessage(message);
4627    if (parsedMessage != null)
4628    {
4629      lastImportProgress = parsedMessage;
4630    }
4631  }
4632
4633  /**
4634   * Returns the timeout to be used to connect in milliseconds.
4635   *
4636   * @return the timeout to be used to connect in milliseconds. Returns
4637   *         {@code 0} if there is no timeout.
4638   */
4639  private int getConnectTimeout()
4640  {
4641    return getUserData().getConnectTimeout();
4642  }
4643
4644  /**
4645   * Copies the template instance files into the instance directory.
4646   *
4647   * @throws ApplicationException
4648   *           If an IO error occurred.
4649   */
4650  private void copyTemplateInstance() throws ApplicationException
4651  {
4652    FileManager fileManager = new FileManager();
4653    fileManager.synchronize(getInstallation().getTemplateDirectory(), getInstallation().getInstanceDirectory());
4654  }
4655}
4656
4657/** Class used to be able to cancel long operations. */
4658abstract class InvokeThread extends Thread
4659{
4660  protected boolean isOver;
4661  protected ApplicationException ae;
4662
4663  /**
4664   * Returns whether the thread is over.
4665   *
4666   * @return {@code true} if the thread is over and {@code false} otherwise.
4667   */
4668  public boolean isOver()
4669  {
4670    return isOver;
4671  }
4672
4673  /**
4674   * Returns the exception that was encountered running the thread.
4675   *
4676   * @return the exception that was encountered running the thread.
4677   */
4678  public ApplicationException getException()
4679  {
4680    return ae;
4681  }
4682
4683  @Override
4684  public abstract void run();
4685
4686  /** Abort this thread. */
4687  public abstract void abort();
4688}