001/*
002 * CDDL HEADER START
003 *
004 * The contents of this file are subject to the terms of the
005 * Common Development and Distribution License, Version 1.0 only
006 * (the "License").  You may not use this file except in compliance
007 * with the License.
008 *
009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
010 * or http://forgerock.org/license/CDDLv1.0.html.
011 * See the License for the specific language governing permissions
012 * and limitations under the License.
013 *
014 * When distributing Covered Code, include this CDDL HEADER in each
015 * file and include the License file at legal-notices/CDDLv1_0.txt.
016 * If applicable, add the following below this CDDL HEADER, with the
017 * fields enclosed by brackets "[]" replaced with your own identifying
018 * information:
019 *      Portions Copyright [yyyy] [name of copyright owner]
020 *
021 * CDDL HEADER END
022 *
023 *
024 *      Copyright 2008-2010 Sun Microsystems, Inc.
025 *      Portions Copyright 2013-2015 ForgeRock AS.
026 */
027package org.opends.server.types;
028
029import static org.opends.messages.ConfigMessages.*;
030import static org.opends.messages.CoreMessages.*;
031import static org.opends.server.config.ConfigConstants.*;
032import static org.opends.server.util.ServerConstants.*;
033
034import java.io.File;
035import java.io.IOException;
036import java.util.Enumeration;
037import java.util.HashMap;
038import java.util.Map;
039import java.util.Properties;
040
041import org.forgerock.i18n.slf4j.LocalizedLogger;
042import org.opends.quicksetup.util.Utils;
043import org.opends.server.api.ConfigHandler;
044import org.opends.server.core.DirectoryServer;
045import org.opends.server.extensions.ConfigFileHandler;
046
047/**
048 * This class provides a set of properties that may control various
049 * aspects of the server environment.  Note that these properties may
050 * only be altered before the Directory Server is started.  Any
051 * attempt to change an environment configuration property while the
052 * server is running will be rejected.
053 */
054@org.opends.server.types.PublicAPI(
055     stability=org.opends.server.types.StabilityLevel.VOLATILE,
056     mayInstantiate=true,
057     mayExtend=false,
058     mayInvoke=true)
059public final class DirectoryEnvironmentConfig
060{
061  /** The set of properties for the environment config. */
062  private final Map<String, String> configProperties;
063
064  private final boolean checkIfServerIsRunning;
065
066  private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
067
068  /**
069   * Creates a new directory environment configuration initialized
070   * from the system properties defined in the JVM.
071   */
072  public DirectoryEnvironmentConfig()
073  {
074    this(true);
075  }
076
077  /**
078   * Creates a new directory environment configuration initialized from the
079   * system properties defined in the JVM.
080   *
081   * @param checkIfServerIsRunning
082   *          If {@code true}, prevent any change when server is running.
083   */
084  public DirectoryEnvironmentConfig(boolean checkIfServerIsRunning)
085  {
086    this(System.getProperties(), checkIfServerIsRunning);
087  }
088
089
090
091  /**
092   * Creates a new directory environment configuration initialized
093   * with a copy of the provided set of properties.
094   *
095   * @param  properties  The properties to use when initializing this
096   *                     environment configuration, or {@code null}
097   *                     to use an empty set of properties.
098   * @param checkIfServerIsRunning
099   *            If {@code true}, prevent any change when server is running.
100   */
101  public DirectoryEnvironmentConfig(Properties properties, boolean checkIfServerIsRunning)
102  {
103    this.checkIfServerIsRunning = checkIfServerIsRunning;
104    configProperties = new HashMap<>();
105    if (properties != null)
106    {
107      Enumeration<?> propertyNames = properties.propertyNames();
108      while (propertyNames.hasMoreElements())
109      {
110        Object o = propertyNames.nextElement();
111        configProperties.put(String.valueOf(o),
112                             String.valueOf(properties.get(o)));
113      }
114    }
115  }
116
117
118
119  /**
120   * Creates a new directory environment configuration initialized
121   * with a copy of the provided set of properties.
122   *
123   * @param  properties  The properties to use when initializing this
124   *                     environment configuration, or {@code null}
125   *                     to use an empty set of properties.
126   * @param checkIfServerIsRunning
127   *            If {@code true}, prevent any change when server is running.
128   */
129  public DirectoryEnvironmentConfig(Map<String,String> properties, boolean checkIfServerIsRunning)
130  {
131    this.checkIfServerIsRunning = checkIfServerIsRunning;
132    if (properties == null)
133    {
134      configProperties = new HashMap<>();
135    }
136    else
137    {
138      configProperties = new HashMap<>(properties);
139    }
140  }
141
142
143
144  /**
145   * Retrieves the property with the specified name.  The check will
146   * first be made in the local config properties, but if no value is
147   * found then the JVM system properties will be checked.
148   *
149   * @param  name  The name of the property to retrieve.
150   *
151   * @return  The property with the specified name, or {@code null} if
152   *          no such property is defined.
153   */
154  public String getProperty(String name)
155  {
156    String value = configProperties.get(name);
157    if (value == null)
158    {
159      value = System.getProperty(name);
160    }
161
162    return value;
163  }
164
165
166
167  /**
168   * Specifies a property with the given name and value.  If a
169   * property is already defined with the given name, then its value
170   * will be replaced with the provided value, or the property will be
171   * removed if the given value is {@code null}.
172   *
173   * @param  name   The name of the property to set.
174   * @param  value  The value of the property to set, or {@code null}
175   *                if the property is to be removed.
176   *
177   * @return  The previous value held for the property, or
178   *          {@code null} if it was not previously set.
179   *
180   * @throws  InitializationException  If the Directory Server is
181   *                                   already running.
182   */
183  public String setProperty(String name, String value)
184         throws InitializationException
185  {
186    checkServerIsRunning();
187
188    if (value == null)
189    {
190      return configProperties.remove(name);
191    }
192    else
193    {
194      return configProperties.put(name, value);
195    }
196  }
197
198  /**
199   * Retrieves the directory that should be considered the server root.
200   * <p>
201   * The determination will first be based on the properties defined in this
202   * object. If no value is found there, then the JVM system properties will be
203   * checked, followed by an environment variable. If there is still no value,
204   * then the location of the config file, if available, is used to determine
205   * the root.
206   *
207   * @return The directory that should be considered the server root, or
208   *         {@code null} if it can't be determined.
209   */
210  public File getServerRoot()
211  {
212    File rootFile = null;
213    try
214    {
215      String serverRootPath = getProperty(PROPERTY_SERVER_ROOT);
216      if (serverRootPath == null)
217      {
218        serverRootPath = System.getenv(ENV_VAR_INSTALL_ROOT);
219      }
220      if (serverRootPath != null)
221      {
222        rootFile = new File(serverRootPath);
223        rootFile = forceNonRelativeFile(rootFile);
224      }
225      else
226      {
227        // Try to figure out root from the location of the configuration file
228        // Check for property first to avoid infinite loop with getConfigFile()
229        final String configFilePath = getProperty(PROPERTY_CONFIG_FILE);
230        if (configFilePath != null)
231        {
232          final File configDirFile = getConfigFile().getParentFile();
233          if (configDirFile != null
234              && CONFIG_DIR_NAME.equals(configDirFile.getName()))
235          {
236            File parent = configDirFile.getParentFile();
237            rootFile = forceNonRelativeFile(parent);
238          }
239        }
240      }
241    }
242    catch (Exception e)
243    {
244      logger.error(ERR_CONFIG_CANNOT_DETERMINE_SERVER_ROOT,
245          ENV_VAR_INSTALL_ROOT, e);
246    }
247    if (rootFile == null)
248    {
249      logger.error(ERR_CONFIG_CANNOT_DETERMINE_SERVER_ROOT,
250          ENV_VAR_INSTALL_ROOT);
251    }
252    return rootFile;
253  }
254
255  /**
256   * Retrieves the path of the directory that should be considered the server
257   * root.
258   * <p>
259   * This method uses the same rules than {@code getServerRoot} method, but
260   * never returns {@code null}. If no directory can be found it returns as a
261   * last resort the value of "user.dir" system property.
262   *
263   * @return the path of the directory that should be considered the server
264   *         root.
265   */
266  public String getServerRootAsString() {
267    File serverRoot = getServerRoot();
268    if (serverRoot != null)
269    {
270      return serverRoot.getAbsolutePath();
271    }
272    // We don't know where the server root is, so we'll have to assume it's
273    // the current working directory.
274    return System.getProperty("user.dir");
275  }
276
277  /**
278   * Retrieves the directory that should be considered the instance
279   * root.
280   *
281   * @return  The directory that should be considered the instance
282   *          root or {@code null} if it can't be determined.
283   */
284  public File getInstanceRoot() {
285    File serverRoot = getServerRoot();
286    if (serverRoot != null)
287    {
288      File instanceRoot = new File(Utils.getInstancePathFromInstallPath(getServerRoot().getAbsolutePath()));
289      return forceNonRelativeFile(instanceRoot);
290    }
291    return null;
292  }
293
294  /**
295   * Retrieves the path of the directory that should be considered the instance
296   * root.
297   * <p>
298   * This method uses the same rules than {@code getInstanceRoot} method, but
299   * never returns {@code null}. If no directory can be found it returns as a
300   * last resort the value of "user.dir" system property.
301   *
302   * @return the path of the directory that should be considered the instance
303   *         root.
304   */
305  public String getInstanceRootAsString()
306  {
307    File instanceRoot = getInstanceRoot();
308    if (instanceRoot != null)
309    {
310      return instanceRoot.getAbsolutePath();
311    }
312
313    // We don't know where the instance root is, so we'll have to assume it's
314    // the current working directory.
315    return System.getProperty("user.dir");
316  }
317
318  private File forceNonRelativeFile(File file) {
319    // Do a best effort to avoid having a relative representation
320    // (for instance to avoid having ../../../).
321    try
322    {
323      return file.getCanonicalFile();
324    }
325    catch (IOException ioe)
326    {
327      return file.getAbsoluteFile();
328    }
329  }
330
331  /**
332   * Retrieves the directory that should be considered the instance
333   * root.  The determination will first be based on the properties
334   * defined in this config object.  If no value is found there, then
335   * the JVM system properties will be checked, followed by an
336   * environment variable.
337   *
338   * @param serverRoot the server Root
339   *
340   * @return  The directory that should be considered the instance
341   *          root, or {@code null} if it is not defined.
342   */
343  public static File getInstanceRootFromServerRoot(File serverRoot)
344  {
345    return new File(Utils.getInstancePathFromInstallPath(serverRoot.getAbsolutePath()));
346  }
347
348
349
350  /**
351   * Specifies the directory that should be considered the server
352   * root.  Any relative path used in the server should be considered
353   * relative to the server root.
354   *
355   * @param  serverRoot  The directory that should be considered the
356   *                     server root.
357   *
358   * @return  The previous server root, or {@code null} if there was
359   *          none.
360   *
361   * @throws  InitializationException  If the Directory Server is
362   *                                   already running or there is a
363   *                                   problem with the provided
364   *                                   server root.
365   */
366  public File setServerRoot(File serverRoot)
367         throws InitializationException
368  {
369    checkServerIsRunning();
370
371    if (!serverRoot.exists() || !serverRoot.isDirectory())
372    {
373      throw new InitializationException(
374              ERR_DIRCFG_INVALID_SERVER_ROOT.get(
375                      serverRoot.getAbsolutePath()));
376    }
377
378    return setPathProperty(PROPERTY_SERVER_ROOT, serverRoot);
379  }
380
381  /**
382   * Sets a path property.
383   *
384   * @param propertyName
385   *          The property name to set.
386   * @param newPath
387   *          The path to set on the property.
388   * @return The previous property value, or {@code null} if there was none.
389   * @throws InitializationException
390   *           If the Directory Server is already running or there is a problem
391   *           with the provided server root.
392   */
393  private File setPathProperty(String propertyName, File newPath)
394      throws InitializationException
395  {
396    String normalizedNewPath;
397    try
398    {
399      normalizedNewPath = newPath.getCanonicalPath();
400    }
401    catch (Exception e)
402    {
403      normalizedNewPath = newPath.getAbsolutePath();
404    }
405
406    String oldPath = setProperty(propertyName, normalizedNewPath);
407    if (oldPath != null)
408    {
409      return new File(oldPath);
410    }
411    return null;
412  }
413
414  /**
415   * Specifies the directory that should be considered the instance
416   * root.  Any relative path used in the server should be considered
417   * relative to the instance root.
418   *
419   * @param  instanceRoot  The directory that should be considered the
420   *                     instanceRoot root.
421   *
422   * @return  The previous server root, or {@code null} if there was
423   *          none.
424   *
425   * @throws  InitializationException  If the Directory Server is
426   *                                   already running or there is a
427   *                                   problem with the provided
428   *                                   server root.
429   */
430  public File setInstanceRoot(File instanceRoot)
431         throws InitializationException
432  {
433    checkServerIsRunning();
434
435    if (!instanceRoot.exists() || !instanceRoot.isDirectory())
436    {
437      throw new InitializationException(
438              ERR_DIRCFG_INVALID_SERVER_ROOT.get(
439                  instanceRoot.getAbsolutePath()));
440    }
441
442    return setPathProperty(PROPERTY_INSTANCE_ROOT, instanceRoot);
443  }
444
445
446  /**
447   * Retrieves the configuration file that should be used to
448   * initialize the Directory Server config handler.  If no default
449   * configuration file is specified, then the server will attempt to
450   * use "config/config.ldif" below the server root if it exists.
451   *
452   * @return  The configuration file that should be used to initialize
453   *          the Directory Server config handler, or {@code null} if
454   *          no configuration file is defined.
455   */
456  public File getConfigFile()
457  {
458    String configFilePath = getProperty(PROPERTY_CONFIG_FILE);
459    if (configFilePath == null)
460    {
461      File serverRoot = getServerRoot();
462      if (serverRoot != null)
463      {
464        File instanceRoot = getInstanceRootFromServerRoot(serverRoot);
465        File configDir = new File(instanceRoot, CONFIG_DIR_NAME);
466        File configFile = new File(configDir, CONFIG_FILE_NAME);
467        if (configFile.exists())
468        {
469          return configFile;
470        }
471      }
472
473      return null;
474    }
475    else
476    {
477      return new File(configFilePath);
478    }
479  }
480
481
482
483  /**
484   * Specifies the configuration file that should be used to
485   * initialize the Directory Server config handler.
486   *
487   * @param  configFile  The configuration file that should be used to
488   *                     initialize the Directory Server config
489   *                     handler.
490   *
491   * @return  The previously-defined configuration file, or
492   *          {@code null} if none was defined.
493   *
494   * @throws  InitializationException  If the Directory Server is
495   *                                   already running or there is a
496   *                                   problem with the provided
497   *                                   configuration file.
498   */
499  public File setConfigFile(File configFile)
500         throws InitializationException
501  {
502    checkServerIsRunning();
503
504    if (!configFile.exists() || !configFile.isFile())
505    {
506      throw new InitializationException(
507              ERR_DIRCFG_INVALID_CONFIG_FILE.get(
508                      configFile.getAbsolutePath()));
509    }
510
511    return setPathProperty(PROPERTY_CONFIG_FILE, configFile);
512  }
513
514
515
516  /**
517   * Retrieves the class that provides the Directory Server
518   * configuration handler implementation.  If no config handler class
519   * is defined, or if a problem occurs while attempting to determine
520   * the config handler class, then a default class of
521   * org.opends.server.extensions.ConfigFileHandler will be returned.
522   *
523   * @return  The class that provides the Directory Server
524   *          configuration handler implementation.
525   */
526  public Class getConfigClass()
527  {
528    String className = getProperty(PROPERTY_CONFIG_CLASS);
529    if (className == null)
530    {
531      return ConfigFileHandler.class;
532    }
533    else
534    {
535      try
536      {
537        return Class.forName(className);
538      }
539      catch (Exception e)
540      {
541        return ConfigFileHandler.class;
542      }
543    }
544  }
545
546
547
548  /**
549   * Specifies the class that provides the Directory Server
550   * configuration handler implementation.  The class must be a
551   * subclass of the org.opends.server.api.ConfigHandler superclass.
552   *
553   * @param  configClass  The class that proviedes the Directory
554   *                      Server configuration handler implementation.
555   *
556   * @return  The class that was previously configured to provide the
557   *          Directory Server configuration handler implementation,
558   *          or {@code null} if none was defined.
559   *
560   * @throws  InitializationException  If the Directory Server is
561   *                                   already running or there is a
562   *                                   problem with the provided
563   *                                   config handler class.
564   */
565  public Class setConfigClass(Class configClass)
566         throws InitializationException
567  {
568    checkServerIsRunning();
569
570    if (!ConfigHandler.class.isAssignableFrom(configClass))
571    {
572      throw new InitializationException(
573              ERR_DIRCFG_INVALID_CONFIG_CLASS.get(
574                      configClass.getName()));
575    }
576
577    String oldClassName = setProperty(PROPERTY_CONFIG_CLASS,
578                                      configClass.getName());
579    if (oldClassName == null)
580    {
581      return null;
582    }
583    else
584    {
585      try
586      {
587        return Class.forName(oldClassName);
588      }
589      catch (Exception e)
590      {
591        return null;
592      }
593    }
594  }
595
596
597
598  /**
599   * Indicates whether the Directory Server should attempt to start
600   * with the "last known good" configuration rather than the current
601   * active configuration file.  Note that if there is no "last known
602   * good" configuration file available, then the server should try to
603   * start using the current, active configuration file.  If no
604   * explicit value is defined, then a default result of {@code false}
605   * will be returned.
606   *
607   * @return  {@code true} if the Directory Server should attempt to
608   *          start using the "last known good" configuration, or
609   *          {@code false} if it should try to start using the
610   *          active configuration.
611   */
612  public boolean useLastKnownGoodConfiguration()
613  {
614    return isPropertyTrue(PROPERTY_USE_LAST_KNOWN_GOOD_CONFIG);
615  }
616
617  /**
618   * Indicates whether the property value is set and equal to "true" for the
619   * supplied property name.
620   *
621   * @param propertyName
622   *          the name of the property to be checked
623   * @return {@code true} if the property is set and the property value is
624   *         <code>"true"</code>, {@code false} otherwise .
625   */
626  private boolean isPropertyTrue(String propertyName)
627  {
628    return "true".equalsIgnoreCase(getProperty(propertyName));
629  }
630
631  /**
632   * Specifies whether the Directory Server should attempt to start
633   * using the last known good configuration rather than the
634   * current active configuration.
635   *
636   * @param  useLastKnownGoodConfiguration  Indicates whether the
637   *                                        Directory Server should
638   *                                        attempt to start using the
639   *                                        last known good
640   *                                        configuration.
641   *
642   * @return  The previous setting for this configuration option.  If
643   *          no previous value was specified, then {@code false} will
644   *          be returned.
645   *
646   * @throws  InitializationException  If the Directory Server is
647   *                                   already running.
648   */
649  public boolean setUseLastKnownGoodConfiguration(
650                      boolean useLastKnownGoodConfiguration)
651         throws InitializationException
652  {
653    return setBooleanProperty(PROPERTY_USE_LAST_KNOWN_GOOD_CONFIG,
654        useLastKnownGoodConfiguration);
655  }
656
657
658
659  /**
660   * Indicates whether the Directory Server should maintain an archive
661   * of previous configurations.  If no explicit value is defined,
662   * then a default result of {@code true} will be returned.
663   *
664   * @return  {@code true} if the Directory Server should maintain an
665   *          archive of previous configurations, or {@code false} if
666   *          not.
667   */
668  public boolean maintainConfigArchive()
669  {
670    String maintainArchiveStr =
671         getProperty(PROPERTY_MAINTAIN_CONFIG_ARCHIVE);
672    return maintainArchiveStr == null
673        || !"false".equalsIgnoreCase(maintainArchiveStr);
674  }
675
676
677
678  /**
679   * Specifies whether the Directory Server should maintain an archive
680   * of previous configurations.
681   *
682   * @param  maintainConfigArchive  Indicates whether the Directory
683   *                                Server should maintain an archive
684   *                                of previous configurations.
685   *
686   * @return  The previous setting for this configuration option.  If
687   *          no previous value was specified, then {@code true} will
688   *          be returned.
689   *
690   * @throws  InitializationException  If the Directory Server is
691   *                                   already running.
692   */
693  public boolean setMaintainConfigArchive(
694                      boolean maintainConfigArchive)
695         throws InitializationException
696  {
697    checkServerIsRunning();
698
699    String oldMaintainStr =
700         setProperty(PROPERTY_MAINTAIN_CONFIG_ARCHIVE,
701                     String.valueOf(maintainConfigArchive));
702    return oldMaintainStr == null || !"false".equalsIgnoreCase(oldMaintainStr);
703  }
704
705
706
707  /**
708   * Retrieves the maximum number of archived configurations that the
709   * Directory Server should maintain.  If no value is defined, then a
710   * value of zero will be returned.
711   *
712   * @return  The maximum number of archived configurations that the
713   *          Directory Server should maintain, or zero if there
714   *          should not be any limit.
715   */
716  public int getMaxConfigArchiveSize()
717  {
718    String maxSizeStr =
719         getProperty(PROPERTY_MAX_CONFIG_ARCHIVE_SIZE);
720    if (maxSizeStr == null)
721    {
722      return 0;
723    }
724
725    try
726    {
727      int maxSize = Integer.parseInt(maxSizeStr);
728      if (maxSize > 0)
729      {
730        return maxSize;
731      }
732      else
733      {
734        return 0;
735      }
736    }
737    catch (Exception e)
738    {
739      return 0;
740    }
741  }
742
743
744
745  /**
746   * Specifies the maximum number of archived configurations that the
747   * Directory Server should maintain.  A value that is less than or
748   * equal to zero may be used to indicate that there should not be
749   * any limit to the number of archived configurations.
750   *
751   * @param  maxConfigArchiveSize  The maximum number of archived
752   *                               configurations that the Directory
753   *                               Server should maintain.
754   *
755   * @return  The previous setting for this configuration option.  If
756   *          no previous value was specified, then zero will be
757   *          returned.
758   *
759   * @throws  InitializationException  If the Directory Server is
760   *                                   already running.
761   */
762  public int setMaxConfigArchiveSize(int maxConfigArchiveSize)
763         throws InitializationException
764  {
765    checkServerIsRunning();
766
767    if (maxConfigArchiveSize < 0)
768    {
769      maxConfigArchiveSize = 0;
770    }
771
772    String oldMaxSizeStr =
773         setProperty(PROPERTY_MAX_CONFIG_ARCHIVE_SIZE,
774                     String.valueOf(maxConfigArchiveSize));
775    if (oldMaxSizeStr == null)
776    {
777      return 0;
778    }
779    else
780    {
781      try
782      {
783        int oldMaxSize = Integer.parseInt(oldMaxSizeStr);
784        if (oldMaxSize > 0)
785        {
786          return oldMaxSize;
787        }
788        else
789        {
790          return 0;
791        }
792      }
793      catch (Exception e)
794      {
795        return 0;
796      }
797    }
798  }
799
800
801
802  /**
803   * Retrieves the directory that contains the server schema
804   * configuration files.  If no value is defined, but a default
805   * directory of "config/schema" exists below the server root, then
806   * that will be returned.
807   *
808   * @return  The directory that contains the server schema
809   *          configuration files, or {@code null} if none is defined.
810   */
811  public File getSchemaDirectory()
812  {
813    String schemaDirectoryPath =
814         getProperty(PROPERTY_SCHEMA_DIRECTORY);
815    if (schemaDirectoryPath == null)
816    {
817      File serverRoot = getServerRoot();
818      if (serverRoot != null)
819      {
820        File instanceRoot =
821          getInstanceRootFromServerRoot(serverRoot);
822        File schemaDir = new File(instanceRoot.getAbsolutePath()
823            + File.separator + PATH_SCHEMA_DIR);
824        if (schemaDir.exists() && schemaDir.isDirectory())
825        {
826          return schemaDir;
827        }
828      }
829      return null;
830    }
831    else
832    {
833      return new File(schemaDirectoryPath);
834    }
835  }
836
837
838
839  /**
840   * Specifies the directory that should contain the server schema
841   * configuration files.  It must exist and must be a directory.
842   *
843   * @param  schemaDirectory  The directory that should contain the
844   *                          server schema configuration files.
845   *
846   * @return  The previously-defined schema configuration directory,
847   *          or {@code null} if none was defined.
848   *
849   * @throws  InitializationException  If the Directory Server is
850   *                                   already running or there is a
851   *                                   problem with the provided
852   *                                   schema directory.
853   */
854  public File setSchemaDirectory(File schemaDirectory)
855         throws InitializationException
856  {
857    checkServerIsRunning();
858
859    if (!schemaDirectory.exists() || !schemaDirectory.isDirectory())
860    {
861      throw new InitializationException(
862              ERR_DIRCFG_INVALID_SCHEMA_DIRECTORY.get(
863                      schemaDirectory.getAbsolutePath()));
864    }
865
866    return setPathProperty(PROPERTY_SCHEMA_DIRECTORY, schemaDirectory);
867  }
868
869
870
871  /**
872   * Retrieves the directory that should be used to hold the server
873   * lock files.  If no value is defined, then the server will attempt
874   * to use a default directory of "locks" below the server root.
875   *
876   * @return  The directory that should be used to hold the server
877   *          lock files, or {@code null} if it cannot be determined.
878   */
879  public File getLockDirectory()
880  {
881    String lockFilePath = getProperty(PROPERTY_LOCK_DIRECTORY);
882    if (lockFilePath == null)
883    {
884      File serverRoot = getServerRoot();
885      if (serverRoot == null)
886      {
887        return null;
888      }
889      else
890      {
891        File instanceRoot = getInstanceRootFromServerRoot(serverRoot);
892        return new File(instanceRoot, LOCKS_DIRECTORY);
893      }
894    }
895    else
896    {
897      return new File(lockFilePath);
898    }
899  }
900
901
902
903  /**
904   * Specifies the directory that should be used to hold the server
905   * lock files.  If the specified path already exists, then it must
906   * be a directory and its contents must be writable by the server.
907   * If it does not exist, then its parent directory must exist and
908   * the server should have permission to create a new subdirectory in
909   * it.
910   *
911   * @param  lockDirectory  The directory that should be used to hold
912   *                        the server lock files.
913   *
914   * @return  The previously-defined lock directory, or {@code null}
915   *          if none was defined.
916   *
917   * @throws  InitializationException  If the Directory Server is
918   *                                   already running or there is a
919   *                                   problem with the provided lock
920   *                                   directory.
921   */
922  public File setLockDirectory(File lockDirectory)
923         throws InitializationException
924  {
925    checkServerIsRunning();
926
927    if (lockDirectory.exists())
928    {
929      if (! lockDirectory.isDirectory())
930      {
931        throw new InitializationException(
932                ERR_DIRCFG_INVALID_LOCK_DIRECTORY.get(
933                        lockDirectory.getAbsolutePath()));
934      }
935    }
936    else
937    {
938      File parentFile = lockDirectory.getParentFile();
939      if (!parentFile.exists() || !parentFile.isDirectory())
940      {
941        throw new InitializationException(
942                ERR_DIRCFG_INVALID_LOCK_DIRECTORY.get(
943                        lockDirectory.getAbsolutePath()));
944      }
945    }
946
947    return setPathProperty(PROPERTY_LOCK_DIRECTORY, lockDirectory);
948  }
949
950
951
952  /**
953   * Indicates whether the Directory Server startup process should
954   * skip the connection handler creation and initialization phases.
955   *
956   * @return  {@code true} if the Directory Server should not start
957   *          its connection handlers, or {@code false} if the
958   *          connection handlers should be enabled.
959   */
960  public boolean disableConnectionHandlers()
961  {
962    return isPropertyTrue(PROPERTY_DISABLE_CONNECTION_HANDLERS);
963  }
964
965  /**
966   * Indicates whether the Directory Server startup process should
967   * skip the synchronization provider creation and initialization
968   * phases.
969   *
970   * @return  {@code true} if the Directory Server should not start
971   *          its synchronization provider, or {@code false} if the
972   *          synchronization provider should be enabled.
973   */
974  public boolean disableSynchronization()
975  {
976    return isPropertyTrue(PROPERTY_DISABLE_SYNCHRONIZATION);
977  }
978
979  /**
980   * Indicates whether the Directory Server startup process should
981   * skip the synchronization between admin data and the
982   * configuration.
983   *
984   * @return  {@code true} if the Directory Server should start
985   *          synchronization between admin data and the
986   *          configuration.
987   */
988  public boolean disableAdminDataSynchronization()
989  {
990    return isPropertyTrue(PROPERTY_DISABLE_ADMIN_DATA_SYNCHRONIZATION);
991  }
992
993  /**
994   * Specifies whether the Directory Server startup process should
995   * skip the connection handler creation and initialization phases.
996   *
997   * @param  disableConnectionHandlers  Indicates whether the
998   *                                    Directory Server should skip
999   *                                    the connection handler
1000   *                                    creation and initialization
1001   *                                    phases.
1002   *
1003   * @return  The previous setting for this configuration option.  If
1004   *          no previous value was specified, then {@code false} will
1005   *          be returned.
1006   *
1007   * @throws  InitializationException  If the Directory Server is
1008   *                                   already running.
1009   */
1010  public boolean setDisableConnectionHandlers(
1011                      boolean disableConnectionHandlers)
1012         throws InitializationException
1013  {
1014    return setBooleanProperty(PROPERTY_DISABLE_CONNECTION_HANDLERS,
1015        disableConnectionHandlers);
1016  }
1017
1018  /**
1019   * Sets a boolean property.
1020   *
1021   * @param propertyName
1022   *          the property name to set
1023   * @param newValue
1024   *          the new value to set for the property
1025   * @return The previous setting for this configuration option. If no previous
1026   *         value was specified, then {@code false} will be returned.
1027   * @throws InitializationException
1028   *           If the Directory Server is already running or there is a problem
1029   *           with the provided server root.
1030   */
1031  private boolean setBooleanProperty(String propertyName, boolean newValue)
1032      throws InitializationException
1033  {
1034    checkServerIsRunning();
1035
1036    final String oldValue = setProperty(propertyName, String.valueOf(newValue));
1037    return "true".equalsIgnoreCase(oldValue);
1038  }
1039
1040  /**
1041   * Indicates whether all threads created by the Directory Server
1042   * should be created as daemon threads.
1043   *
1044   * @return  {@code true} if all threads created by the Directory
1045   *          Server should be created as daemon threads, or
1046   *          {@code false} if not.
1047   */
1048  public boolean forceDaemonThreads()
1049  {
1050    return isPropertyTrue(PROPERTY_FORCE_DAEMON_THREADS);
1051  }
1052
1053
1054
1055  /**
1056   * Specifies whether all threads created by the Directory Server
1057   * should be created as daemon threads.
1058   *
1059   * @param  forceDaemonThreads  Indicates whether all threads created
1060   *                             by the Directory Server should be
1061   *                             created as daemon threads.
1062   *
1063   * @return  The previous setting for this configuration option.  If
1064   *          no previous value was specified, then {@code false} will
1065   *          be returned.
1066   *
1067   * @throws  InitializationException  If the Directory Server is
1068   *                                   already running.
1069   */
1070  public boolean setForceDaemonThreads(boolean forceDaemonThreads)
1071         throws InitializationException
1072  {
1073    return setBooleanProperty(PROPERTY_FORCE_DAEMON_THREADS,
1074        forceDaemonThreads);
1075  }
1076
1077
1078
1079  /**
1080   * Indicates whether the Directory Server should be allowed to use
1081   * the {@code Runtime.exec()} method to be able to launch external
1082   * commands on the underlying system.
1083   *
1084   * @return  {@code true} if the Directory Server should be allowed
1085   *          to use {@code Runtime.exec()}, or {@code false} if not.
1086   */
1087  public boolean disableExec()
1088  {
1089    return isPropertyTrue(PROPERTY_DISABLE_EXEC);
1090  }
1091
1092
1093
1094  /**
1095   * Specifies whether the Directory Server should be allowed to use
1096   * the {@code Runtime.exec()} method to be able to launch external
1097   * commands on the underlying system.
1098   *
1099   * @param  disableExec  Indicates whether the Directory Server
1100   *                      should be allowed to launch external
1101   *                      commands on the underlying system.
1102   *
1103   * @return  The previous setting for this configuration option.  If
1104   *          no previous value was specified, then {@code false} will
1105   *          be returned.
1106   *
1107   * @throws  InitializationException  If the Directory Server is
1108   *                                   already running.
1109   */
1110  public boolean setDisableExec(boolean disableExec)
1111         throws InitializationException
1112  {
1113    return setBooleanProperty(PROPERTY_DISABLE_EXEC, disableExec);
1114  }
1115
1116
1117
1118  /** Throws an exception if server is running and it is not allowed. */
1119  private void checkServerIsRunning() throws InitializationException
1120  {
1121    if (checkIfServerIsRunning && DirectoryServer.isRunning())
1122    {
1123      throw new InitializationException(
1124              ERR_DIRCFG_SERVER_ALREADY_RUNNING.get());
1125    }
1126  }
1127}