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