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