001/* 002 * The contents of this file are subject to the terms of the Common Development and 003 * Distribution License (the License). You may not use this file except in compliance with the 004 * License. 005 * 006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 007 * specific language governing permission and limitations under the License. 008 * 009 * When distributing Covered Software, include this CDDL Header Notice in each file and include 010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 011 * Header, with the fields enclosed by brackets [] replaced by your own identifying 012 * information: "Portions Copyright [year] [name of copyright owner]". 013 * 014 * Copyright 2006-2010 Sun Microsystems, Inc. 015 * Portions Copyright 2011-2016 ForgeRock AS. 016 */ 017package org.opends.quicksetup.util; 018 019import static com.forgerock.opendj.cli.Utils.*; 020import static com.forgerock.opendj.util.OperatingSystem.*; 021 022import static org.forgerock.util.Utils.*; 023import static org.opends.admin.ads.util.ConnectionUtils.*; 024import static org.opends.messages.QuickSetupMessages.*; 025import static org.opends.quicksetup.Installation.*; 026import static org.opends.server.util.CollectionUtils.*; 027import static org.opends.server.util.DynamicConstants.*; 028 029import java.io.BufferedOutputStream; 030import java.io.BufferedReader; 031import java.io.ByteArrayOutputStream; 032import java.io.File; 033import java.io.FileOutputStream; 034import java.io.FileReader; 035import java.io.FileWriter; 036import java.io.IOException; 037import java.io.InputStream; 038import java.io.InputStreamReader; 039import java.io.PrintStream; 040import java.io.PrintWriter; 041import java.net.InetAddress; 042import java.text.SimpleDateFormat; 043import java.util.ArrayList; 044import java.util.Collection; 045import java.util.HashMap; 046import java.util.Hashtable; 047import java.util.LinkedHashSet; 048import java.util.List; 049import java.util.Locale; 050import java.util.Map; 051import java.util.Set; 052import java.util.TimeZone; 053 054import javax.naming.AuthenticationException; 055import javax.naming.CommunicationException; 056import javax.naming.NamingEnumeration; 057import javax.naming.NamingException; 058import javax.naming.NamingSecurityException; 059import javax.naming.NoPermissionException; 060import javax.naming.directory.SearchControls; 061import javax.naming.directory.SearchResult; 062import javax.naming.ldap.InitialLdapContext; 063import javax.naming.ldap.LdapName; 064import javax.net.ssl.HostnameVerifier; 065import javax.net.ssl.TrustManager; 066 067import org.forgerock.i18n.LocalizableMessage; 068import org.forgerock.i18n.LocalizableMessageBuilder; 069import org.forgerock.i18n.slf4j.LocalizedLogger; 070import org.forgerock.opendj.config.ManagedObjectDefinition; 071import org.forgerock.opendj.server.config.client.BackendCfgClient; 072import org.forgerock.opendj.server.config.server.BackendCfg; 073import org.opends.admin.ads.ADSContext; 074import org.opends.admin.ads.ReplicaDescriptor; 075import org.opends.admin.ads.ServerDescriptor; 076import org.opends.admin.ads.SuffixDescriptor; 077import org.opends.admin.ads.TopologyCacheException; 078import org.opends.admin.ads.util.ConnectionUtils; 079import org.opends.quicksetup.Constants; 080import org.opends.quicksetup.Installation; 081import org.opends.quicksetup.SecurityOptions; 082import org.opends.quicksetup.UserData; 083import org.opends.quicksetup.installer.AuthenticationData; 084import org.opends.quicksetup.installer.DataReplicationOptions; 085import org.opends.quicksetup.installer.NewSuffixOptions; 086import org.opends.quicksetup.installer.SuffixesToReplicateOptions; 087import org.opends.quicksetup.ui.UIFactory; 088import org.opends.server.tools.BackendTypeHelper; 089import org.opends.server.util.SetupUtils; 090 091import com.forgerock.opendj.cli.ArgumentConstants; 092import com.forgerock.opendj.cli.ClientException; 093 094/** This class provides some static convenience methods of different nature. */ 095public class Utils 096{ 097 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 098 099 private Utils() {} 100 101 private static final int BUFFER_SIZE = 1024; 102 private static final int MAX_LINE_WIDTH = 80; 103 104 /** Chars that require special treatment when passing them to command-line. */ 105 private static final char[] CHARS_TO_ESCAPE = 106 { ' ', '\t', '\n', '|', ';', '<', '>', '(', ')', '$', '`', '\\', '"', '\'' }; 107 108 /** The class name that contains the control panel customizations for products. */ 109 private static final String CUSTOMIZATION_CLASS_NAME = "org.opends.server.util.ReleaseDefinition"; 110 111 /** 112 * Returns <CODE>true</CODE> if the provided port is free and we can use it, 113 * <CODE>false</CODE> otherwise. 114 * 115 * @param port 116 * the port we are analyzing. 117 * @return <CODE>true</CODE> if the provided port is free and we can use it, 118 * <CODE>false</CODE> otherwise. 119 */ 120 public static boolean canUseAsPort(int port) 121 { 122 return SetupUtils.canUseAsPort(port); 123 } 124 125 /** 126 * Returns <CODE>true</CODE> if the provided port is a privileged port, 127 * <CODE>false</CODE> otherwise. 128 * 129 * @param port 130 * the port we are analyzing. 131 * @return <CODE>true</CODE> if the provided port is a privileged port, 132 * <CODE>false</CODE> otherwise. 133 */ 134 public static boolean isPrivilegedPort(int port) 135 { 136 return SetupUtils.isPrivilegedPort(port); 137 } 138 139 /** 140 * Tells whether the provided java installation supports a given option or 141 * not. 142 * 143 * @param javaHome 144 * the java installation path. 145 * @param option 146 * the java option that we want to check. 147 * @param installPath 148 * the install path of the server. 149 * @return <CODE>true</CODE> if the provided java installation supports a 150 * given option and <CODE>false</CODE> otherwise. 151 */ 152 public static boolean supportsOption(String option, String javaHome, String installPath) 153 { 154 boolean supported = false; 155 logger.info(LocalizableMessage.raw("Checking if options " + option + " are supported with java home: " + javaHome)); 156 try 157 { 158 List<String> args = new ArrayList<>(); 159 args.add(getScript(installPath)); 160 161 ProcessBuilder pb = new ProcessBuilder(args); 162 Map<String, String> env = pb.environment(); 163 env.put(SetupUtils.OPENDJ_JAVA_HOME, javaHome); 164 env.put("OPENDJ_JAVA_ARGS", option); 165 env.put("SCRIPT_UTIL_CMD", "set-full-environment-and-test-java"); 166 env.remove("OPENDJ_JAVA_BIN"); 167 // In windows by default the scripts ask the user to click on enter when 168 // they fail. Set this environment variable to avoid it. 169 if (isWindows()) 170 { 171 env.put("DO_NOT_PAUSE", "true"); 172 } 173 final Process process = pb.start(); 174 logger.info(LocalizableMessage.raw("launching " + args + " with env: " + env)); 175 InputStream is = process.getInputStream(); 176 BufferedReader reader = new BufferedReader(new InputStreamReader(is)); 177 String line; 178 boolean errorDetected = false; 179 while (null != (line = reader.readLine())) 180 { 181 logger.info(LocalizableMessage.raw("The output: " + line)); 182 if (line.contains("ERROR: The detected Java version")) 183 { 184 if (isWindows()) 185 { 186 // If we are running windows, the process get blocked waiting for 187 // user input. Just wait for a certain time to print the output 188 // in the logger and then kill the process. 189 Thread t = new Thread(new Runnable() 190 { 191 @Override 192 public void run() 193 { 194 try 195 { 196 Thread.sleep(3000); 197 // To see if the process is over, call the exitValue method. 198 // If it is not over, a IllegalThreadStateException. 199 process.exitValue(); 200 } 201 catch (Throwable t) 202 { 203 process.destroy(); 204 } 205 } 206 }); 207 t.start(); 208 } 209 errorDetected = true; 210 } 211 } 212 process.waitFor(); 213 int returnCode = process.exitValue(); 214 logger.info(LocalizableMessage.raw("returnCode: " + returnCode)); 215 supported = returnCode == 0 && !errorDetected; 216 logger.info(LocalizableMessage.raw("supported: " + supported)); 217 } 218 catch (Throwable t) 219 { 220 logger.warn(LocalizableMessage.raw("Error testing option " + option + " on " + javaHome, t)); 221 } 222 return supported; 223 } 224 225 private static String getScript(String installPath) 226 { 227 String libPath = Utils.getPath(installPath, Installation.LIBRARIES_PATH_RELATIVE); 228 String scriptUtilFileUnix = isWindows() ? SCRIPT_UTIL_FILE_WINDOWS : SCRIPT_UTIL_FILE_UNIX; 229 return Utils.getScriptPath(Utils.getPath(libPath, scriptUtilFileUnix)); 230 } 231 232 /** 233 * Creates a new file attempting to create the parent directories if necessary. 234 * 235 * @param f 236 * File to create 237 * @return boolean indicating whether the file was created; false otherwise 238 * @throws IOException 239 * if something goes wrong 240 */ 241 static boolean createFile(File f) throws IOException 242 { 243 if (f != null) 244 { 245 File parent = f.getParentFile(); 246 if (!parent.exists()) 247 { 248 parent.mkdirs(); 249 } 250 return f.createNewFile(); 251 } 252 return false; 253 } 254 255 /** 256 * Returns the absolute path for the given parentPath and relativePath. 257 * 258 * @param parentPath 259 * the parent path. 260 * @param relativePath 261 * the relative path. 262 * @return the absolute path for the given parentPath and relativePath. 263 */ 264 public static String getPath(String parentPath, String relativePath) 265 { 266 return getPath(new File(new File(parentPath), relativePath)); 267 } 268 269 /** 270 * Returns the String that can be used to launch an script using Runtime.exec. 271 * This method is required because in Windows the script that contain a "=" in 272 * their path must be quoted. 273 * 274 * @param script 275 * the script name 276 * @return the absolute path for the given parentPath and relativePath. 277 */ 278 public static String getScriptPath(String script) 279 { 280 return SetupUtils.getScriptPath(script); 281 } 282 283 /** 284 * Returns the absolute path for the given file. It tries to get the canonical 285 * file path. If it fails it returns the string representation. 286 * 287 * @param f 288 * File to get the path 289 * @return the absolute path for the given file. 290 */ 291 public static String getPath(File f) 292 { 293 if (f != null) 294 { 295 try 296 { 297 /* 298 * Do a best effort to avoid having a relative representation (for 299 * instance to avoid having ../../../). 300 */ 301 f = f.getCanonicalFile(); 302 } 303 catch (IOException ioe) 304 { 305 /* 306 * This is a best effort to get the best possible representation of the 307 * file: reporting the error is not necessary. 308 */ 309 } 310 return f.toString(); 311 } 312 return null; 313 } 314 315 /** 316 * Returns <CODE>true</CODE> if the first provided path is under the second 317 * path in the file system. 318 * 319 * @param descendant 320 * the descendant candidate path. 321 * @param path 322 * the path. 323 * @return <CODE>true</CODE> if the first provided path is under the second 324 * path in the file system; <code>false</code> otherwise or if either 325 * of the files are null 326 */ 327 public static boolean isDescendant(File descendant, File path) 328 { 329 boolean isDescendant = false; 330 if (descendant != null && path != null) 331 { 332 File parent = descendant.getParentFile(); 333 while (parent != null && !isDescendant) 334 { 335 isDescendant = path.equals(parent); 336 if (!isDescendant) 337 { 338 parent = parent.getParentFile(); 339 } 340 } 341 } 342 return isDescendant; 343 } 344 345 /** 346 * Returns <CODE>true</CODE> if the the provided path is a file and exists and 347 * <CODE>false</CODE> otherwise. 348 * 349 * @param path 350 * the path that we are analyzing. 351 * @return <CODE>true</CODE> if the the provided path is a file and exists and 352 * <CODE>false</CODE> otherwise. 353 */ 354 public static boolean fileExists(String path) 355 { 356 return new File(path).isFile(); 357 } 358 359 /** 360 * Returns <CODE>true</CODE> if the the provided path is a directory, exists 361 * and is not empty <CODE>false</CODE> otherwise. 362 * 363 * @param path 364 * the path that we are analyzing. 365 * @return <CODE>true</CODE> if the the provided path is a directory, exists 366 * and is not empty <CODE>false</CODE> otherwise. 367 */ 368 public static boolean directoryExistsAndIsNotEmpty(String path) 369 { 370 final File f = new File(path); 371 if (f.isDirectory()) 372 { 373 final String[] ch = f.list(); 374 return ch != null && ch.length > 0; 375 } 376 return false; 377 } 378 379 /** 380 * Returns <CODE>true</CODE> if the the provided string is a configuration DN 381 * and <CODE>false</CODE> otherwise. 382 * 383 * @param dn 384 * the String we are analyzing. 385 * @return <CODE>true</CODE> if the the provided string is a configuration DN 386 * and <CODE>false</CODE> otherwise. 387 */ 388 public static boolean isConfigurationDn(String dn) 389 { 390 boolean isConfigurationDn = false; 391 String[] configDns = { "cn=config", Constants.SCHEMA_DN }; 392 for (int i = 0; i < configDns.length && !isConfigurationDn; i++) 393 { 394 isConfigurationDn = areDnsEqual(dn, configDns[i]); 395 } 396 return isConfigurationDn; 397 } 398 399 /** 400 * Returns <CODE>true</CODE> if the the provided strings represent the same DN 401 * and <CODE>false</CODE> otherwise. 402 * 403 * @param dn1 404 * the first dn to compare. 405 * @param dn2 406 * the second dn to compare. 407 * @return <CODE>true</CODE> if the the provided strings represent the same DN 408 * and <CODE>false</CODE> otherwise. 409 */ 410 public static boolean areDnsEqual(String dn1, String dn2) 411 { 412 try 413 { 414 LdapName name1 = new LdapName(dn1); 415 LdapName name2 = new LdapName(dn2); 416 return name1.equals(name2); 417 } 418 catch (Exception ex) 419 { 420 return false; 421 } 422 } 423 424 /** 425 * Creates the parent directory if it does not already exist. 426 * 427 * @param f 428 * File for which parentage will be insured 429 * @return boolean indicating whether the input <code>f</code> has a 430 * parent after this method is invoked. 431 */ 432 static boolean ensureParentsExist(File f) 433 { 434 final File parent = f.getParentFile(); 435 return parent.exists() || parent.mkdirs(); 436 } 437 438 /** 439 * Creates the a directory in the provided path. 440 * 441 * @param f 442 * the path. 443 * @return <CODE>true</CODE> if the path was created or already existed (and 444 * was a directory) and <CODE>false</CODE> otherwise. 445 * @throws IOException 446 * if something goes wrong. 447 */ 448 static boolean createDirectory(File f) throws IOException 449 { 450 if (f.exists()) 451 { 452 return f.isDirectory(); 453 } 454 return f.mkdirs(); 455 } 456 457 /** 458 * Creates a file on the specified path with the contents of the provided 459 * stream. 460 * 461 * @param path 462 * the path where the file will be created. 463 * @param is 464 * the InputStream with the contents of the file. 465 * @throws IOException 466 * if something goes wrong. 467 */ 468 static void createFile(File path, InputStream is) throws IOException 469 { 470 try (FileOutputStream out = new FileOutputStream(path); 471 BufferedOutputStream dest = new BufferedOutputStream(out)) 472 { 473 byte[] data = new byte[BUFFER_SIZE]; 474 int count; 475 while ((count = is.read(data, 0, BUFFER_SIZE)) != -1) 476 { 477 dest.write(data, 0, count); 478 } 479 } 480 } 481 482 /** 483 * Creates a file on the specified path with the contents of the provided 484 * String. The file is protected, so that 'others' have no access to it. 485 * 486 * @param path 487 * the path where the file will be created. 488 * @param content 489 * the String with the contents of the file. 490 * @throws IOException 491 * if something goes wrong. 492 * @throws InterruptedException 493 * if there is a problem changing the permissions of the file. 494 */ 495 public static void createProtectedFile(String path, String content) throws IOException, InterruptedException 496 { 497 FileWriter file = new FileWriter(path); 498 PrintWriter out = new PrintWriter(file); 499 500 out.println(content); 501 502 out.flush(); 503 out.close(); 504 505 if (!isWindows()) 506 { 507 setPermissionsUnix(path, "600"); 508 } 509 } 510 511 /** 512 * This is a helper method that gets a LocalizableMessage representation of 513 * the elements in the Collection of Messages. The LocalizableMessage will 514 * display the different elements separated by the separator String. 515 * 516 * @param col 517 * the collection containing the messages. 518 * @param separator 519 * the separator String to be used. 520 * @return the message representation for the collection; null if 521 * <code>col</code> is null 522 */ 523 public static LocalizableMessage getMessageFromCollection(Collection<LocalizableMessage> col, String separator) 524 { 525 if (col != null) 526 { 527 final LocalizableMessageBuilder mb = new LocalizableMessageBuilder(); 528 for (LocalizableMessage m : col) 529 { 530 mb.append(separator).append(m); 531 } 532 return mb.toMessage(); 533 } 534 return null; 535 } 536 537 /** 538 * Returns the default server location that will be proposed to the user in 539 * the installation. 540 * 541 * @return the default server location that will be proposed to the user in 542 * the installation. 543 */ 544 public static String getDefaultServerLocation() 545 { 546 String userDir = System.getProperty("user.home"); 547 String firstLocation = userDir + File.separator + SHORT_NAME.toLowerCase(Locale.ENGLISH); 548 String serverLocation = firstLocation; 549 int i = 1; 550 while (fileExists(serverLocation) || directoryExistsAndIsNotEmpty(serverLocation)) 551 { 552 serverLocation = firstLocation + "-" + i; 553 i++; 554 } 555 return serverLocation; 556 } 557 558 /** 559 * Gets a localized representation of the provide TopologyCacheException. 560 * 561 * @param te 562 * the exception. 563 * @return a localized representation of the provide TopologyCacheException. 564 */ 565 public static LocalizableMessage getMessage(TopologyCacheException te) 566 { 567 LocalizableMessageBuilder buf = new LocalizableMessageBuilder(); 568 569 String ldapUrl = te.getLdapUrl(); 570 if (ldapUrl != null) 571 { 572 String hostName = ldapUrl.substring(ldapUrl.indexOf("://") + 3); 573 buf.append(INFO_SERVER_ERROR.get(hostName)); 574 buf.append(" "); 575 } 576 if (te.getType() == TopologyCacheException.Type.TIMEOUT) 577 { 578 buf.append(INFO_ERROR_CONNECTING_TIMEOUT.get()); 579 } 580 else if (te.getCause() instanceof NamingException) 581 { 582 buf.append(getThrowableMsg(INFO_ERROR_CONNECTING_TO_LOCAL.get(), te.getCause())); 583 } 584 else 585 { 586 logger.warn(LocalizableMessage.raw("Unexpected error: " + te, te)); 587 // This is unexpected. 588 if (te.getCause() != null) 589 { 590 buf.append(getThrowableMsg(INFO_BUG_MSG.get(), te.getCause())); 591 } 592 else 593 { 594 buf.append(getThrowableMsg(INFO_BUG_MSG.get(), te)); 595 } 596 } 597 return buf.toMessage(); 598 } 599 600 /** 601 * Sets the permissions of the provided paths with the provided permission 602 * String. 603 * 604 * @param paths 605 * the paths to set permissions on. 606 * @param permissions 607 * the UNIX-mode file system permission representation (for example 608 * "644" or "755") 609 * @return the return code of the chmod command. 610 * @throws IOException 611 * if something goes wrong. 612 * @throws InterruptedException 613 * if the Runtime.exec method is interrupted. 614 */ 615 static int setPermissionsUnix(List<String> paths, String permissions) throws IOException, 616 InterruptedException 617 { 618 String[] args = new String[paths.size() + 2]; 619 args[0] = "chmod"; 620 args[1] = permissions; 621 for (int i = 2; i < args.length; i++) 622 { 623 args[i] = paths.get(i - 2); 624 } 625 Process p = Runtime.getRuntime().exec(args); 626 return p.waitFor(); 627 } 628 629 /** 630 * Sets the permissions of the provided paths with the provided permission 631 * String. 632 * 633 * @param path 634 * to set permissions on. 635 * @param permissions 636 * the UNIX-mode file system permission representation (for example 637 * "644" or "755") 638 * @return the return code of the chmod command. 639 * @throws IOException 640 * if something goes wrong. 641 * @throws InterruptedException 642 * if the Runtime.exec method is interrupted. 643 */ 644 static int setPermissionsUnix(String path, String permissions) throws IOException, InterruptedException 645 { 646 String[] args = new String[] { "chmod", permissions, path }; 647 Process p = Runtime.getRuntime().exec(args); 648 return p.waitFor(); 649 } 650 651 /** 652 * Returns <CODE>true</CODE> if this is executed from command line and 653 * <CODE>false</CODE> otherwise. 654 * 655 * @return <CODE>true</CODE> if this is executed from command line and 656 * <CODE>false</CODE> otherwise. 657 */ 658 public static boolean isCli() 659 { 660 return "true".equals(System.getProperty(Constants.CLI_JAVA_PROPERTY)); 661 } 662 663 /** 664 * Creates an LDAP+StartTLS connection and returns the corresponding 665 * LdapContext. This method first creates an LdapContext with anonymous bind. 666 * Then it requests a StartTlsRequest extended operation. The StartTlsResponse 667 * is setup with the specified hostname verifier. Negotiation is done using a 668 * TrustSocketFactory so that the specified TrustManager gets called during 669 * the SSL handshake. If trust manager is null, certificates are not checked 670 * during SSL handshake. 671 * 672 * @param ldapsURL 673 * the target *LDAPS* URL. 674 * @param dn 675 * passed as Context.SECURITY_PRINCIPAL if not null. 676 * @param pwd 677 * passed as Context.SECURITY_CREDENTIALS if not null. 678 * @param timeout 679 * passed as com.sun.jndi.ldap.connect.timeout if > 0. 680 * @param env 681 * null or additional environment properties. 682 * @param trustManager 683 * null or the trust manager to be invoked during SSL. negociation. 684 * @param verifier 685 * null or the hostname verifier to be setup in the StartTlsResponse. 686 * @return the established connection with the given parameters. 687 * @throws NamingException 688 * the exception thrown when instantiating InitialLdapContext. 689 * @see javax.naming.Context 690 * @see javax.naming.ldap.InitialLdapContext 691 * @see javax.naming.ldap.StartTlsRequest 692 * @see javax.naming.ldap.StartTlsResponse 693 * @see org.opends.admin.ads.util.TrustedSocketFactory 694 */ 695 696 public static InitialLdapContext createStartTLSContext(String ldapsURL, String dn, String pwd, int timeout, 697 Hashtable<String, String> env, TrustManager trustManager, HostnameVerifier verifier) throws NamingException 698 { 699 return ConnectionUtils.createStartTLSContext(ldapsURL, dn, pwd, timeout, env, trustManager, null, verifier); 700 } 701 702 /** 703 * Returns a message object for the given NamingException. The code assume 704 * that we are trying to connect to the local server. 705 * 706 * @param ne 707 * the NamingException. 708 * @return a message object for the given NamingException. 709 */ 710 public static LocalizableMessage getMessageForException(NamingException ne) 711 { 712 final String detailedException = ne.toString(true); 713 if (isCertificateException(ne)) 714 { 715 return INFO_ERROR_READING_CONFIG_LDAP_CERTIFICATE.get(detailedException); 716 } 717 else if (ne instanceof AuthenticationException) 718 { 719 return ERR_CANNOT_CONNECT_TO_LOCAL_AUTHENTICATION.get(detailedException); 720 } 721 else if (ne instanceof NoPermissionException) 722 { 723 return ERR_CANNOT_CONNECT_TO_LOCAL_PERMISSIONS.get(detailedException); 724 } 725 else if (ne instanceof NamingSecurityException) 726 { 727 return ERR_CANNOT_CONNECT_TO_LOCAL_PERMISSIONS.get(detailedException); 728 } 729 else if (ne instanceof CommunicationException) 730 { 731 return ERR_CANNOT_CONNECT_TO_LOCAL_COMMUNICATION.get(detailedException); 732 } 733 else 734 { 735 return ERR_CANNOT_CONNECT_TO_LOCAL_GENERIC.get(detailedException); 736 } 737 } 738 739 /** 740 * Returns the path of the installation of the directory server. Note that 741 * this method assumes that this code is being run locally. 742 * 743 * @return the path of the installation of the directory server. 744 */ 745 public static String getInstallPathFromClasspath() 746 { 747 String installPath = System.getProperty("org.opends.quicksetup.Root"); 748 if (installPath != null) 749 { 750 return installPath; 751 } 752 753 /* Get the install path from the Class Path */ 754 String sep = System.getProperty("path.separator"); 755 String[] classPaths = System.getProperty("java.class.path").split(sep); 756 String path = getInstallPath(classPaths); 757 if (path != null) 758 { 759 File f = new File(path).getAbsoluteFile(); 760 File librariesDir = f.getParentFile(); 761 762 /* 763 * Do a best effort to avoid having a relative representation (for 764 * instance to avoid having ../../../). 765 */ 766 try 767 { 768 installPath = librariesDir.getParentFile().getCanonicalPath(); 769 } 770 catch (IOException ioe) 771 { 772 // Best effort 773 installPath = librariesDir.getParent(); 774 } 775 } 776 return installPath; 777 } 778 779 private static String getInstallPath(final String[] classPaths) 780 { 781 for (String classPath : classPaths) 782 { 783 final String normPath = classPath.replace(File.separatorChar, '/'); 784 if (normPath.endsWith(OPENDJ_BOOTSTRAP_CLIENT_JAR_RELATIVE_PATH) 785 || normPath.endsWith(OPENDJ_BOOTSTRAP_JAR_RELATIVE_PATH)) 786 { 787 return classPath; 788 } 789 } 790 return null; 791 } 792 793 /** 794 * Returns the path of the installation of the directory server. Note that 795 * this method assumes that this code is being run locally. 796 * 797 * @param installPath 798 * The installation path 799 * @return the path of the installation of the directory server. 800 */ 801 public static String getInstancePathFromInstallPath(String installPath) 802 { 803 String instancePathFileName = Installation.INSTANCE_LOCATION_PATH; 804 File _svcScriptPathName = new File( 805 installPath + File.separator + Installation.LIBRARIES_PATH_RELATIVE + File.separator + "_svc-opendj.sh"); 806 807 // look for /etc/opt/opendj/instance.loc 808 File f = new File(instancePathFileName); 809 if (!_svcScriptPathName.exists() || !f.exists()) 810 { 811 // look for <installPath>/instance.loc 812 instancePathFileName = installPath + File.separator + Installation.INSTANCE_LOCATION_PATH_RELATIVE; 813 f = new File(instancePathFileName); 814 if (!f.exists()) 815 { 816 return installPath; 817 } 818 } 819 820 // Read the first line and close the file. 821 try (BufferedReader reader = new BufferedReader(new FileReader(instancePathFileName))) 822 { 823 String line = reader.readLine(); 824 File instanceLoc = new File(line.trim()); 825 return getCanonicalPath(instanceLoc.isAbsolute() 826 ? instanceLoc 827 : new File(installPath + File.separator + instanceLoc.getPath())); 828 } 829 catch (Exception e) 830 { 831 return installPath; 832 } 833 } 834 835 /** 836 * Returns the max size in character of a line to be displayed in the command 837 * line. 838 * 839 * @return the max size in character of a line to be displayed in the command 840 * line. 841 */ 842 public static int getCommandLineMaxLineWidth() 843 { 844 return MAX_LINE_WIDTH; 845 } 846 847 /** 848 * Puts Swing menus in the Mac OS menu bar, if using the Aqua look and feel, 849 * and sets the application name that is displayed in the application menu and 850 * in the dock. 851 * 852 * @param appName 853 * application name to display in the menu bar and the dock. 854 */ 855 public static void setMacOSXMenuBar(LocalizableMessage appName) 856 { 857 System.setProperty("apple.laf.useScreenMenuBar", "true"); 858 System.setProperty("com.apple.mrj.application.apple.menu.about.name", String.valueOf(appName)); 859 } 860 861 /** 862 * Returns the file system permissions for a file. 863 * 864 * @param file 865 * the file for which we want the file permissions. 866 * @return the file system permissions for the file. 867 */ 868 static String getFileSystemPermissions(File file) 869 { 870 String name = file.getName(); 871 if (file.getParent().endsWith(File.separator + Installation.WINDOWS_BINARIES_PATH_RELATIVE) 872 || file.getParent().endsWith(File.separator + Installation.UNIX_BINARIES_PATH_RELATIVE)) 873 { 874 return name.endsWith(".bat") ? "644" : "755"; 875 } 876 else if (name.endsWith(".sh") 877 || name.endsWith(Installation.UNIX_SETUP_FILE_NAME) 878 || name.endsWith(Installation.UNIX_UNINSTALL_FILE_NAME) 879 || name.endsWith(Installation.UNIX_UPGRADE_FILE_NAME) 880 || name.endsWith(Installation.MAC_JAVA_APP_STUB_NAME)) 881 { 882 return "755"; 883 } 884 else 885 { 886 return "644"; 887 } 888 } 889 890 /** 891 * Inserts HTML break tags into <code>d</code> breaking it up so that ideally 892 * no line is longer than <code>maxll</code> assuming no single word is longer 893 * then <code>maxll</code>. If the string already contains HTML tags that 894 * cause a line break (e.g break and closing list item tags) they are 895 * respected by this method when calculating where to place new breaks to 896 * control the maximum line length. 897 * 898 * @param cs 899 * String to break 900 * @param maxll 901 * int maximum line length 902 * @return String representing <code>d</code> with HTML break tags inserted 903 */ 904 public static String breakHtmlString(CharSequence cs, int maxll) 905 { 906 if (cs == null) 907 { 908 return null; 909 } 910 911 String d = cs.toString(); 912 int len = d.length(); 913 if (len <= 0 || len <= maxll) 914 { 915 return d; 916 } 917 918 // First see if there are any tags that would cause a natural break in the line. 919 // If so start line break point evaluation from that point. 920 for (String tag : Constants.BREAKING_TAGS) 921 { 922 int p = d.lastIndexOf(tag, maxll); 923 if (p > 0 && p < len) 924 { 925 return d.substring(0, p + tag.length()) + breakHtmlString(d.substring(p + tag.length()), maxll); 926 } 927 } 928 929 // Now look for spaces in which to insert a break. 930 // First see if there are any spaces counting backward from the max line length. 931 // If there aren't any, then use the first space encountered after the max line length. 932 int p = d.lastIndexOf(' ', maxll); 933 if (p <= 0) 934 { 935 p = d.indexOf(' ', maxll); 936 } 937 if (0 < p && p < len) 938 { 939 return d.substring(0, p) + Constants.HTML_LINE_BREAK + breakHtmlString(d.substring(p + 1), maxll); 940 } 941 return d; 942 } 943 944 /** 945 * Tests a text string to see if it contains HTML. 946 * 947 * @param text 948 * String to test 949 * @return true if the string contains HTML 950 */ 951 static boolean containsHtml(String text) 952 { 953 return text != null && text.indexOf('<') != -1 && text.indexOf('>') != -1; 954 } 955 956 private static EmptyPrintStream emptyStream = new EmptyPrintStream(); 957 958 /** 959 * Returns a printstream that does not write anything to standard output. 960 * 961 * @return a printstream that does not write anything to standard output. 962 */ 963 public static EmptyPrintStream getEmptyPrintStream() 964 { 965 if (emptyStream == null) 966 { 967 emptyStream = new EmptyPrintStream(); 968 } 969 return emptyStream; 970 } 971 972 /** 973 * Returns the current time of a server in milliseconds. 974 * 975 * @param ctx 976 * the connection to the server. 977 * @return the current time of a server in milliseconds. 978 */ 979 public static long getServerClock(InitialLdapContext ctx) 980 { 981 long time = -1; 982 SearchControls ctls = new SearchControls(); 983 ctls.setSearchScope(SearchControls.OBJECT_SCOPE); 984 ctls.setReturningAttributes(new String[] { "currentTime" }); 985 String filter = "(objectclass=*)"; 986 987 try 988 { 989 LdapName jndiName = new LdapName("cn=monitor"); 990 NamingEnumeration<?> listeners = ctx.search(jndiName, filter, ctls); 991 992 try 993 { 994 while (listeners.hasMore()) 995 { 996 SearchResult sr = (SearchResult) listeners.next(); 997 998 String v = getFirstValue(sr, "currentTime"); 999 1000 TimeZone utcTimeZone = TimeZone.getTimeZone("UTC"); 1001 1002 SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMddHHmmss'Z'"); 1003 formatter.setTimeZone(utcTimeZone); 1004 1005 time = formatter.parse(v).getTime(); 1006 } 1007 } 1008 finally 1009 { 1010 listeners.close(); 1011 } 1012 } 1013 catch (Throwable t) 1014 { 1015 logger.warn(LocalizableMessage.raw("Error retrieving server current time: " + t, t)); 1016 } 1017 return time; 1018 } 1019 1020 /** 1021 * Checks that the java version we are running is compatible with OpenDS. 1022 * 1023 * @throws IncompatibleVersionException 1024 * if the java version we are running is not compatible with OpenDS. 1025 */ 1026 public static void checkJavaVersion() throws IncompatibleVersionException 1027 { 1028 try 1029 { 1030 com.forgerock.opendj.cli.Utils.checkJavaVersion(); 1031 } 1032 catch (ClientException e) 1033 { 1034 throw new IncompatibleVersionException(e.getMessageObject(), e); 1035 } 1036 } 1037 1038 /** 1039 * Basic method to know if the host is local or not. This is only used to know 1040 * if we can perform a port check or not. 1041 * 1042 * @param host 1043 * the host to analyze. 1044 * @return <CODE>true</CODE> if it is the local host and <CODE>false</CODE> 1045 * otherwise. 1046 */ 1047 public static boolean isLocalHost(String host) 1048 { 1049 if ("localhost".equalsIgnoreCase(host)) 1050 { 1051 return true; 1052 } 1053 1054 try 1055 { 1056 InetAddress localAddress = InetAddress.getLocalHost(); 1057 InetAddress[] addresses = InetAddress.getAllByName(host); 1058 for (InetAddress address : addresses) 1059 { 1060 if (localAddress.equals(address)) 1061 { 1062 return true; 1063 } 1064 } 1065 } 1066 catch (Throwable t) 1067 { 1068 logger.warn(LocalizableMessage.raw("Failing checking host names: " + t, t)); 1069 } 1070 return false; 1071 } 1072 1073 /** 1074 * Returns the HTML representation of a plain text string which is obtained 1075 * by converting some special characters (like '<') into its equivalent 1076 * escaped HTML representation. 1077 * 1078 * @param rawString the String from which we want to obtain the HTML 1079 * representation. 1080 * @return the HTML representation of the plain text string. 1081 */ 1082 private static String escapeHtml(String rawString) 1083 { 1084 StringBuilder buffer = new StringBuilder(); 1085 for (int i = 0; i < rawString.length(); i++) 1086 { 1087 escapeChar(buffer, rawString.charAt(i)); 1088 } 1089 return buffer.toString(); 1090 } 1091 1092 private static StringBuilder escapeChar(StringBuilder buffer, char c) 1093 { 1094 switch (c) 1095 { 1096 case '<': 1097 return buffer.append("<"); 1098 case '>': 1099 return buffer.append(">"); 1100 case '&': 1101 return buffer.append("&"); 1102 case '"': 1103 return buffer.append("""); 1104 default: 1105 return buffer.append(c); 1106 } 1107 } 1108 1109 /** 1110 * Returns the HTML representation for a given text. without adding any kind 1111 * of font or style elements. Just escapes the problematic characters 1112 * (like '<') and transform the break lines into '\n' characters. 1113 * 1114 * @param text the source text from which we want to get the HTML 1115 * representation 1116 * @return the HTML representation for the given text. 1117 */ 1118 public static String getHtml(String text) 1119 { 1120 if (text == null) 1121 { 1122 return ""; 1123 } 1124 1125 text = text.replaceAll("\r\n", "\n"); 1126 1127 StringBuilder buffer = new StringBuilder(); 1128 String[] lines = text.split("[\n\r\u0085\u2028\u2029]"); 1129 for (int i = 0; i < lines.length; i++) 1130 { 1131 if (i != 0) 1132 { 1133 buffer.append(Constants.HTML_LINE_BREAK); 1134 } 1135 buffer.append(escapeHtml(lines[i])); 1136 } 1137 return buffer.toString(); 1138 } 1139 1140 /** 1141 * Tries to find a customized object in the customization class. If the 1142 * customization class does not exist or it does not contain the field as the 1143 * specified type of the object, returns the default value. 1144 * 1145 * @param <T> 1146 * the type of the customized object. 1147 * @param fieldName 1148 * the name of the field representing an object in the customization 1149 * class. 1150 * @param defaultValue 1151 * the default value. 1152 * @param valueClass 1153 * the class of the parameterized value. 1154 * @return the customized object. 1155 */ 1156 public static <T> T getCustomizedObject(String fieldName, T defaultValue, Class<T> valueClass) 1157 { 1158 try 1159 { 1160 Class<?> c = Class.forName(Utils.CUSTOMIZATION_CLASS_NAME); 1161 Object obj = c.newInstance(); 1162 1163 return valueClass.cast(c.getField(fieldName).get(obj)); 1164 } 1165 catch (Exception ex) 1166 { 1167 //do nothing. 1168 } 1169 return defaultValue; 1170 } 1171 1172 /** 1173 * Adds word break tags to the provided html string. 1174 * 1175 * @param htmlString 1176 * the string. 1177 * @param from 1178 * the first index to start the spacing from. 1179 * @param spacing 1180 * the minimal spacing between word breaks. 1181 * @return a string containing word breaks. 1182 */ 1183 public static String addWordBreaks(String htmlString, int from, int spacing) 1184 { 1185 StringBuilder sb = new StringBuilder(); 1186 boolean insideTag = false; 1187 int totalAddedChars = 0; 1188 int addedChars = 0; 1189 for (int i = 0; i < htmlString.length(); i++) 1190 { 1191 char c = htmlString.charAt(i); 1192 sb.append(c); 1193 if (c == '<') 1194 { 1195 insideTag = true; 1196 } 1197 else if (c == '>' && insideTag) 1198 { 1199 insideTag = false; 1200 } 1201 if (!insideTag && c != '>') 1202 { 1203 addedChars++; 1204 totalAddedChars++; 1205 } 1206 if (addedChars > spacing && totalAddedChars > from && !insideTag) 1207 { 1208 sb.append("<wbr>"); 1209 addedChars = 0; 1210 } 1211 } 1212 return sb.toString(); 1213 } 1214 1215 /** 1216 * Returns the localized string describing the DataOptions chosen by the user. 1217 * 1218 * @param userInstallData 1219 * the DataOptions of the user. 1220 * @return the localized string describing the DataOptions chosen by the user. 1221 */ 1222 public static String getDataDisplayString(final UserData userInstallData) 1223 { 1224 LocalizableMessage msg; 1225 1226 final DataReplicationOptions repl = userInstallData.getReplicationOptions(); 1227 final SuffixesToReplicateOptions suf = userInstallData.getSuffixesToReplicateOptions(); 1228 1229 boolean createSuffix = repl.getType() == DataReplicationOptions.Type.FIRST_IN_TOPOLOGY 1230 || repl.getType() == DataReplicationOptions.Type.STANDALONE 1231 || suf.getType() == SuffixesToReplicateOptions.Type.NEW_SUFFIX_IN_TOPOLOGY; 1232 1233 if (createSuffix) 1234 { 1235 NewSuffixOptions options = userInstallData.getNewSuffixOptions(); 1236 LocalizableMessage arg2 = toArg2(options); 1237 1238 if (options.getBaseDns().isEmpty()) 1239 { 1240 msg = INFO_REVIEW_CREATE_NO_SUFFIX.get(); 1241 } 1242 else 1243 { 1244 final String backendType = userInstallData.getBackendType().getUserFriendlyName().toString(); 1245 if (options.getBaseDns().size() > 1) 1246 { 1247 msg = INFO_REVIEW_CREATE_SUFFIX.get( 1248 backendType, joinAsString(Constants.LINE_SEPARATOR, options.getBaseDns()), arg2); 1249 } 1250 else 1251 { 1252 msg = INFO_REVIEW_CREATE_SUFFIX.get(backendType, options.getBaseDns().getFirst(), arg2); 1253 } 1254 } 1255 } 1256 else 1257 { 1258 final StringBuilder buf = new StringBuilder(); 1259 for (final SuffixDescriptor suffix : suf.getSuffixes()) 1260 { 1261 if (buf.length() > 0) 1262 { 1263 buf.append(Constants.LINE_SEPARATOR); 1264 } 1265 buf.append(suffix.getDN()); 1266 } 1267 msg = INFO_REVIEW_REPLICATE_SUFFIX.get(buf); 1268 } 1269 1270 return msg.toString(); 1271 } 1272 1273 private static LocalizableMessage toArg2(NewSuffixOptions options) 1274 { 1275 switch (options.getType()) 1276 { 1277 case CREATE_BASE_ENTRY: 1278 return INFO_REVIEW_CREATE_BASE_ENTRY_LABEL.get(options.getBaseDns().getFirst()); 1279 case LEAVE_DATABASE_EMPTY: 1280 return INFO_REVIEW_LEAVE_DATABASE_EMPTY_LABEL.get(); 1281 case IMPORT_FROM_LDIF_FILE: 1282 return INFO_REVIEW_IMPORT_LDIF.get(options.getLDIFPaths().getFirst()); 1283 case IMPORT_AUTOMATICALLY_GENERATED_DATA: 1284 return INFO_REVIEW_IMPORT_AUTOMATICALLY_GENERATED.get(options.getNumberEntries()); 1285 default: 1286 throw new IllegalArgumentException("Unknown type: " + options.getType()); 1287 } 1288 } 1289 1290 /** 1291 * Returns a localized String representation of the provided SecurityOptions 1292 * object. 1293 * 1294 * @param ops 1295 * the SecurityOptions object from which we want to obtain the String 1296 * representation. 1297 * @param html 1298 * whether the resulting String must be in HTML or not. 1299 * @return a localized String representation of the provided SecurityOptions 1300 * object. 1301 */ 1302 public static String getSecurityOptionsString(SecurityOptions ops, boolean html) 1303 { 1304 StringBuilder buf = new StringBuilder(); 1305 1306 if (ops.getCertificateType() == SecurityOptions.CertificateType.NO_CERTIFICATE) 1307 { 1308 buf.append(INFO_NO_SECURITY.get()); 1309 } 1310 else 1311 { 1312 if (ops.getEnableStartTLS()) 1313 { 1314 buf.append(INFO_ENABLE_STARTTLS.get()); 1315 } 1316 if (ops.getEnableSSL()) 1317 { 1318 if (buf.length() > 0) 1319 { 1320 if (html) 1321 { 1322 buf.append(Constants.HTML_LINE_BREAK); 1323 } 1324 else 1325 { 1326 buf.append("\n"); 1327 } 1328 } 1329 buf.append(INFO_ENABLE_SSL.get(ops.getSslPort())); 1330 } 1331 if (html) 1332 { 1333 buf.append(Constants.HTML_LINE_BREAK); 1334 } 1335 else 1336 { 1337 buf.append("\n"); 1338 } 1339 buf.append(toCertMsg(ops)); 1340 } 1341 1342 if (html) 1343 { 1344 return "<html>" + UIFactory.applyFontToHtml(buf.toString(), UIFactory.SECONDARY_FIELD_VALID_FONT); 1345 } 1346 else 1347 { 1348 return buf.toString(); 1349 } 1350 } 1351 1352 private static LocalizableMessage toCertMsg(SecurityOptions ops) 1353 { 1354 switch (ops.getCertificateType()) 1355 { 1356 case SELF_SIGNED_CERTIFICATE: 1357 return INFO_SELF_SIGNED_CERTIFICATE.get(); 1358 case JKS: 1359 return INFO_JKS_CERTIFICATE.get(); 1360 case JCEKS: 1361 return INFO_JCEKS_CERTIFICATE.get(); 1362 case PKCS11: 1363 return INFO_PKCS11_CERTIFICATE.get(); 1364 case PKCS12: 1365 return INFO_PKCS12_CERTIFICATE.get(); 1366 default: 1367 throw new IllegalStateException("Unknown certificate options type: " + ops.getCertificateType()); 1368 } 1369 } 1370 1371 /** 1372 * Returns a String representation of the provided command-line. 1373 * 1374 * @param cmd 1375 * the command-line arguments. 1376 * @param formatter 1377 * the formatted to be used to create the String representation. 1378 * @return a String representation of the provided command-line. 1379 */ 1380 public static String getFormattedEquivalentCommandLine(List<String> cmd, ProgressMessageFormatter formatter) 1381 { 1382 StringBuilder builder = new StringBuilder(); 1383 builder.append(formatter.getFormattedProgress(LocalizableMessage.raw(cmd.get(0)))); 1384 int initialIndex = 1; 1385 StringBuilder sbSeparator = new StringBuilder(); 1386 sbSeparator.append(formatter.getSpace()); 1387 if (!isWindows()) 1388 { 1389 sbSeparator.append("\\"); 1390 sbSeparator.append(formatter.getLineBreak()); 1391 for (int i = 0; i < 10; i++) 1392 { 1393 sbSeparator.append(formatter.getSpace()); 1394 } 1395 } 1396 1397 String lineSeparator = sbSeparator.toString(); 1398 for (int i = initialIndex; i < cmd.size(); i++) 1399 { 1400 String s = cmd.get(i); 1401 if (s.startsWith("-")) 1402 { 1403 builder.append(lineSeparator); 1404 builder.append(formatter.getFormattedProgress(LocalizableMessage.raw(s))); 1405 } 1406 else 1407 { 1408 builder.append(formatter.getSpace()); 1409 builder.append(formatter.getFormattedProgress(LocalizableMessage.raw(escapeCommandLineValue(s)))); 1410 } 1411 } 1412 return builder.toString(); 1413 } 1414 1415 /** 1416 * This method simply takes a value and tries to transform it (with escape or 1417 * '"') characters so that it can be used in a command line. 1418 * 1419 * @param value 1420 * the String to be treated. 1421 * @return the transformed value. 1422 */ 1423 public static String escapeCommandLineValue(String value) 1424 { 1425 StringBuilder b = new StringBuilder(); 1426 if (isUnix()) 1427 { 1428 for (int i = 0; i < value.length(); i++) 1429 { 1430 char c = value.charAt(i); 1431 boolean charToEscapeFound = false; 1432 for (int j = 0; j < CHARS_TO_ESCAPE.length && !charToEscapeFound; j++) 1433 { 1434 charToEscapeFound = c == CHARS_TO_ESCAPE[j]; 1435 } 1436 if (charToEscapeFound) 1437 { 1438 b.append('\\'); 1439 } 1440 b.append(c); 1441 } 1442 } 1443 else 1444 { 1445 b.append('"').append(value).append('"'); 1446 } 1447 1448 return b.toString(); 1449 } 1450 1451 /** 1452 * Returns the equivalent setup CLI command-line. Note that this command-line 1453 * does not cover all the replication part of the GUI install. 1454 * 1455 * @param userData 1456 * the user data. 1457 * @return the equivalent setup command-line. 1458 */ 1459 public static List<String> getSetupEquivalentCommandLine(final UserData userData) 1460 { 1461 List<String> cmdLine = new ArrayList<>(); 1462 cmdLine.add(getInstallDir() + getSetupFileName()); 1463 cmdLine.add("--cli"); 1464 1465 final ManagedObjectDefinition<? extends BackendCfgClient, ? extends BackendCfg> backendType = 1466 userData.getBackendType(); 1467 if (backendType != null) 1468 { 1469 cmdLine.add("--" + ArgumentConstants.OPTION_LONG_BACKEND_TYPE); 1470 cmdLine.add(BackendTypeHelper.filterSchemaBackendName(backendType.getName())); 1471 } 1472 1473 for (final String baseDN : getBaseDNs(userData)) 1474 { 1475 cmdLine.add("--baseDN"); 1476 cmdLine.add(baseDN); 1477 } 1478 1479 switch (userData.getNewSuffixOptions().getType()) 1480 { 1481 case CREATE_BASE_ENTRY: 1482 cmdLine.add("--addBaseEntry"); 1483 break; 1484 1485 case IMPORT_AUTOMATICALLY_GENERATED_DATA: 1486 cmdLine.add("--sampleData"); 1487 cmdLine.add(Integer.toString(userData.getNewSuffixOptions().getNumberEntries())); 1488 break; 1489 1490 case IMPORT_FROM_LDIF_FILE: 1491 for (final String ldifFile : userData.getNewSuffixOptions().getLDIFPaths()) 1492 { 1493 cmdLine.add("--ldifFile"); 1494 cmdLine.add(ldifFile); 1495 } 1496 1497 final String rejectFile = userData.getNewSuffixOptions().getRejectedFile(); 1498 if (rejectFile != null) 1499 { 1500 cmdLine.add("--rejectFile"); 1501 cmdLine.add(rejectFile); 1502 } 1503 1504 final String skipFile = userData.getNewSuffixOptions().getSkippedFile(); 1505 if (skipFile != null) 1506 { 1507 cmdLine.add("--skipFile"); 1508 cmdLine.add(skipFile); 1509 } 1510 break; 1511 1512 default: 1513 break; 1514 } 1515 1516 cmdLine.add("--ldapPort"); 1517 cmdLine.add(Integer.toString(userData.getServerPort())); 1518 1519 cmdLine.add("--adminConnectorPort"); 1520 cmdLine.add(Integer.toString(userData.getAdminConnectorPort())); 1521 1522 if (userData.getServerJMXPort() != -1) 1523 { 1524 cmdLine.add("--jmxPort"); 1525 cmdLine.add(Integer.toString(userData.getServerJMXPort())); 1526 } 1527 1528 cmdLine.add("--rootUserDN"); 1529 cmdLine.add(userData.getDirectoryManagerDn()); 1530 1531 cmdLine.add("--rootUserPassword"); 1532 cmdLine.add(OBFUSCATED_VALUE); 1533 1534 if (isWindows() && userData.getEnableWindowsService()) 1535 { 1536 cmdLine.add("--enableWindowsService"); 1537 } 1538 1539 if (userData.getReplicationOptions().getType() == DataReplicationOptions.Type.STANDALONE 1540 && !userData.getStartServer()) 1541 { 1542 cmdLine.add("--doNotStart"); 1543 } 1544 1545 if (userData.getSecurityOptions().getEnableStartTLS()) 1546 { 1547 cmdLine.add("--enableStartTLS"); 1548 } 1549 1550 if (userData.getSecurityOptions().getEnableSSL()) 1551 { 1552 cmdLine.add("--ldapsPort"); 1553 cmdLine.add(Integer.toString(userData.getSecurityOptions().getSslPort())); 1554 } 1555 1556 cmdLine.addAll(getSecurityOptionSetupEquivalentCmdLine(userData)); 1557 cmdLine.add("--no-prompt"); 1558 cmdLine.add("--noPropertiesFile"); 1559 1560 return cmdLine; 1561 } 1562 1563 private static List<String> getSecurityOptionSetupEquivalentCmdLine(final UserData userData) 1564 { 1565 final List<String> cmdLine = new ArrayList<>(); 1566 1567 switch (userData.getSecurityOptions().getCertificateType()) 1568 { 1569 case SELF_SIGNED_CERTIFICATE: 1570 cmdLine.add("--generateSelfSignedCertificate"); 1571 cmdLine.add("--hostName"); 1572 cmdLine.add(userData.getHostName()); 1573 break; 1574 1575 case JKS: 1576 cmdLine.add("--useJavaKeystore"); 1577 cmdLine.add(userData.getSecurityOptions().getKeystorePath()); 1578 addKeyStoreAndCert(userData.getSecurityOptions(), cmdLine); 1579 break; 1580 1581 case JCEKS: 1582 cmdLine.add("--useJCEKS"); 1583 cmdLine.add(userData.getSecurityOptions().getKeystorePath()); 1584 1585 addKeyStoreAndCert(userData.getSecurityOptions(), cmdLine); 1586 break; 1587 1588 case PKCS12: 1589 cmdLine.add("--usePkcs12keyStore"); 1590 cmdLine.add(userData.getSecurityOptions().getKeystorePath()); 1591 1592 addKeyStoreAndCert(userData.getSecurityOptions(), cmdLine); 1593 break; 1594 1595 case PKCS11: 1596 cmdLine.add("--usePkcs11Keystore"); 1597 1598 addKeyStoreAndCert(userData.getSecurityOptions(), cmdLine); 1599 break; 1600 1601 default: 1602 break; 1603 } 1604 1605 return cmdLine; 1606 } 1607 1608 private static void addKeyStoreAndCert(final SecurityOptions securityOptions, final List<String> cmdLine) 1609 { 1610 if (securityOptions.getKeystorePassword() != null) 1611 { 1612 cmdLine.add("--keyStorePassword"); 1613 cmdLine.add(OBFUSCATED_VALUE); 1614 } 1615 1616 for(String alias : securityOptions.getAliasesToUse()) 1617 { 1618 cmdLine.add("--certNickname"); 1619 cmdLine.add(alias); 1620 } 1621 } 1622 1623 /** 1624 * Returns the list of equivalent command-lines that must be executed to 1625 * enable or initialize replication as the setup does. 1626 * 1627 * @param subcommand 1628 * either {@code "enable"} or {@code "initialize"} 1629 * @param userData 1630 * the user data. 1631 * @return the list of equivalent command-lines that must be executed to 1632 * enable or initialize replication as the setup does. 1633 */ 1634 public static List<List<String>> getDsReplicationEquivalentCommandLines(String subcommand, UserData userData) 1635 { 1636 final List<List<String>> cmdLines = new ArrayList<>(); 1637 final Map<ServerDescriptor, Set<String>> hmServerBaseDNs = getServerDescriptorBaseDNMap(userData); 1638 for (ServerDescriptor server : hmServerBaseDNs.keySet()) 1639 { 1640 cmdLines.add(getDsReplicationEquivalentCommandLine(subcommand, userData, hmServerBaseDNs.get(server), server)); 1641 } 1642 return cmdLines; 1643 } 1644 1645 private static void addEnableCommandOptions(UserData userData, ServerDescriptor server, List<String> cmdLine) 1646 { 1647 DataReplicationOptions replOptions = userData.getReplicationOptions(); 1648 cmdLine.add("--host1"); 1649 cmdLine.add(server.getHostName()); 1650 cmdLine.add("--port1"); 1651 cmdLine.add(String.valueOf(server.getEnabledAdministrationPorts().get(0))); 1652 1653 AuthenticationData authData = userData.getReplicationOptions().getAuthenticationData(); 1654 if (!Utils.areDnsEqual(authData.getDn(), ADSContext.getAdministratorDN(userData.getGlobalAdministratorUID()))) 1655 { 1656 cmdLine.add("--bindDN1"); 1657 cmdLine.add(authData.getDn()); 1658 cmdLine.add("--bindPassword1"); 1659 cmdLine.add(OBFUSCATED_VALUE); 1660 } 1661 for (ServerDescriptor s : userData.getRemoteWithNoReplicationPort().keySet()) 1662 { 1663 if (s.getAdminConnectorURL().equals(server.getAdminConnectorURL())) 1664 { 1665 AuthenticationData remoteRepl = userData.getRemoteWithNoReplicationPort().get(server); 1666 1667 cmdLine.add("--replicationPort1"); 1668 cmdLine.add(String.valueOf(remoteRepl.getPort())); 1669 if (remoteRepl.useSecureConnection()) 1670 { 1671 cmdLine.add("--secureReplication1"); 1672 } 1673 } 1674 } 1675 cmdLine.add("--host2"); 1676 cmdLine.add(userData.getHostName()); 1677 cmdLine.add("--port2"); 1678 cmdLine.add(String.valueOf(userData.getAdminConnectorPort())); 1679 cmdLine.add("--bindDN2"); 1680 cmdLine.add(userData.getDirectoryManagerDn()); 1681 cmdLine.add("--bindPassword2"); 1682 cmdLine.add(OBFUSCATED_VALUE); 1683 if (replOptions.getReplicationPort() != -1) 1684 { 1685 cmdLine.add("--replicationPort2"); 1686 cmdLine.add(String.valueOf(replOptions.getReplicationPort())); 1687 if (replOptions.useSecureReplication()) 1688 { 1689 cmdLine.add("--secureReplication2"); 1690 } 1691 } 1692 } 1693 1694 /** 1695 * Returns the full path of the command-line for a given script name. 1696 * 1697 * @param scriptBasicName 1698 * the script basic name (with no extension). 1699 * @return the full path of the command-line for a given script name. 1700 */ 1701 private static String getCommandLinePath(String scriptBasicName) 1702 { 1703 String installDir = getInstallDir(); 1704 if (isWindows()) 1705 { 1706 return installDir + WINDOWS_BINARIES_PATH_RELATIVE + File.separatorChar + scriptBasicName + ".bat"; 1707 } 1708 else 1709 { 1710 return installDir + UNIX_BINARIES_PATH_RELATIVE + File.separatorChar + scriptBasicName; 1711 } 1712 } 1713 1714 private static String installDir; 1715 1716 /** 1717 * Returns the installation directory. 1718 * 1719 * @return the installation directory. 1720 */ 1721 private static String getInstallDir() 1722 { 1723 if (installDir == null) 1724 { 1725 File f = org.opends.quicksetup.Installation.getLocal().getRootDirectory(); 1726 installDir = getCanonicalPath(f); 1727 if (installDir.lastIndexOf(File.separatorChar) != installDir.length() - 1) 1728 { 1729 installDir += File.separatorChar; 1730 } 1731 } 1732 return installDir; 1733 } 1734 1735 private static String getCanonicalPath(File f) 1736 { 1737 try 1738 { 1739 return f.getCanonicalPath(); 1740 } 1741 catch (IOException t) 1742 { 1743 return f.getAbsolutePath(); 1744 } 1745 } 1746 1747 private static List<String> getDsReplicationEquivalentCommandLine(String subcommand, UserData userData, 1748 Set<String> baseDNs, ServerDescriptor server) 1749 { 1750 List<String> cmdLine = new ArrayList<>(); 1751 String cmdName = getCommandLinePath("dsreplication"); 1752 cmdLine.add(cmdName); 1753 cmdLine.add(subcommand); 1754 1755 if ("enable".equals(subcommand)) 1756 { 1757 addEnableCommandOptions(userData, server, cmdLine); 1758 } 1759 else if ("initialize".equals(subcommand)) 1760 { 1761 addInitializeCommandOptions(userData, server, cmdLine); 1762 } 1763 else 1764 { 1765 throw new IllegalArgumentException("Code is not implemented for subcommand " + subcommand); 1766 } 1767 1768 addCommonOptions(userData, baseDNs, cmdLine); 1769 return cmdLine; 1770 } 1771 1772 private static void addInitializeCommandOptions(UserData userData, ServerDescriptor server, List<String> cmdLine) 1773 { 1774 cmdLine.add("--hostSource"); 1775 cmdLine.add(server.getHostName()); 1776 cmdLine.add("--portSource"); 1777 cmdLine.add(String.valueOf(server.getEnabledAdministrationPorts().get(0))); 1778 1779 cmdLine.add("--hostDestination"); 1780 cmdLine.add(userData.getHostName()); 1781 cmdLine.add("--portDestination"); 1782 cmdLine.add(String.valueOf(userData.getAdminConnectorPort())); 1783 } 1784 1785 private static void addCommonOptions(UserData userData, Set<String> baseDNs, List<String> cmdLine) 1786 { 1787 for (String baseDN : baseDNs) 1788 { 1789 cmdLine.add("--baseDN"); 1790 cmdLine.add(baseDN); 1791 } 1792 1793 cmdLine.add("--adminUID"); 1794 cmdLine.add(userData.getGlobalAdministratorUID()); 1795 cmdLine.add("--adminPassword"); 1796 cmdLine.add(OBFUSCATED_VALUE); 1797 1798 cmdLine.add("--trustAll"); 1799 cmdLine.add("--no-prompt"); 1800 cmdLine.add("--noPropertiesFile"); 1801 } 1802 1803 private static List<String> getBaseDNs(UserData userData) 1804 { 1805 List<String> baseDNs = new ArrayList<>(); 1806 1807 DataReplicationOptions repl = userData.getReplicationOptions(); 1808 SuffixesToReplicateOptions suf = userData.getSuffixesToReplicateOptions(); 1809 1810 boolean createSuffix = 1811 repl.getType() == DataReplicationOptions.Type.FIRST_IN_TOPOLOGY 1812 || repl.getType() == DataReplicationOptions.Type.STANDALONE 1813 || suf.getType() == SuffixesToReplicateOptions.Type.NEW_SUFFIX_IN_TOPOLOGY; 1814 1815 if (createSuffix) 1816 { 1817 NewSuffixOptions options = userData.getNewSuffixOptions(); 1818 baseDNs.addAll(options.getBaseDns()); 1819 } 1820 else 1821 { 1822 Set<SuffixDescriptor> suffixes = suf.getSuffixes(); 1823 for (SuffixDescriptor suffix : suffixes) 1824 { 1825 baseDNs.add(suffix.getDN()); 1826 } 1827 } 1828 return baseDNs; 1829 } 1830 1831 private static Map<ServerDescriptor, Set<String>> getServerDescriptorBaseDNMap(UserData userData) 1832 { 1833 Map<ServerDescriptor, Set<String>> hm = new HashMap<>(); 1834 1835 Set<SuffixDescriptor> suffixes = userData.getSuffixesToReplicateOptions().getSuffixes(); 1836 AuthenticationData authData = userData.getReplicationOptions().getAuthenticationData(); 1837 String ldapURL = ConnectionUtils.getLDAPUrl(authData.getHostPort(), authData.useSecureConnection()); 1838 for (SuffixDescriptor suffix : suffixes) 1839 { 1840 boolean found = false; 1841 for (ReplicaDescriptor replica : suffix.getReplicas()) 1842 { 1843 if (ldapURL.equalsIgnoreCase(replica.getServer().getAdminConnectorURL())) 1844 { 1845 // This is the server we're configuring 1846 found = true; 1847 Set<String> baseDNs = hm.get(replica.getServer()); 1848 if (baseDNs == null) 1849 { 1850 baseDNs = new LinkedHashSet<>(); 1851 hm.put(replica.getServer(), baseDNs); 1852 } 1853 baseDNs.add(suffix.getDN()); 1854 break; 1855 } 1856 } 1857 if (!found) 1858 { 1859 for (ReplicaDescriptor replica : suffix.getReplicas()) 1860 { 1861 if (hm.keySet().contains(replica.getServer())) 1862 { 1863 hm.get(replica.getServer()).add(suffix.getDN()); 1864 found = true; 1865 break; 1866 } 1867 } 1868 } 1869 if (!found) 1870 { 1871 // We haven't found the server yet, just take the first one 1872 ReplicaDescriptor replica = suffix.getReplicas().iterator().next(); 1873 if (replica != null) 1874 { 1875 Set<String> baseDNs = new LinkedHashSet<>(); 1876 hm.put(replica.getServer(), baseDNs); 1877 baseDNs.add(suffix.getDN()); 1878 } 1879 } 1880 } 1881 return hm; 1882 } 1883 1884 /** 1885 * Returns the equivalent dsconfig command-line required to configure the 1886 * first replicated server in the topology. 1887 * 1888 * @param userData 1889 * the user data. 1890 * @return the equivalent dsconfig command-line required to configure the 1891 * first replicated server in the topology. 1892 */ 1893 public static List<List<String>> getDsConfigReplicationEnableEquivalentCommandLines(UserData userData) 1894 { 1895 final List<List<String>> cmdLines = new ArrayList<>(); 1896 final String cmdName = getCommandLinePath("dsconfig"); 1897 1898 List<String> connectionArgs = newArrayList( 1899 "--hostName", userData.getHostName(), 1900 "--port", String.valueOf(userData.getAdminConnectorPort()), 1901 "--bindDN", userData.getDirectoryManagerDn(), 1902 "--bindPassword", OBFUSCATED_VALUE, 1903 "--trustAll", 1904 "--no-prompt", 1905 "--noPropertiesFile"); 1906 1907 List<String> cmdReplicationServer = newArrayList( 1908 cmdName, 1909 "create-replication-server", 1910 "--provider-name", "Multimaster Synchronization", 1911 "--set", "replication-port:" + userData.getReplicationOptions().getReplicationPort(), 1912 "--set", "replication-server-id:1", 1913 "--type", "generic"); 1914 cmdReplicationServer.addAll(connectionArgs); 1915 1916 cmdLines.add(cmdReplicationServer); 1917 return cmdLines; 1918 } 1919} 1920 1921/** 1922 * This class is used to avoid displaying the error message related to display 1923 * problems that we might have when trying to display the SplashWindow. 1924 */ 1925class EmptyPrintStream extends PrintStream 1926{ 1927 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 1928 1929 /** Default constructor. */ 1930 public EmptyPrintStream() 1931 { 1932 super(new ByteArrayOutputStream(), true); 1933 } 1934 1935 @Override 1936 public void println(String msg) 1937 { 1938 logger.info(LocalizableMessage.raw("EmptyStream msg: " + msg)); 1939 } 1940}