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