001/* 002 * (C) Copyright 2010-2016 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * Julien Carsique 018 * 019 */ 020 021package org.nuxeo.launcher.config; 022 023import java.io.BufferedReader; 024import java.io.BufferedWriter; 025import java.io.File; 026import java.io.FileInputStream; 027import java.io.FileNotFoundException; 028import java.io.FileReader; 029import java.io.FileWriter; 030import java.io.IOException; 031import java.io.InputStream; 032import java.io.StringWriter; 033import java.io.Writer; 034import java.net.Inet6Address; 035import java.net.InetAddress; 036import java.net.MalformedURLException; 037import java.net.ServerSocket; 038import java.net.URL; 039import java.net.URLClassLoader; 040import java.net.UnknownHostException; 041import java.security.MessageDigest; 042import java.sql.Connection; 043import java.sql.Driver; 044import java.sql.DriverManager; 045import java.sql.SQLException; 046import java.util.ArrayList; 047import java.util.Arrays; 048import java.util.Enumeration; 049import java.util.HashMap; 050import java.util.HashSet; 051import java.util.Hashtable; 052import java.util.List; 053import java.util.Map; 054import java.util.Properties; 055import java.util.Set; 056import java.util.StringTokenizer; 057import java.util.TreeSet; 058import java.util.UUID; 059 060import javax.naming.NamingException; 061import javax.naming.directory.DirContext; 062import javax.naming.directory.InitialDirContext; 063 064import org.apache.commons.codec.binary.Hex; 065import org.apache.commons.codec.digest.DigestUtils; 066import org.apache.commons.lang.ArrayUtils; 067import org.apache.commons.lang.StringUtils; 068import org.apache.commons.lang.text.StrSubstitutor; 069import org.apache.commons.lang3.SystemUtils; 070import org.apache.commons.logging.Log; 071import org.apache.commons.logging.LogFactory; 072import org.apache.log4j.Logger; 073import org.apache.log4j.helpers.NullEnumeration; 074 075import org.nuxeo.common.Environment; 076import org.nuxeo.common.codec.Crypto; 077import org.nuxeo.common.codec.CryptoProperties; 078import org.nuxeo.common.utils.TextTemplate; 079import org.nuxeo.launcher.commons.DatabaseDriverException; 080import org.nuxeo.log4j.Log4JHelper; 081 082import freemarker.core.ParseException; 083import freemarker.template.TemplateException; 084 085/** 086 * Builder for server configuration and datasource files from templates and properties. 087 * 088 * @author jcarsique 089 */ 090public class ConfigurationGenerator { 091 092 /** 093 * @since 6.0 094 */ 095 public static final String TEMPLATE_SEPARATOR = ","; 096 097 /** 098 * Accurate but not used internally. NXP-18023: Java 8 update 40+ required 099 * 100 * @since 5.7 101 */ 102 public static final String[] COMPLIANT_JAVA_VERSIONS = new String[] { "1.8.0_40" }; 103 104 /** 105 * @since 5.6 106 */ 107 protected static final String CONFIGURATION_PROPERTIES = "configuration.properties"; 108 109 private static final Log log = LogFactory.getLog(ConfigurationGenerator.class); 110 111 /** 112 * @deprecated Since 5.6, use {@link Environment#NUXEO_HOME} instead 113 */ 114 @Deprecated 115 public static final String NUXEO_HOME = Environment.NUXEO_HOME; 116 117 public static final String NUXEO_CONF = "nuxeo.conf"; 118 119 public static final String TEMPLATES = "templates"; 120 121 public static final String NUXEO_DEFAULT_CONF = "nuxeo.defaults"; 122 123 /** 124 * Absolute or relative PATH to the user chosen template 125 * 126 * @deprecated use {@link #PARAM_TEMPLATES_NAME} instead 127 */ 128 @Deprecated 129 public static final String PARAM_TEMPLATE_NAME = "nuxeo.template"; 130 131 /** 132 * Absolute or relative PATH to the user chosen templates (comma separated list) 133 */ 134 public static final String PARAM_TEMPLATES_NAME = "nuxeo.templates"; 135 136 public static final String PARAM_TEMPLATE_DBNAME = "nuxeo.dbtemplate"; 137 138 /** 139 * @since 8.1 140 */ 141 public static final String PARAM_TEMPLATE_DBNOSQL_NAME = "nuxeo.dbnosqltemplate"; 142 143 public static final String PARAM_TEMPLATE_DBTYPE = "nuxeo.db.type"; 144 145 /** 146 * @since 8.1 147 */ 148 public static final String PARAM_TEMPLATE_DBNOSQL_TYPE = "nuxeo.dbnosql.type"; 149 150 /** 151 * @deprecated since 5.7 152 */ 153 @Deprecated 154 public static final String PARAM_TEMPLATES_NODB = "nuxeo.nodbtemplates"; 155 156 public static final String OLD_PARAM_TEMPLATES_PARSING_EXTENSIONS = "nuxeo.templates.parsing.extensions"; 157 158 public static final String PARAM_TEMPLATES_PARSING_EXTENSIONS = "nuxeo.plaintext_parsing_extensions"; 159 160 public static final String PARAM_TEMPLATES_FREEMARKER_EXTENSIONS = "nuxeo.freemarker_parsing_extensions"; 161 162 /** 163 * Absolute or relative PATH to the included templates (comma separated list) 164 */ 165 protected static final String PARAM_INCLUDED_TEMPLATES = "nuxeo.template.includes"; 166 167 public static final String PARAM_FORCE_GENERATION = "nuxeo.force.generation"; 168 169 public static final String BOUNDARY_BEGIN = "### BEGIN - DO NOT EDIT BETWEEN BEGIN AND END ###"; 170 171 public static final String BOUNDARY_END = "### END - DO NOT EDIT BETWEEN BEGIN AND END ###"; 172 173 public static final List<String> DB_LIST = Arrays.asList("default", "postgresql", "oracle", "mysql", "mssql", "db2"); 174 175 public static final List<String> DB_NOSQL_LIST = Arrays.asList("none", "mongodb", "marklogic"); 176 177 public static final List<String> DB_EXCLUDE_CHECK_LIST = Arrays.asList("default", "none"); 178 179 public static final String PARAM_WIZARD_DONE = "nuxeo.wizard.done"; 180 181 public static final String PARAM_WIZARD_RESTART_PARAMS = "wizard.restart.params"; 182 183 public static final String PARAM_FAKE_WINDOWS = "org.nuxeo.fake.vindoz"; 184 185 public static final String PARAM_LOOPBACK_URL = "nuxeo.loopback.url"; 186 187 public static final int MIN_PORT = 1; 188 189 public static final int MAX_PORT = 65535; 190 191 public static final int ADDRESS_PING_TIMEOUT = 1000; 192 193 public static final String PARAM_BIND_ADDRESS = "nuxeo.bind.address"; 194 195 public static final String PARAM_HTTP_PORT = "nuxeo.server.http.port"; 196 197 /** 198 * @deprecated Since 7.4. Use {@link Environment#SERVER_STATUS_KEY} instead 199 */ 200 @Deprecated 201 public static final String PARAM_STATUS_KEY = Environment.SERVER_STATUS_KEY; 202 203 public static final String PARAM_CONTEXT_PATH = "org.nuxeo.ecm.contextPath"; 204 205 public static final String PARAM_MP_DIR = "nuxeo.distribution.marketplace.dir"; 206 207 public static final String DISTRIBUTION_MP_DIR = "setupWizardDownloads"; 208 209 public static final String INSTALL_AFTER_RESTART = "installAfterRestart.log"; 210 211 public static final String PARAM_DB_DRIVER = "nuxeo.db.driver"; 212 213 public static final String PARAM_DB_JDBC_URL = "nuxeo.db.jdbc.url"; 214 215 public static final String PARAM_DB_HOST = "nuxeo.db.host"; 216 217 public static final String PARAM_DB_PORT = "nuxeo.db.port"; 218 219 public static final String PARAM_DB_NAME = "nuxeo.db.name"; 220 221 public static final String PARAM_DB_USER = "nuxeo.db.user"; 222 223 public static final String PARAM_DB_PWD = "nuxeo.db.password"; 224 225 /** 226 * @since 8.1 227 */ 228 public static final String PARAM_MONGODB_NAME = "nuxeo.mongodb.dbname"; 229 230 /** 231 * @since 8.1 232 */ 233 public static final String PARAM_MONGODB_SERVER = "nuxeo.mongodb.server"; 234 235 /** 236 * Keys which value must be displayed thoughtfully 237 * 238 * @since 8.1 239 */ 240 public static final List<String> SECRET_KEYS = Arrays.asList(PARAM_DB_PWD, "mailservice.password", 241 "mail.transport.password", "nuxeo.http.proxy.password", "nuxeo.ldap.bindpassword", 242 "nuxeo.user.emergency.password"); 243 244 /** 245 * @deprecated Since 7.10. Use {@link Environment#PRODUCT_NAME} 246 */ 247 @Deprecated 248 public static final String PARAM_PRODUCT_NAME = Environment.PRODUCT_NAME; 249 250 /** 251 * @deprecated Since 7.10. Use {@link Environment#PRODUCT_VERSION} 252 */ 253 @Deprecated 254 public static final String PARAM_PRODUCT_VERSION = Environment.PRODUCT_VERSION; 255 256 /** 257 * @since 5.6 258 */ 259 public static final String PARAM_NUXEO_URL = "nuxeo.url"; 260 261 /** 262 * Global dev property, duplicated from runtime framework 263 * 264 * @since 5.6 265 */ 266 public static final String NUXEO_DEV_SYSTEM_PROP = "org.nuxeo.dev"; 267 268 /** 269 * Seam hot reload property, also controlled by {@link #NUXEO_DEV_SYSTEM_PROP} 270 * 271 * @since 5.6 272 */ 273 public static final String SEAM_DEBUG_SYSTEM_PROP = "org.nuxeo.seam.debug"; 274 275 /** 276 * Old way of detecting if seam debug should be enabled, by looking for the presence of this file. Setting property 277 * {@link #SEAM_DEBUG_SYSTEM_PROP} in nuxeo.conf is enough now. 278 * 279 * @deprecated since 5.6 280 * @since 5.6 281 */ 282 @Deprecated 283 public static final String SEAM_HOT_RELOAD_GLOBAL_CONFIG_FILE = "seam-debug.properties"; 284 285 private final File nuxeoHome; 286 287 // User configuration file 288 private final File nuxeoConf; 289 290 // Chosen templates 291 private final List<File> includedTemplates = new ArrayList<>(); 292 293 // Common default configuration file 294 private File nuxeoDefaultConf; 295 296 public boolean isJBoss; 297 298 public boolean isJetty; 299 300 public boolean isTomcat; 301 302 private ServerConfigurator serverConfigurator; 303 304 private boolean forceGeneration; 305 306 private Properties defaultConfig; 307 308 private CryptoProperties userConfig; 309 310 private boolean configurable = false; 311 312 private boolean onceGeneration = false; 313 314 private String templates; 315 316 // if PARAM_FORCE_GENERATION=once, set to false; else keep current value 317 private boolean setOnceToFalse = true; 318 319 // if PARAM_FORCE_GENERATION=false, set to once; else keep the current 320 // value 321 private boolean setFalseToOnce = false; 322 323 public boolean isConfigurable() { 324 return configurable; 325 } 326 327 public ConfigurationGenerator() { 328 this(true, false); 329 } 330 331 private boolean quiet = false; 332 333 @SuppressWarnings("unused") 334 private boolean debug = false; 335 336 private static boolean hideDeprecationWarnings = false; 337 338 private Environment env; 339 340 private Properties storedConfig; 341 342 private String currentConfigurationDigest; 343 344 /** 345 * @since 5.7 346 */ 347 protected Properties getStoredConfig() { 348 if (storedConfig == null) { 349 updateStoredConfig(); 350 } 351 return storedConfig; 352 } 353 354 protected static final Map<String, String> parametersMigration = new HashMap<String, String>() { 355 private static final long serialVersionUID = 1L; 356 { 357 put(OLD_PARAM_TEMPLATES_PARSING_EXTENSIONS, PARAM_TEMPLATES_PARSING_EXTENSIONS); 358 put("nuxeo.db.user.separator.key", "nuxeo.db.user_separator_key"); 359 put("mail.pop3.host", "mail.store.host"); 360 put("mail.pop3.port", "mail.store.port"); 361 put("mail.smtp.host", "mail.transport.host"); 362 put("mail.smtp.port", "mail.transport.port"); 363 put("mail.smtp.username", "mail.transport.username"); 364 put("mail.transport.username", "mail.transport.user"); 365 put("mail.smtp.password", "mail.transport.password"); 366 put("mail.smtp.usetls", "mail.transport.usetls"); 367 put("mail.smtp.auth", "mail.transport.auth"); 368 } 369 }; 370 371 /** 372 * @param quiet Suppress info level messages from the console output 373 * @param debug Activate debug level logging 374 * @since 5.6 375 */ 376 public ConfigurationGenerator(boolean quiet, boolean debug) { 377 this.quiet = quiet; 378 this.debug = debug; 379 File serverHome = Environment.getDefault().getServerHome(); 380 if (serverHome != null) { 381 nuxeoHome = serverHome.getAbsoluteFile(); 382 } else { 383 File userDir = new File(System.getProperty("user.dir")); 384 if ("bin".equalsIgnoreCase(userDir.getName())) { 385 nuxeoHome = userDir.getParentFile().getAbsoluteFile(); 386 } else { 387 nuxeoHome = userDir.getAbsoluteFile(); 388 } 389 } 390 String nuxeoConfPath = System.getProperty(NUXEO_CONF); 391 if (nuxeoConfPath != null) { 392 nuxeoConf = new File(nuxeoConfPath).getAbsoluteFile(); 393 } else { 394 nuxeoConf = new File(nuxeoHome, "bin" + File.separator + "nuxeo.conf").getAbsoluteFile(); 395 } 396 System.setProperty(NUXEO_CONF, nuxeoConf.getPath()); 397 398 nuxeoDefaultConf = new File(nuxeoHome, TEMPLATES + File.separator + NUXEO_DEFAULT_CONF); 399 400 // detect server type based on System properties 401 isJetty = System.getProperty(JettyConfigurator.JETTY_HOME) != null; 402 isTomcat = System.getProperty(TomcatConfigurator.TOMCAT_HOME) != null; 403 if (!isJBoss && !isJetty && !isTomcat) { 404 // fallback on jar detection 405 isJBoss = new File(nuxeoHome, "bin/run.jar").exists(); 406 isTomcat = new File(nuxeoHome, "bin/bootstrap.jar").exists(); 407 String[] files = nuxeoHome.list(); 408 for (String file : files) { 409 if (file.startsWith("nuxeo-runtime-launcher")) { 410 isJetty = true; 411 break; 412 } 413 } 414 } 415 if (isTomcat) { 416 serverConfigurator = new TomcatConfigurator(this); 417 } else if (isJetty) { 418 serverConfigurator = new JettyConfigurator(this); 419 } else { 420 serverConfigurator = new UnknownServerConfigurator(this); 421 } 422 if (Logger.getRootLogger().getAllAppenders() instanceof NullEnumeration) { 423 serverConfigurator.initLogs(); 424 } 425 String homeInfo = "Nuxeo home: " + nuxeoHome.getPath(); 426 String confInfo = "Nuxeo configuration: " + nuxeoConf.getPath(); 427 if (quiet) { 428 log.debug(homeInfo); 429 log.debug(confInfo); 430 } else { 431 log.info(homeInfo); 432 log.info(confInfo); 433 } 434 } 435 436 public void hideDeprecationWarnings(boolean hide) { 437 hideDeprecationWarnings = hide; 438 } 439 440 /** 441 * @see #PARAM_FORCE_GENERATION 442 * @param forceGeneration 443 */ 444 public void setForceGeneration(boolean forceGeneration) { 445 this.forceGeneration = forceGeneration; 446 } 447 448 /** 449 * @see #PARAM_FORCE_GENERATION 450 * @return true if configuration will be generated from templates 451 * @since 5.4.2 452 */ 453 public boolean isForceGeneration() { 454 return forceGeneration; 455 } 456 457 public CryptoProperties getUserConfig() { 458 return userConfig; 459 } 460 461 /** 462 * @since 5.4.2 463 */ 464 public final ServerConfigurator getServerConfigurator() { 465 return serverConfigurator; 466 } 467 468 /** 469 * Runs the configuration files generation. 470 */ 471 public void run() throws ConfigurationException { 472 if (init()) { 473 if (!serverConfigurator.isConfigured()) { 474 log.info("No current configuration, generating files..."); 475 generateFiles(); 476 } else if (forceGeneration) { 477 log.info("Configuration files generation (nuxeo.force.generation=" 478 + userConfig.getProperty(PARAM_FORCE_GENERATION) + ")..."); 479 generateFiles(); 480 } else { 481 log.info("Server already configured (set nuxeo.force.generation=true to force configuration files generation)."); 482 } 483 } 484 } 485 486 /** 487 * Initialize configurator, check requirements and load current configuration 488 * 489 * @return returns true if current install is configurable, else returns false 490 */ 491 public boolean init() { 492 return init(false); 493 } 494 495 /** 496 * Initialize configurator, check requirements and load current configuration 497 * 498 * @since 5.6 499 * @param forceReload If true, forces configuration reload. 500 * @return returns true if current install is configurable, else returns false 501 */ 502 public boolean init(boolean forceReload) { 503 if (serverConfigurator instanceof UnknownServerConfigurator) { 504 configurable = false; 505 forceGeneration = false; 506 log.warn("Server will be considered as not configurable."); 507 } 508 if (!nuxeoConf.exists()) { 509 log.info("Missing " + nuxeoConf); 510 configurable = false; 511 userConfig = new CryptoProperties(); 512 } else if (userConfig == null || userConfig.size() == 0 || forceReload) { 513 try { 514 setBasicConfiguration(); 515 configurable = true; 516 } catch (ConfigurationException e) { 517 log.warn("Error reading basic configuration.", e); 518 configurable = false; 519 } 520 } else { 521 configurable = true; 522 } 523 return configurable; 524 } 525 526 /** 527 * @param newTemplates 528 * @return Old templates 529 */ 530 public String changeTemplates(String newTemplates) { 531 String oldTemplates = templates; 532 templates = newTemplates; 533 try { 534 setBasicConfiguration(false); 535 configurable = true; 536 } catch (ConfigurationException e) { 537 log.warn("Error reading basic configuration.", e); 538 configurable = false; 539 } 540 return oldTemplates; 541 } 542 543 /** 544 * Change templates using given database template 545 * 546 * @param dbTemplate new database template 547 * @since 5.4.2 548 */ 549 public void changeDBTemplate(String dbTemplate) { 550 changeTemplates(rebuildTemplatesStr(dbTemplate)); 551 } 552 553 private void setBasicConfiguration() throws ConfigurationException { 554 setBasicConfiguration(true); 555 } 556 557 private void setBasicConfiguration(boolean save) throws ConfigurationException { 558 try { 559 // Load default configuration 560 defaultConfig = loadTrimmedProperties(nuxeoDefaultConf); 561 // Add System properties 562 defaultConfig.putAll(System.getProperties()); 563 userConfig = new CryptoProperties(defaultConfig); 564 565 // If Windows, replace backslashes in paths in nuxeo.conf 566 if (SystemUtils.IS_OS_WINDOWS) { 567 replaceBackslashes(); 568 } 569 // Load user configuration 570 userConfig.putAll(loadTrimmedProperties(nuxeoConf)); 571 onceGeneration = "once".equals(userConfig.getProperty(PARAM_FORCE_GENERATION)); 572 forceGeneration = onceGeneration 573 || Boolean.parseBoolean(userConfig.getProperty(PARAM_FORCE_GENERATION, "false")); 574 checkForDeprecatedParameters(userConfig); 575 576 // Synchronize directories between serverConfigurator and 577 // userConfig/defaultConfig 578 setDirectoryWithProperty(org.nuxeo.common.Environment.NUXEO_DATA_DIR); 579 setDirectoryWithProperty(org.nuxeo.common.Environment.NUXEO_LOG_DIR); 580 setDirectoryWithProperty(org.nuxeo.common.Environment.NUXEO_PID_DIR); 581 setDirectoryWithProperty(org.nuxeo.common.Environment.NUXEO_TMP_DIR); 582 setDirectoryWithProperty(org.nuxeo.common.Environment.NUXEO_MP_DIR); 583 } catch (NullPointerException e) { 584 throw new ConfigurationException("Missing file", e); 585 } catch (FileNotFoundException e) { 586 throw new ConfigurationException("Missing file: " + nuxeoDefaultConf + " or " + nuxeoConf, e); 587 } catch (IOException e) { 588 throw new ConfigurationException("Error reading " + nuxeoConf, e); 589 } 590 591 // Override default configuration with specific configuration(s) of 592 // the chosen template(s) which can be outside of server filesystem 593 try { 594 includeTemplates(); 595 checkForDeprecatedParameters(defaultConfig); 596 extractDatabaseTemplateName(); 597 extractNoSqlDatabaseTemplateName(); 598 } catch (FileNotFoundException e) { 599 throw new ConfigurationException("Missing file", e); 600 } catch (IOException e) { 601 throw new ConfigurationException("Error reading " + nuxeoConf, e); 602 } 603 604 Map<String, String> newParametersToSave = evalDynamicProperties(); 605 if (save && newParametersToSave != null && !newParametersToSave.isEmpty()) { 606 saveConfiguration(newParametersToSave, false, false); 607 } 608 609 logDebugInformation(); 610 611 // Could be useful to initialize DEFAULT env... 612 // initEnv(); 613 } 614 615 /** 616 * @since 5.7 617 * @throws IOException 618 */ 619 protected void includeTemplates() throws IOException { 620 includedTemplates.clear(); 621 List<File> orderedTemplates = includeTemplates(getUserTemplates()); 622 includedTemplates.clear(); 623 includedTemplates.addAll(orderedTemplates); 624 log.debug(includedTemplates); 625 } 626 627 /** 628 * Old way of detecting if seam debug is set, by checking for the presence of a file. 629 * <p> 630 * On 5.6, using the config generator to get the info from the nuxeo.conf file makes it possible to get the property 631 * value this early, so adding an empty file at {@link #SEAM_HOT_RELOAD_GLOBAL_CONFIG_FILE} is no longer needed. 632 * 633 * @deprecated since 5.6 634 */ 635 @Deprecated 636 protected boolean hasSeamDebugFile() { 637 File f = new File(getServerConfigurator().getConfigDir(), SEAM_HOT_RELOAD_GLOBAL_CONFIG_FILE); 638 if (!f.exists()) { 639 return false; 640 } 641 return true; 642 } 643 644 private void logDebugInformation() { 645 String debugPropValue = userConfig.getProperty(NUXEO_DEV_SYSTEM_PROP); 646 if (Boolean.parseBoolean(debugPropValue)) { 647 log.debug("Nuxeo Dev mode enabled"); 648 } else { 649 log.debug("Nuxeo Dev mode is not enabled"); 650 } 651 652 // XXX: cannot init seam debug mode when global debug mode is set, as 653 // it needs to be activated at startup, and requires the seam-debug jar 654 // to be in the classpath anyway 655 String seamDebugPropValue = userConfig.getProperty(SEAM_DEBUG_SYSTEM_PROP); 656 if (Boolean.parseBoolean(seamDebugPropValue) || hasSeamDebugFile()) { 657 log.debug("Nuxeo Seam HotReload is enabled"); 658 // add it to the system props for compat, in case this mode was 659 // detected because of presence of the file in the config dir, and 660 // because it's checked there on code that relies on it 661 System.setProperty(SEAM_DEBUG_SYSTEM_PROP, "true"); 662 } else { 663 log.debug("Nuxeo Seam HotReload is not enabled"); 664 } 665 } 666 667 /** 668 * Generate properties which values are based on others 669 * 670 * @return Map with new parameters to save in {@code nuxeoConf} 671 * @throws ConfigurationException 672 * @since 5.5 673 */ 674 protected HashMap<String, String> evalDynamicProperties() throws ConfigurationException { 675 HashMap<String, String> newParametersToSave = new HashMap<>(); 676 evalLoopbackURL(); 677 evalServerStatusKey(newParametersToSave); 678 return newParametersToSave; 679 } 680 681 /** 682 * Generate a server status key if not already set 683 * 684 * @param newParametersToSave 685 * @throws ConfigurationException 686 * @see Environment#SERVER_STATUS_KEY 687 * @since 5.5 688 */ 689 private void evalServerStatusKey(Map<String, String> newParametersToSave) throws ConfigurationException { 690 if (userConfig.getProperty(Environment.SERVER_STATUS_KEY) == null) { 691 newParametersToSave.put(Environment.SERVER_STATUS_KEY, UUID.randomUUID().toString().substring(0, 8)); 692 } 693 } 694 695 private void evalLoopbackURL() throws ConfigurationException { 696 String loopbackURL = userConfig.getProperty(PARAM_LOOPBACK_URL); 697 if (loopbackURL != null) { 698 log.debug("Using configured loop back url: " + loopbackURL); 699 return; 700 } 701 InetAddress bindAddress = getBindAddress(); 702 // Address and ports already checked by #checkAddressesAndPorts 703 try { 704 if (bindAddress.isAnyLocalAddress()) { 705 boolean preferIPv6 = "false".equals(System.getProperty("java.net.preferIPv4Stack")) 706 && "true".equals(System.getProperty("java.net.preferIPv6Addresses")); 707 bindAddress = preferIPv6 ? InetAddress.getByName("::1") : InetAddress.getByName("127.0.0.1"); 708 log.debug("Bind address is \"ANY\", using local address instead: " + bindAddress); 709 } 710 } catch (UnknownHostException e) { 711 log.debug(e, e); 712 log.error(e.getMessage()); 713 } 714 715 String httpPort = userConfig.getProperty(PARAM_HTTP_PORT); 716 String contextPath = userConfig.getProperty(PARAM_CONTEXT_PATH); 717 // Is IPv6 or IPv4 ? 718 if (bindAddress instanceof Inet6Address) { 719 loopbackURL = "http://[" + bindAddress.getHostAddress() + "]:" + httpPort + contextPath; 720 } else { 721 loopbackURL = "http://" + bindAddress.getHostAddress() + ":" + httpPort + contextPath; 722 } 723 log.debug("Set as loop back URL: " + loopbackURL); 724 defaultConfig.setProperty(PARAM_LOOPBACK_URL, loopbackURL); 725 } 726 727 /** 728 * Read nuxeo.conf, replace backslashes in paths and write new nuxeo.conf 729 * 730 * @throws ConfigurationException if any error reading or writing nuxeo.conf 731 * @since 5.4.1 732 */ 733 protected void replaceBackslashes() throws ConfigurationException { 734 StringBuffer sb = new StringBuffer(); 735 BufferedReader reader = null; 736 try { 737 reader = new BufferedReader(new FileReader(nuxeoConf)); 738 String line; 739 while ((line = reader.readLine()) != null) { 740 if (line.matches(".*:\\\\.*")) { 741 line = line.replaceAll("\\\\", "/"); 742 } 743 sb.append(line + System.getProperty("line.separator")); 744 } 745 reader.close(); 746 } catch (IOException e) { 747 throw new ConfigurationException("Error reading " + nuxeoConf, e); 748 } finally { 749 if (reader != null) { 750 try { 751 reader.close(); 752 } catch (IOException e) { 753 throw new ConfigurationException(e); 754 } 755 } 756 } 757 FileWriter writer = null; 758 try { 759 writer = new FileWriter(nuxeoConf, false); 760 // Copy back file content 761 writer.append(sb.toString()); 762 } catch (IOException e) { 763 throw new ConfigurationException("Error writing in " + nuxeoConf, e); 764 } finally { 765 if (writer != null) { 766 try { 767 writer.close(); 768 } catch (IOException e) { 769 throw new ConfigurationException(e); 770 } 771 } 772 } 773 } 774 775 /** 776 * @since 5.4.2 777 * @param key Directory system key 778 * @see Environment 779 */ 780 public void setDirectoryWithProperty(String key) { 781 String directory = userConfig.getProperty(key); 782 if (directory == null) { 783 defaultConfig.setProperty(key, serverConfigurator.getDirectory(key).getPath()); 784 } else { 785 serverConfigurator.setDirectory(key, directory); 786 } 787 } 788 789 public String getUserTemplates() { 790 if (templates == null) { 791 templates = userConfig.getProperty(PARAM_TEMPLATES_NAME); 792 } 793 if (templates == null) { 794 // backward compliance: manage parameter for a single template 795 templates = userConfig.getProperty(PARAM_TEMPLATE_NAME); 796 } 797 if (templates == null) { 798 log.warn("No template found in configuration! Fallback on 'default'."); 799 templates = "default"; 800 } 801 userConfig.setProperty(PARAM_TEMPLATES_NAME, templates); 802 return templates; 803 } 804 805 protected void generateFiles() throws ConfigurationException { 806 try { 807 serverConfigurator.parseAndCopy(userConfig); 808 serverConfigurator.dumpProperties(userConfig); 809 log.info("Configuration files generated."); 810 // keep true or false, switch once to false 811 if (onceGeneration) { 812 setOnceToFalse = true; 813 writeConfiguration(); 814 } 815 } catch (FileNotFoundException e) { 816 throw new ConfigurationException("Missing file: " + e.getMessage(), e); 817 } catch (TemplateException | ParseException e) { 818 throw new ConfigurationException("Could not process FreeMarker template: " + e.getMessage(), e); 819 } catch (IOException e) { 820 throw new ConfigurationException("Configuration failure: " + e.getMessage(), e); 821 } 822 } 823 824 private List<File> includeTemplates(String templatesList) throws IOException { 825 List<File> orderedTemplates = new ArrayList<>(); 826 StringTokenizer st = new StringTokenizer(templatesList, TEMPLATE_SEPARATOR); 827 while (st.hasMoreTokens()) { 828 String nextToken = st.nextToken(); 829 File chosenTemplate = new File(nextToken); 830 // is it absolute and existing or relative path ? 831 if (!chosenTemplate.exists() || !chosenTemplate.getPath().equals(chosenTemplate.getAbsolutePath())) { 832 chosenTemplate = new File(nuxeoDefaultConf.getParentFile(), nextToken); 833 } 834 if (includedTemplates.contains(chosenTemplate)) { 835 log.debug("Already included " + nextToken); 836 continue; 837 } 838 if (!chosenTemplate.exists()) { 839 log.error(String.format("Template '%s' not found with relative or absolute path (%s). " 840 + "Check your %s parameter, and %s for included files.", nextToken, chosenTemplate, 841 PARAM_TEMPLATES_NAME, PARAM_INCLUDED_TEMPLATES)); 842 continue; 843 } 844 File chosenTemplateConf = new File(chosenTemplate, NUXEO_DEFAULT_CONF); 845 includedTemplates.add(chosenTemplate); 846 if (!chosenTemplateConf.exists()) { 847 log.warn("Ignore template (no default configuration): " + nextToken); 848 continue; 849 } 850 851 Properties subTemplateConf = loadTrimmedProperties(chosenTemplateConf); 852 String subTemplatesList = subTemplateConf.getProperty(PARAM_INCLUDED_TEMPLATES); 853 if (subTemplatesList != null && subTemplatesList.length() > 0) { 854 orderedTemplates.addAll(includeTemplates(subTemplatesList)); 855 } 856 // Load configuration from chosen templates 857 defaultConfig.putAll(subTemplateConf); 858 orderedTemplates.add(chosenTemplate); 859 String templateInfo = "Include template: " + chosenTemplate.getPath(); 860 if (quiet) { 861 log.debug(templateInfo); 862 } else { 863 log.info(templateInfo); 864 } 865 } 866 return orderedTemplates; 867 } 868 869 /** 870 * Check for deprecated parameters 871 * 872 * @param properties 873 * @since 5.6 874 */ 875 protected void checkForDeprecatedParameters(Properties properties) { 876 serverConfigurator.addServerSpecificParameters(parametersMigration); 877 @SuppressWarnings("rawtypes") 878 Enumeration userEnum = properties.propertyNames(); 879 while (userEnum.hasMoreElements()) { 880 String key = (String) userEnum.nextElement(); 881 if (parametersMigration.containsKey(key)) { 882 String value = properties.getProperty(key); 883 properties.setProperty(parametersMigration.get(key), value); 884 // Don't remove the deprecated key yet - more 885 // warnings but old things should keep working 886 // properties.remove(key); 887 if (!hideDeprecationWarnings) { 888 log.warn("Parameter " + key + " is deprecated - please use " + parametersMigration.get(key) 889 + " instead"); 890 } 891 } 892 } 893 } 894 895 public File getNuxeoHome() { 896 return nuxeoHome; 897 } 898 899 public File getNuxeoDefaultConf() { 900 return nuxeoDefaultConf; 901 } 902 903 public List<File> getIncludedTemplates() { 904 return includedTemplates; 905 } 906 907 public static void main(String[] args) throws ConfigurationException { 908 new ConfigurationGenerator().run(); 909 } 910 911 /** 912 * Save changed parameters in {@code nuxeo.conf}. This method does not check values in map. Use 913 * {@link #saveFilteredConfiguration(Map)} for parameters filtering. 914 * 915 * @param changedParameters Map of modified parameters 916 * @see #saveFilteredConfiguration(Map) 917 */ 918 public void saveConfiguration(Map<String, String> changedParameters) throws ConfigurationException { 919 // Keep generation true or once; switch false to once 920 saveConfiguration(changedParameters, false, true); 921 } 922 923 /** 924 * Save changed parameters in {@code nuxeo.conf} calculating templates if changedParameters contains a value for 925 * {@link #PARAM_TEMPLATE_DBNAME}. If a parameter value is empty ("" or null), then the property is unset. 926 * {@link #PARAM_WIZARD_DONE}, {@link #PARAM_TEMPLATES_NAME} and {@link #PARAM_FORCE_GENERATION} cannot be unset, 927 * but their value can be changed.<br/> 928 * This method does not check values in map: use {@link #saveFilteredConfiguration(Map)} for parameters filtering. 929 * 930 * @param changedParameters Map of modified parameters 931 * @param setGenerationOnceToFalse If generation was on (true or once), then set it to false or not? 932 * @param setGenerationFalseToOnce If generation was off (false), then set it to once? 933 * @see #saveFilteredConfiguration(Map) 934 * @since 5.5 935 */ 936 public void saveConfiguration(Map<String, String> changedParameters, boolean setGenerationOnceToFalse, 937 boolean setGenerationFalseToOnce) throws ConfigurationException { 938 setOnceToFalse = setGenerationOnceToFalse; 939 setFalseToOnce = setGenerationFalseToOnce; 940 updateStoredConfig(); 941 String newDbTemplate = changedParameters.remove(PARAM_TEMPLATE_DBNAME); 942 if (newDbTemplate != null) { 943 changedParameters.put(PARAM_TEMPLATES_NAME, rebuildTemplatesStr(newDbTemplate)); 944 } 945 newDbTemplate = changedParameters.remove(PARAM_TEMPLATE_DBNOSQL_NAME); 946 if (newDbTemplate != null) { 947 changedParameters.put(PARAM_TEMPLATES_NAME, rebuildTemplatesStr(newDbTemplate)); 948 } 949 if (changedParameters.containsValue(null) || changedParameters.containsValue("")) { 950 // There are properties to unset 951 Set<String> propertiesToUnset = new HashSet<>(); 952 for (String key : changedParameters.keySet()) { 953 if (StringUtils.isEmpty(changedParameters.get(key))) { 954 propertiesToUnset.add(key); 955 } 956 } 957 for (String key : propertiesToUnset) { 958 changedParameters.remove(key); 959 userConfig.remove(key); 960 } 961 } 962 userConfig.putAll(changedParameters); 963 writeConfiguration(); 964 updateStoredConfig(); 965 } 966 967 private void updateStoredConfig() { 968 if (storedConfig == null) { 969 storedConfig = new Properties(defaultConfig); 970 } else { 971 storedConfig.clear(); 972 } 973 storedConfig.putAll(userConfig); 974 } 975 976 /** 977 * Save changed parameters in {@code nuxeo.conf}, filtering parameters with {@link #getChangedParameters(Map)} 978 * 979 * @param changedParameters Maps of modified parameters 980 * @since 5.4.2 981 * @see #saveConfiguration(Map) 982 * @see #getChangedParameters(Map) 983 */ 984 public void saveFilteredConfiguration(Map<String, String> changedParameters) throws ConfigurationException { 985 Map<String, String> filteredParameters = getChangedParameters(changedParameters); 986 saveConfiguration(filteredParameters); 987 } 988 989 /** 990 * Filters given parameters including them only if (there was no previous value and new value is not empty/null) or 991 * (there was a previous value and it differs from the new value) 992 * 993 * @param changedParameters parameters to be filtered 994 * @return filtered map 995 * @since 5.4.2 996 */ 997 public Map<String, String> getChangedParameters(Map<String, String> changedParameters) { 998 Map<String, String> filteredChangedParameters = new HashMap<>(); 999 for (String key : changedParameters.keySet()) { 1000 String oldParam = getStoredConfig().getProperty(key); 1001 String newParam = changedParameters.get(key); 1002 if (newParam != null) { 1003 newParam = newParam.trim(); 1004 } 1005 if (oldParam == null && StringUtils.isNotEmpty(newParam) || oldParam != null 1006 && !oldParam.trim().equals(newParam)) { 1007 filteredChangedParameters.put(key, newParam); 1008 } 1009 } 1010 return filteredChangedParameters; 1011 } 1012 1013 private void writeConfiguration() throws ConfigurationException { 1014 final MessageDigest newContentDigest = DigestUtils.getMd5Digest(); 1015 StringWriter newContent = new StringWriter() { 1016 @Override 1017 public void write(String str) { 1018 if (str != null) { 1019 newContentDigest.update(str.getBytes()); 1020 } 1021 super.write(str); 1022 } 1023 }; 1024 // Copy back file content 1025 newContent.append(readConfiguration()); 1026 // Write changed parameters 1027 newContent.write(BOUNDARY_BEGIN + System.getProperty("line.separator")); 1028 for (Object o : new TreeSet<>(userConfig.keySet())) { 1029 String key = (String) o; 1030 // Ignore parameters already stored in newContent 1031 if (PARAM_FORCE_GENERATION.equals(key) || PARAM_WIZARD_DONE.equals(key) || PARAM_TEMPLATES_NAME.equals(key)) { 1032 continue; 1033 } 1034 String oldValue = storedConfig.getProperty(key, ""); 1035 String newValue = userConfig.getRawProperty(key, ""); 1036 if (!newValue.equals(oldValue)) { 1037 newContent.write("#" + key + "=" + oldValue + System.getProperty("line.separator")); 1038 newContent.write(key + "=" + newValue + System.getProperty("line.separator")); 1039 } 1040 } 1041 newContent.write(BOUNDARY_END + System.getProperty("line.separator")); 1042 1043 // Write file only if content has changed 1044 if (!Hex.encodeHexString(newContentDigest.digest()).equals(currentConfigurationDigest)) { 1045 try (Writer writer = new FileWriter(nuxeoConf, false)) { 1046 writer.append(newContent.getBuffer()); 1047 } catch (IOException e) { 1048 throw new ConfigurationException("Error writing in " + nuxeoConf, e); 1049 } 1050 } 1051 } 1052 1053 private StringBuffer readConfiguration() throws ConfigurationException { 1054 String wizardParam = null, templatesParam = null; 1055 Integer generationIndex = null, wizardIndex = null, templatesIndex = null; 1056 // Will change wizardParam value instead of appending it 1057 wizardParam = userConfig.getProperty(PARAM_WIZARD_DONE); 1058 // Will change templatesParam value instead of appending it 1059 templatesParam = userConfig.getProperty(PARAM_TEMPLATES_NAME); 1060 ArrayList<String> newLines = new ArrayList<>(); 1061 try (BufferedReader reader = new BufferedReader(new FileReader(nuxeoConf))) { 1062 String line; 1063 MessageDigest digest = DigestUtils.getMd5Digest(); 1064 boolean onConfiguratorContent = false; 1065 while ((line = reader.readLine()) != null) { 1066 digest.update(line.getBytes()); 1067 if (!onConfiguratorContent) { 1068 if (!line.startsWith(BOUNDARY_BEGIN)) { 1069 if (line.startsWith(PARAM_FORCE_GENERATION)) { 1070 if (setOnceToFalse && onceGeneration) { 1071 line = PARAM_FORCE_GENERATION + "=false"; 1072 } 1073 if (setFalseToOnce && !forceGeneration) { 1074 line = PARAM_FORCE_GENERATION + "=once"; 1075 } 1076 if (generationIndex == null) { 1077 newLines.add(line); 1078 generationIndex = newLines.size() - 1; 1079 } else { 1080 newLines.set(generationIndex, line); 1081 } 1082 } else if (line.startsWith(PARAM_WIZARD_DONE)) { 1083 if (wizardParam != null) { 1084 line = PARAM_WIZARD_DONE + "=" + wizardParam; 1085 } 1086 if (wizardIndex == null) { 1087 newLines.add(line); 1088 wizardIndex = newLines.size() - 1; 1089 } else { 1090 newLines.set(wizardIndex, line); 1091 } 1092 } else if (line.startsWith(PARAM_TEMPLATES_NAME)) { 1093 if (templatesParam != null) { 1094 line = PARAM_TEMPLATES_NAME + "=" + templatesParam; 1095 } 1096 if (templatesIndex == null) { 1097 newLines.add(line); 1098 templatesIndex = newLines.size() - 1; 1099 } else { 1100 newLines.set(templatesIndex, line); 1101 } 1102 } else { 1103 int equalIdx = line.indexOf("="); 1104 if (equalIdx < 1 || line.trim().startsWith("#")) { 1105 newLines.add(line); 1106 } else { 1107 String key = line.substring(0, equalIdx).trim(); 1108 if (userConfig.getProperty(key) != null) { 1109 newLines.add(line); 1110 } else { 1111 newLines.add("#" + line); 1112 } 1113 } 1114 } 1115 } else { 1116 // What must be written just before the BOUNDARY_BEGIN 1117 if (templatesIndex == null && templatesParam != null) { 1118 newLines.add(PARAM_TEMPLATES_NAME + "=" + templatesParam); 1119 templatesIndex = newLines.size() - 1; 1120 } 1121 if (wizardIndex == null && wizardParam != null) { 1122 newLines.add(PARAM_WIZARD_DONE + "=" + wizardParam); 1123 wizardIndex = newLines.size() - 1; 1124 } 1125 onConfiguratorContent = true; 1126 } 1127 } else { 1128 if (!line.startsWith(BOUNDARY_END)) { 1129 int equalIdx = line.indexOf("="); 1130 if (line.startsWith("#" + PARAM_TEMPLATES_NAME) || line.startsWith(PARAM_TEMPLATES_NAME)) { 1131 // Backward compliance, it must be ignored 1132 continue; 1133 } 1134 if (equalIdx < 1) { // Ignore non-readable lines 1135 continue; 1136 } 1137 if (line.trim().startsWith("#")) { 1138 String key = line.substring(1, equalIdx).trim(); 1139 String value = line.substring(equalIdx + 1).trim(); 1140 getStoredConfig().setProperty(key, value); 1141 } else { 1142 String key = line.substring(0, equalIdx).trim(); 1143 String value = line.substring(equalIdx + 1).trim(); 1144 if (!value.equals(userConfig.getRawProperty(key))) { 1145 getStoredConfig().setProperty(key, value); 1146 } 1147 } 1148 } else { 1149 onConfiguratorContent = false; 1150 } 1151 } 1152 } 1153 reader.close(); 1154 currentConfigurationDigest = Hex.encodeHexString(digest.digest()); 1155 } catch (IOException e) { 1156 throw new ConfigurationException("Error reading " + nuxeoConf, e); 1157 } 1158 StringBuffer newContent = new StringBuffer(); 1159 for (int i = 0; i < newLines.size(); i++) { 1160 newContent.append(newLines.get(i).trim() + System.getProperty("line.separator")); 1161 } 1162 return newContent; 1163 } 1164 1165 /** 1166 * Extract a database template from the current list of templates. Return the last one if there are multiples. 1167 * 1168 * @see #rebuildTemplatesStr(String) 1169 */ 1170 public String extractDatabaseTemplateName() { 1171 return extractDbTemplateName(DB_LIST, PARAM_TEMPLATE_DBTYPE, PARAM_TEMPLATE_DBNAME, "unknown"); 1172 } 1173 1174 /** 1175 * Extract a NoSQL database template from the current list of templates. Return the last one if there are multiples. 1176 * 1177 * @see #rebuildTemplatesStr(String) 1178 * @since 8.1 1179 */ 1180 public String extractNoSqlDatabaseTemplateName() { 1181 return extractDbTemplateName(DB_NOSQL_LIST, PARAM_TEMPLATE_DBNOSQL_TYPE, PARAM_TEMPLATE_DBNOSQL_NAME, null); 1182 } 1183 1184 private String extractDbTemplateName(List<String> knownDbList, String paramTemplateDbType, 1185 String paramTemplateDbName, String defaultTemplate) { 1186 String dbTemplate = defaultTemplate; 1187 boolean found = false; 1188 for (File templateFile : includedTemplates) { 1189 String template = templateFile.getName(); 1190 if (knownDbList.contains(template)) { 1191 dbTemplate = template; 1192 found = true; 1193 } 1194 } 1195 String dbType = userConfig.getProperty(paramTemplateDbType); 1196 if (!found && dbType != null) { 1197 log.warn(String.format("Didn't find a known database template in the list but " 1198 + "some template contributed a value for %s.", paramTemplateDbType)); 1199 dbTemplate = dbType; 1200 } 1201 if (dbTemplate != null && !dbTemplate.equals(dbType)) { 1202 if (dbType == null) { 1203 log.warn(String.format("Missing value for %s, using %s", paramTemplateDbType, dbTemplate)); 1204 userConfig.setProperty(paramTemplateDbType, dbTemplate); 1205 } else { 1206 log.error(String.format("Inconsistent values between %s (%s) and %s (%s)", paramTemplateDbName, 1207 dbTemplate, paramTemplateDbType, dbType)); 1208 } 1209 } 1210 if (dbTemplate == null) { 1211 defaultConfig.remove(paramTemplateDbName); 1212 } else { 1213 defaultConfig.setProperty(paramTemplateDbName, dbTemplate); 1214 } 1215 return dbTemplate; 1216 } 1217 1218 /** 1219 * @return nuxeo.conf file used 1220 */ 1221 public File getNuxeoConf() { 1222 return nuxeoConf; 1223 } 1224 1225 /** 1226 * Delegate logs initialization to serverConfigurator instance 1227 * 1228 * @since 5.4.2 1229 */ 1230 public void initLogs() { 1231 serverConfigurator.initLogs(); 1232 } 1233 1234 /** 1235 * @return log directory 1236 * @since 5.4.2 1237 */ 1238 public File getLogDir() { 1239 return serverConfigurator.getLogDir(); 1240 } 1241 1242 /** 1243 * @return pid directory 1244 * @since 5.4.2 1245 */ 1246 public File getPidDir() { 1247 return serverConfigurator.getPidDir(); 1248 } 1249 1250 /** 1251 * @return Data directory 1252 * @since 5.4.2 1253 */ 1254 public File getDataDir() { 1255 return serverConfigurator.getDataDir(); 1256 } 1257 1258 /** 1259 * Create needed directories. Check existence of old paths. If old paths have been found and they cannot be upgraded 1260 * automatically, then upgrading message is logged and error thrown. 1261 * 1262 * @throws ConfigurationException If a deprecated directory has been detected. 1263 * @since 5.4.2 1264 * @see ServerConfigurator#verifyInstallation() 1265 */ 1266 public void verifyInstallation() throws ConfigurationException { 1267 checkJavaVersion(); 1268 ifNotExistsAndIsDirectoryThenCreate(getLogDir()); 1269 ifNotExistsAndIsDirectoryThenCreate(getPidDir()); 1270 ifNotExistsAndIsDirectoryThenCreate(getDataDir()); 1271 ifNotExistsAndIsDirectoryThenCreate(getTmpDir()); 1272 ifNotExistsAndIsDirectoryThenCreate(getPackagesDir()); 1273 checkAddressesAndPorts(); 1274 serverConfigurator.verifyInstallation(); 1275 if (!DB_EXCLUDE_CHECK_LIST.contains(userConfig.getProperty(PARAM_TEMPLATE_DBTYPE))) { 1276 try { 1277 checkDatabaseConnection(userConfig.getProperty(PARAM_TEMPLATE_DBNAME), 1278 userConfig.getProperty(PARAM_DB_NAME), userConfig.getProperty(PARAM_DB_USER), 1279 userConfig.getProperty(PARAM_DB_PWD), userConfig.getProperty(PARAM_DB_HOST), 1280 userConfig.getProperty(PARAM_DB_PORT)); 1281 } catch (IOException e) { 1282 throw new ConfigurationException(e); 1283 } catch (DatabaseDriverException e) { 1284 log.debug(e, e); 1285 log.error(e.getMessage()); 1286 throw new ConfigurationException("Could not find database driver: " + e.getMessage()); 1287 } catch (SQLException e) { 1288 log.debug(e, e); 1289 log.error(e.getMessage()); 1290 throw new ConfigurationException("Failed to connect on database: " + e.getMessage()); 1291 } 1292 } 1293 // TODO NXP-18773: check NoSQL database 1294 } 1295 1296 /** 1297 * @return Marketplace packages directory 1298 * @since 5.9.4 1299 */ 1300 private File getPackagesDir() { 1301 return serverConfigurator.getPackagesDir(); 1302 } 1303 1304 /** 1305 * Check that the process is executed with a supported Java version. See <a 1306 * href="http://www.oracle.com/technetwork/java/javase/versioning-naming-139433.html">J2SE SDK/JRE Version String 1307 * Naming Convention</a> 1308 * 1309 * @throws ConfigurationException 1310 * @since 5.6 1311 */ 1312 public void checkJavaVersion() throws ConfigurationException { 1313 String[] requiredVersion = COMPLIANT_JAVA_VERSIONS[0].split("_"); 1314 String version = System.getProperty("java.version"); 1315 String[] versionSplit = version.split("_"); 1316 boolean isCompliant = requiredVersion[0].equals(versionSplit[0]) 1317 && requiredVersion[1].compareTo(versionSplit[1]) <= 0; 1318 boolean isGreater = requiredVersion[0].compareTo(versionSplit[0]) < 0; 1319 if (!isCompliant) { 1320 String message = String.format("Nuxeo requires Java %s+ (detected %s).", COMPLIANT_JAVA_VERSIONS[0], 1321 version); 1322 if (isGreater || "nofail".equalsIgnoreCase(System.getProperty("jvmcheck", "fail"))) { 1323 log.warn(message); 1324 } else { 1325 throw new ConfigurationException(message + " See 'jvmcheck' option to bypass version check."); 1326 } 1327 } 1328 } 1329 1330 /** 1331 * Will check the configured addresses are reachable and Nuxeo required ports are available on those addresses. 1332 * Server specific implementations should override this method in order to check for server specific ports. 1333 * {@link #PARAM_BIND_ADDRESS} must be set before. 1334 * 1335 * @throws ConfigurationException 1336 * @since 5.5 1337 * @see ServerConfigurator#verifyInstallation() 1338 */ 1339 public void checkAddressesAndPorts() throws ConfigurationException { 1340 InetAddress bindAddress = getBindAddress(); 1341 // Sanity check 1342 if (bindAddress.isMulticastAddress()) { 1343 throw new ConfigurationException("Multicast address won't work: " + bindAddress); 1344 } 1345 checkAddressReachable(bindAddress); 1346 checkPortAvailable(bindAddress, Integer.parseInt(userConfig.getProperty(PARAM_HTTP_PORT))); 1347 } 1348 1349 public InetAddress getBindAddress() throws ConfigurationException { 1350 InetAddress bindAddress; 1351 try { 1352 bindAddress = InetAddress.getByName(userConfig.getProperty(PARAM_BIND_ADDRESS)); 1353 log.debug("Configured bind address: " + bindAddress); 1354 } catch (UnknownHostException e) { 1355 throw new ConfigurationException(e); 1356 } 1357 return bindAddress; 1358 } 1359 1360 /** 1361 * @param address address to check for availability 1362 * @throws ConfigurationException 1363 * @since 5.5 1364 */ 1365 public static void checkAddressReachable(InetAddress address) throws ConfigurationException { 1366 try { 1367 log.debug("Checking availability of " + address); 1368 address.isReachable(ADDRESS_PING_TIMEOUT); 1369 } catch (IOException e) { 1370 throw new ConfigurationException("Unreachable bind address " + address); 1371 } 1372 } 1373 1374 /** 1375 * Checks if port is available on given address. 1376 * 1377 * @param port port to check for availability 1378 * @throws ConfigurationException Throws an exception if address is unavailable. 1379 * @since 5.5 1380 */ 1381 public static void checkPortAvailable(InetAddress address, int port) throws ConfigurationException { 1382 if ((port == 0) || (port == -1)) { 1383 log.warn("Port is set to " + Integer.toString(port) 1384 + " - assuming it is disabled - skipping availability check"); 1385 return; 1386 } 1387 if (port < MIN_PORT || port > MAX_PORT) { 1388 throw new IllegalArgumentException("Invalid port: " + port); 1389 } 1390 ServerSocket socketTCP = null; 1391 // DatagramSocket socketUDP = null; 1392 try { 1393 log.debug("Checking availability of port " + port + " on address " + address); 1394 socketTCP = new ServerSocket(port, 0, address); 1395 socketTCP.setReuseAddress(true); 1396 // socketUDP = new DatagramSocket(port, address); 1397 // socketUDP.setReuseAddress(true); 1398 // return true; 1399 } catch (IOException e) { 1400 throw new ConfigurationException(e.getMessage() + ": " + address + ":" + port, e); 1401 } finally { 1402 // if (socketUDP != null) { 1403 // socketUDP.close(); 1404 // } 1405 if (socketTCP != null) { 1406 try { 1407 socketTCP.close(); 1408 } catch (IOException e) { 1409 // Do not throw 1410 } 1411 } 1412 } 1413 } 1414 1415 /** 1416 * @return Temporary directory 1417 */ 1418 public File getTmpDir() { 1419 return serverConfigurator.getTmpDir(); 1420 } 1421 1422 private void ifNotExistsAndIsDirectoryThenCreate(File directory) { 1423 if (!directory.isDirectory()) { 1424 directory.mkdirs(); 1425 } 1426 } 1427 1428 /** 1429 * @return Log files produced by Log4J configuration without loading this configuration instead of current active 1430 * one. 1431 * @since 5.4.2 1432 */ 1433 public ArrayList<String> getLogFiles() { 1434 File log4jConfFile = serverConfigurator.getLogConfFile(); 1435 System.setProperty(org.nuxeo.common.Environment.NUXEO_LOG_DIR, getLogDir().getPath()); 1436 return Log4JHelper.getFileAppendersFiles(log4jConfFile); 1437 } 1438 1439 /** 1440 * Check if wizard must and can be ran 1441 * 1442 * @return true if configuration wizard is required before starting Nuxeo 1443 * @since 5.4.2 1444 */ 1445 public boolean isWizardRequired() { 1446 return !"true".equalsIgnoreCase(getUserConfig().getProperty(PARAM_WIZARD_DONE, "true")) 1447 && serverConfigurator.isWizardAvailable(); 1448 } 1449 1450 /** 1451 * Rebuild a templates string for use in nuxeo.conf 1452 * 1453 * @param dbTemplate database template to use instead of current one 1454 * @return new templates string using given dbTemplate 1455 * @since 5.4.2 1456 * @see #extractDatabaseTemplateName() 1457 * @see #changeDBTemplate(String) 1458 * @see #changeTemplates(String) 1459 */ 1460 public String rebuildTemplatesStr(String dbTemplate) { 1461 List<String> templatesList = new ArrayList<>(); 1462 templatesList.addAll(Arrays.asList(templates.split(TEMPLATE_SEPARATOR))); 1463 String currentDBTemplate = null; 1464 if (DB_LIST.contains(dbTemplate)) { 1465 currentDBTemplate = userConfig.getProperty(PARAM_TEMPLATE_DBNAME); 1466 if (currentDBTemplate == null) { 1467 currentDBTemplate = extractDatabaseTemplateName(); 1468 } 1469 } else if (DB_NOSQL_LIST.contains(dbTemplate)) { 1470 currentDBTemplate = userConfig.getProperty(PARAM_TEMPLATE_DBNOSQL_NAME); 1471 if (currentDBTemplate == null) { 1472 currentDBTemplate = extractNoSqlDatabaseTemplateName(); 1473 } 1474 if ("none".equals(dbTemplate)) { 1475 dbTemplate = null; 1476 } 1477 } 1478 int dbIdx = templatesList.indexOf(currentDBTemplate); 1479 if (dbIdx < 0) { 1480 if (dbTemplate == null) { 1481 return templates; 1482 } 1483 // current db template is implicit => set the new one 1484 templatesList.add(dbTemplate); 1485 } else if (dbTemplate == null) { 1486 // current db template is explicit => remove it 1487 templatesList.remove(dbIdx); 1488 } else { 1489 // current db template is explicit => replace it 1490 templatesList.set(dbIdx, dbTemplate); 1491 } 1492 return StringUtils.join(templatesList, TEMPLATE_SEPARATOR); 1493 } 1494 1495 /** 1496 * @return Nuxeo config directory 1497 * @since 5.4.2 1498 */ 1499 public File getConfigDir() { 1500 return serverConfigurator.getConfigDir(); 1501 } 1502 1503 /** 1504 * Ensure the server will start only wizard application, not Nuxeo 1505 * 1506 * @since 5.4.2 1507 */ 1508 public void prepareWizardStart() { 1509 serverConfigurator.prepareWizardStart(); 1510 } 1511 1512 /** 1513 * Ensure the wizard won't be started and nuxeo is ready for use 1514 * 1515 * @since 5.4.2 1516 */ 1517 public void cleanupPostWizard() { 1518 serverConfigurator.cleanupPostWizard(); 1519 } 1520 1521 /** 1522 * @return Nuxeo runtime home 1523 */ 1524 public File getRuntimeHome() { 1525 return serverConfigurator.getRuntimeHome(); 1526 } 1527 1528 /** 1529 * @since 5.4.2 1530 * @return true if there's an install in progress 1531 */ 1532 public boolean isInstallInProgress() { 1533 return getInstallFile().exists(); 1534 } 1535 1536 /** 1537 * @return File pointing to the directory containing the marketplace packages included in the distribution 1538 * @since 5.6 1539 */ 1540 public File getDistributionMPDir() { 1541 String mpDir = userConfig.getProperty(PARAM_MP_DIR, DISTRIBUTION_MP_DIR); 1542 return new File(getNuxeoHome(), mpDir); 1543 } 1544 1545 /** 1546 * @return Install/upgrade file 1547 * @since 5.4.1 1548 */ 1549 public File getInstallFile() { 1550 return new File(serverConfigurator.getDataDir(), INSTALL_AFTER_RESTART); 1551 } 1552 1553 /** 1554 * Add template(s) to the {@link #PARAM_TEMPLATES_NAME} list if not already present 1555 * 1556 * @param templatesToAdd Comma separated templates to add 1557 * @throws ConfigurationException 1558 * @since 5.5 1559 */ 1560 public void addTemplate(String templatesToAdd) throws ConfigurationException { 1561 String currentTemplatesStr = userConfig.getProperty(PARAM_TEMPLATES_NAME); 1562 List<String> templatesList = new ArrayList<>(); 1563 templatesList.addAll(Arrays.asList(currentTemplatesStr.split(TEMPLATE_SEPARATOR))); 1564 List<String> templatesToAddList = Arrays.asList(templatesToAdd.split(TEMPLATE_SEPARATOR)); 1565 if (templatesList.addAll(templatesToAddList)) { 1566 String newTemplatesStr = StringUtils.join(templatesList, TEMPLATE_SEPARATOR); 1567 HashMap<String, String> parametersToSave = new HashMap<>(); 1568 parametersToSave.put(PARAM_TEMPLATES_NAME, newTemplatesStr); 1569 saveFilteredConfiguration(parametersToSave); 1570 changeTemplates(newTemplatesStr); 1571 } 1572 } 1573 1574 /** 1575 * Remove template(s) from the {@link #PARAM_TEMPLATES_NAME} list 1576 * 1577 * @param templatesToRm Comma separated templates to remove 1578 * @throws ConfigurationException 1579 * @since 5.5 1580 */ 1581 public void rmTemplate(String templatesToRm) throws ConfigurationException { 1582 String currentTemplatesStr = userConfig.getProperty(PARAM_TEMPLATES_NAME); 1583 List<String> templatesList = new ArrayList<>(); 1584 templatesList.addAll(Arrays.asList(currentTemplatesStr.split(TEMPLATE_SEPARATOR))); 1585 List<String> templatesToRmList = Arrays.asList(templatesToRm.split(TEMPLATE_SEPARATOR)); 1586 if (templatesList.removeAll(templatesToRmList)) { 1587 String newTemplatesStr = StringUtils.join(templatesList, TEMPLATE_SEPARATOR); 1588 HashMap<String, String> parametersToSave = new HashMap<>(); 1589 parametersToSave.put(PARAM_TEMPLATES_NAME, newTemplatesStr); 1590 saveFilteredConfiguration(parametersToSave); 1591 changeTemplates(newTemplatesStr); 1592 } 1593 } 1594 1595 /** 1596 * Set a property in nuxeo configuration 1597 * 1598 * @param key 1599 * @param value 1600 * @throws ConfigurationException 1601 * @return The old value 1602 * @since 5.5 1603 */ 1604 public String setProperty(String key, String value) throws ConfigurationException { 1605 String oldValue = getStoredConfig().getProperty(key); 1606 if (PARAM_TEMPLATES_NAME.equals(key)) { 1607 templates = StringUtils.isBlank(value) ? null : value; 1608 } 1609 HashMap<String, String> newParametersToSave = new HashMap<>(); 1610 newParametersToSave.put(key, value); 1611 saveFilteredConfiguration(newParametersToSave); 1612 setBasicConfiguration(); 1613 return oldValue; 1614 } 1615 1616 /** 1617 * Set properties in nuxeo configuration 1618 * 1619 * @param newParametersToSave 1620 * @return The old values 1621 * @throws ConfigurationException 1622 * @since 7.4 1623 */ 1624 public Map<String, String> setProperties(Map<String, String> newParametersToSave) throws ConfigurationException { 1625 Map<String, String> oldValues = new HashMap<>(); 1626 for (String key : newParametersToSave.keySet()) { 1627 oldValues.put(key, getStoredConfig().getProperty(key)); 1628 if (PARAM_TEMPLATES_NAME.equals(key)) { 1629 String value = newParametersToSave.get(key); 1630 templates = StringUtils.isBlank(value) ? null : value; 1631 } 1632 } 1633 saveFilteredConfiguration(newParametersToSave); 1634 setBasicConfiguration(); 1635 return oldValues; 1636 } 1637 1638 /** 1639 * Set properties in the given template, if it exists 1640 * 1641 * @param newParametersToSave 1642 * @return The old values 1643 * @throws ConfigurationException 1644 * @throws IOException 1645 * @since 7.4 1646 */ 1647 public Map<String, String> setProperties(String template, Map<String, String> newParametersToSave) 1648 throws ConfigurationException, IOException { 1649 File templateConf = getTemplateConf(template); 1650 Properties templateProperties = loadTrimmedProperties(templateConf); 1651 Map<String, String> oldValues = new HashMap<>(); 1652 StringBuffer newContent = new StringBuffer(); 1653 try (BufferedReader reader = new BufferedReader(new FileReader(templateConf))) { 1654 String line = reader.readLine(); 1655 if (line != null && line.startsWith("## DO NOT EDIT THIS FILE")) { 1656 throw new ConfigurationException("The template states in its header that it must not be modified."); 1657 } 1658 while (line != null) { 1659 int equalIdx = line.indexOf("="); 1660 if (equalIdx < 1 || line.trim().startsWith("#")) { 1661 newContent.append(line + System.getProperty("line.separator")); 1662 } else { 1663 String key = line.substring(0, equalIdx).trim(); 1664 if (newParametersToSave.containsKey(key)) { 1665 newContent.append(key + "=" + newParametersToSave.get(key) 1666 + System.getProperty("line.separator")); 1667 } else { 1668 newContent.append(line + System.getProperty("line.separator")); 1669 } 1670 } 1671 line = reader.readLine(); 1672 } 1673 } 1674 for (String key : newParametersToSave.keySet()) { 1675 if (templateProperties.containsKey(key)) { 1676 oldValues.put(key, templateProperties.getProperty(key)); 1677 } else { 1678 newContent.append(key + "=" + newParametersToSave.get(key) + System.getProperty("line.separator")); 1679 } 1680 } 1681 try (BufferedWriter writer = new BufferedWriter(new FileWriter(templateConf))) { 1682 writer.append(newContent.toString()); 1683 } 1684 setBasicConfiguration(); 1685 return oldValues; 1686 } 1687 1688 /** 1689 * Check driver availability and database connection 1690 * 1691 * @param databaseTemplate Nuxeo database template 1692 * @param dbName nuxeo.db.name parameter in nuxeo.conf 1693 * @param dbUser nuxeo.db.user parameter in nuxeo.conf 1694 * @param dbPassword nuxeo.db.password parameter in nuxeo.conf 1695 * @param dbHost nuxeo.db.host parameter in nuxeo.conf 1696 * @param dbPort nuxeo.db.port parameter in nuxeo.conf 1697 * @throws DatabaseDriverException 1698 * @throws IOException 1699 * @throws FileNotFoundException 1700 * @throws SQLException 1701 * @since 5.6 1702 */ 1703 public void checkDatabaseConnection(String databaseTemplate, String dbName, String dbUser, String dbPassword, 1704 String dbHost, String dbPort) throws FileNotFoundException, IOException, DatabaseDriverException, 1705 SQLException { 1706 File databaseTemplateDir = new File(nuxeoHome, TEMPLATES + File.separator + databaseTemplate); 1707 Properties templateProperties = loadTrimmedProperties(new File(databaseTemplateDir, NUXEO_DEFAULT_CONF)); 1708 String classname, connectionUrl; 1709 if (userConfig.getProperty(PARAM_TEMPLATE_DBNAME).equals(databaseTemplateDir)) { 1710 // userConfig already includes databaseTemplate 1711 classname = userConfig.getProperty(PARAM_DB_DRIVER); 1712 connectionUrl = userConfig.getProperty(PARAM_DB_JDBC_URL); 1713 } else { // testing a databaseTemplate not included in userConfig 1714 // check if value is set in nuxeo.conf 1715 if (userConfig.containsKey(PARAM_DB_DRIVER)) { 1716 classname = (String) userConfig.get(PARAM_DB_DRIVER); 1717 } else { 1718 classname = templateProperties.getProperty(PARAM_DB_DRIVER); 1719 } 1720 if (userConfig.containsKey(PARAM_DB_JDBC_URL)) { 1721 connectionUrl = (String) userConfig.get(PARAM_DB_JDBC_URL); 1722 } else { 1723 connectionUrl = templateProperties.getProperty(PARAM_DB_JDBC_URL); 1724 } 1725 } 1726 // Load driver class from template or default lib directory 1727 Driver driver = lookupDriver(databaseTemplate, databaseTemplateDir, classname); 1728 // Test db connection 1729 DriverManager.registerDriver(driver); 1730 Properties ttProps = new Properties(userConfig); 1731 ttProps.put(PARAM_DB_HOST, dbHost); 1732 ttProps.put(PARAM_DB_PORT, dbPort); 1733 ttProps.put(PARAM_DB_NAME, dbName); 1734 ttProps.put(PARAM_DB_USER, dbUser); 1735 ttProps.put(PARAM_DB_PWD, dbPassword); 1736 TextTemplate tt = new TextTemplate(ttProps); 1737 String url = tt.processText(connectionUrl); 1738 Properties conProps = new Properties(); 1739 conProps.put("user", dbUser); 1740 conProps.put("password", dbPassword); 1741 log.debug("Testing URL " + url + " with " + conProps); 1742 Connection con = driver.connect(url, conProps); 1743 con.close(); 1744 } 1745 1746 /** 1747 * Build an {@link URLClassLoader} for the given databaseTemplate looking in the templates directory and in the 1748 * server lib directory, then looks for a driver 1749 * 1750 * @param databaseTemplate 1751 * @param databaseTemplateDir 1752 * @param classname Driver class name, defined by {@link #PARAM_DB_DRIVER} 1753 * @return Driver driver if found, else an Exception must have been raised. 1754 * @throws IOException 1755 * @throws FileNotFoundException 1756 * @throws DatabaseDriverException If there was an error when trying to instantiate the driver. 1757 * @since 5.6 1758 */ 1759 private Driver lookupDriver(String databaseTemplate, File databaseTemplateDir, String classname) 1760 throws FileNotFoundException, IOException, DatabaseDriverException { 1761 File[] files = (File[]) ArrayUtils.addAll( // 1762 new File(databaseTemplateDir, "lib").listFiles(), // 1763 serverConfigurator.getServerLibDir().listFiles()); 1764 List<URL> urlsList = new ArrayList<>(); 1765 if (files != null) { 1766 for (File file : files) { 1767 if (file.getName().endsWith("jar")) { 1768 try { 1769 urlsList.add(new URL("jar:file:" + file.getPath() + "!/")); 1770 log.debug("Added " + file.getPath()); 1771 } catch (MalformedURLException e) { 1772 log.error(e); 1773 } 1774 } 1775 } 1776 } 1777 URLClassLoader ucl = new URLClassLoader(urlsList.toArray(new URL[0])); 1778 try { 1779 return (Driver) Class.forName(classname, true, ucl).newInstance(); 1780 } catch (InstantiationException e) { 1781 throw new DatabaseDriverException(e); 1782 } catch (IllegalAccessException e) { 1783 throw new DatabaseDriverException(e); 1784 } catch (ClassNotFoundException e) { 1785 throw new DatabaseDriverException(e); 1786 } 1787 } 1788 1789 /** 1790 * @since 5.6 1791 * @return an {@link Environment} initialized with a few basics 1792 */ 1793 public Environment getEnv() { 1794 /* 1795 * It could be useful to initialize DEFAULT env in {@link #setBasicConfiguration()}... For now, the generated 1796 * {@link Environment} is not static. 1797 */ 1798 if (env == null) { 1799 env = new Environment(getRuntimeHome()); 1800 File distribFile = new File(new File(nuxeoHome, TEMPLATES), "common/config/distribution.properties"); 1801 if (distribFile.exists()) { 1802 try { 1803 env.loadProperties(loadTrimmedProperties(distribFile)); 1804 } catch (FileNotFoundException e) { 1805 log.error(e); 1806 } catch (IOException e) { 1807 log.error(e); 1808 } 1809 } 1810 env.loadProperties(userConfig); 1811 env.setServerHome(getNuxeoHome()); 1812 env.init(); 1813 env.setData(userConfig.getProperty(Environment.NUXEO_DATA_DIR)); 1814 env.setLog(userConfig.getProperty(Environment.NUXEO_LOG_DIR)); 1815 env.setTemp(userConfig.getProperty(Environment.NUXEO_TMP_DIR)); 1816 env.setPath(PARAM_MP_DIR, getDistributionMPDir(), env.getServerHome()); 1817 env.setPath(Environment.NUXEO_MP_DIR, getPackagesDir(), env.getServerHome()); 1818 } 1819 return env; 1820 } 1821 1822 /** 1823 * @since 5.6 1824 * @param propsFile Properties file 1825 * @return new Properties containing trimmed keys and values read in {@code propsFile} 1826 * @throws IOException 1827 */ 1828 public static Properties loadTrimmedProperties(File propsFile) throws IOException { 1829 Properties props = new Properties(); 1830 FileInputStream propsIS = new FileInputStream(propsFile); 1831 try { 1832 loadTrimmedProperties(props, propsIS); 1833 } finally { 1834 propsIS.close(); 1835 } 1836 return props; 1837 } 1838 1839 /** 1840 * @since 5.6 1841 * @param props Properties object to be filled 1842 * @param propsIS Properties InputStream 1843 * @throws IOException 1844 */ 1845 public static void loadTrimmedProperties(Properties props, InputStream propsIS) throws IOException { 1846 if (props == null) { 1847 return; 1848 } 1849 Properties p = new Properties(); 1850 p.load(propsIS); 1851 @SuppressWarnings("unchecked") 1852 Enumeration<String> pEnum = (Enumeration<String>) p.propertyNames(); 1853 while (pEnum.hasMoreElements()) { 1854 String key = pEnum.nextElement(); 1855 String value = p.getProperty(key); 1856 props.put(key.trim(), value.trim()); 1857 } 1858 } 1859 1860 /** 1861 * @return The generated properties file with dumped configuration. 1862 * @since 5.6 1863 */ 1864 public File getDumpedConfig() { 1865 return new File(getConfigDir(), CONFIGURATION_PROPERTIES); 1866 } 1867 1868 /** 1869 * Build a {@link Hashtable} which contains environment properties to instantiate a {@link InitialDirContext} 1870 * 1871 * @since 6.0 1872 */ 1873 public Hashtable<Object, Object> getContextEnv(String ldapUrl, String bindDn, String bindPassword, 1874 boolean checkAuthentication) { 1875 Hashtable<Object, Object> contextEnv = new Hashtable<>(); 1876 contextEnv.put(javax.naming.Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); 1877 contextEnv.put("com.sun.jndi.ldap.connect.timeout", "10000"); 1878 contextEnv.put(javax.naming.Context.PROVIDER_URL, ldapUrl); 1879 if (checkAuthentication) { 1880 contextEnv.put(javax.naming.Context.SECURITY_AUTHENTICATION, "simple"); 1881 contextEnv.put(javax.naming.Context.SECURITY_PRINCIPAL, bindDn); 1882 contextEnv.put(javax.naming.Context.SECURITY_CREDENTIALS, bindPassword); 1883 } 1884 return contextEnv; 1885 } 1886 1887 /** 1888 * Check if the LDAP parameters are correct to bind to a LDAP server. if authenticate argument is true, it will also 1889 * check if the authentication against the LDAP server succeeds 1890 * 1891 * @param ldapUrl 1892 * @param ldapBindDn 1893 * @param ldapBindPwd 1894 * @param authenticate Indicates if authentication against LDAP should be checked. 1895 * @since 6.0 1896 */ 1897 public void checkLdapConnection(String ldapUrl, String ldapBindDn, String ldapBindPwd, boolean authenticate) 1898 throws NamingException { 1899 checkLdapConnection(getContextEnv(ldapUrl, ldapBindDn, ldapBindPwd, authenticate)); 1900 } 1901 1902 /** 1903 * @param contextEnv Environment properties to build a {@link InitialDirContext} 1904 * @since 6.0 1905 */ 1906 public void checkLdapConnection(Hashtable<Object, Object> contextEnv) throws NamingException { 1907 DirContext dirContext = new InitialDirContext(contextEnv); 1908 dirContext.close(); 1909 } 1910 1911 /** 1912 * @return a {@link Crypto} instance initialized with the configuration parameters 1913 * @since 7.4 1914 * @see Crypto 1915 */ 1916 public Crypto getCrypto() { 1917 return userConfig.getCrypto(); 1918 } 1919 1920 /** 1921 * @param template path to configuration template directory 1922 * @return A {@code nuxeo.defaults} file if it exists. 1923 * @throws ConfigurationException if the template file is not found. 1924 * @since 7.4 1925 */ 1926 public File getTemplateConf(String template) throws ConfigurationException { 1927 File templateDir = new File(template); 1928 if (!templateDir.isAbsolute()) { 1929 templateDir = new File(System.getProperty("user.dir"), template); 1930 if (!templateDir.exists() || !new File(templateDir, NUXEO_DEFAULT_CONF).exists()) { 1931 templateDir = new File(nuxeoDefaultConf.getParentFile(), template); 1932 } 1933 } 1934 if (!templateDir.exists() || !new File(templateDir, NUXEO_DEFAULT_CONF).exists()) { 1935 throw new ConfigurationException("Template not found: " + template); 1936 } 1937 return new File(templateDir, NUXEO_DEFAULT_CONF); 1938 } 1939 1940 /** 1941 * Gets the Java options with 'nuxeo.*' properties substituted. It enables 1942 * usage of property like ${nuxeo.log.dir} inside JAVA_OPTS. 1943 * 1944 * @return the java options string. 1945 */ 1946 protected String getJavaOpts(String key, String value) { 1947 return StrSubstitutor.replace(System.getProperty(key, value), getUserConfig()); 1948 } 1949 1950}