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    String path = null;
322    try
323    {
324      path = file.getCanonicalPath();
325    }
326    catch (IOException ioe)
327    {
328      path = file.getAbsolutePath();
329    }
330    return new File(path);
331  }
332
333  /**
334   * Retrieves the directory that should be considered the instance
335   * root.  The determination will first be based on the properties
336   * defined in this config object.  If no value is found there, then
337   * the JVM system properties will be checked, followed by an
338   * environment variable.
339   *
340   * @param serverRoot the server Root
341   *
342   * @return  The directory that should be considered the instance
343   *          root, or {@code null} if it is not defined.
344   */
345  public static File getInstanceRootFromServerRoot(File serverRoot)
346  {
347    return new File(Utils.getInstancePathFromInstallPath(serverRoot.getAbsolutePath()));
348  }
349
350
351
352  /**
353   * Specifies the directory that should be considered the server
354   * root.  Any relative path used in the server should be considered
355   * relative to the server root.
356   *
357   * @param  serverRoot  The directory that should be considered the
358   *                     server root.
359   *
360   * @return  The previous server root, or {@code null} if there was
361   *          none.
362   *
363   * @throws  InitializationException  If the Directory Server is
364   *                                   already running or there is a
365   *                                   problem with the provided
366   *                                   server root.
367   */
368  public File setServerRoot(File serverRoot)
369         throws InitializationException
370  {
371    checkServerIsRunning();
372
373    if (!serverRoot.exists() || !serverRoot.isDirectory())
374    {
375      throw new InitializationException(
376              ERR_DIRCFG_INVALID_SERVER_ROOT.get(
377                      serverRoot.getAbsolutePath()));
378    }
379
380    return setPathProperty(PROPERTY_SERVER_ROOT, serverRoot);
381  }
382
383  /**
384   * Sets a path property.
385   *
386   * @param propertyName
387   *          The property name to set.
388   * @param newPath
389   *          The path to set on the property.
390   * @return The previous property value, or {@code null} if there was none.
391   * @throws InitializationException
392   *           If the Directory Server is already running or there is a problem
393   *           with the provided server root.
394   */
395  private File setPathProperty(String propertyName, File newPath)
396      throws InitializationException
397  {
398    String normalizedNewPath;
399    try
400    {
401      normalizedNewPath = newPath.getCanonicalPath();
402    }
403    catch (Exception e)
404    {
405      normalizedNewPath = newPath.getAbsolutePath();
406    }
407
408    String oldPath = setProperty(propertyName, normalizedNewPath);
409    if (oldPath != null)
410    {
411      return new File(oldPath);
412    }
413    return null;
414  }
415
416  /**
417   * Specifies the directory that should be considered the instance
418   * root.  Any relative path used in the server should be considered
419   * relative to the instance root.
420   *
421   * @param  instanceRoot  The directory that should be considered the
422   *                     instanceRoot root.
423   *
424   * @return  The previous server root, or {@code null} if there was
425   *          none.
426   *
427   * @throws  InitializationException  If the Directory Server is
428   *                                   already running or there is a
429   *                                   problem with the provided
430   *                                   server root.
431   */
432  public File setInstanceRoot(File instanceRoot)
433         throws InitializationException
434  {
435    checkServerIsRunning();
436
437    if (!instanceRoot.exists() || !instanceRoot.isDirectory())
438    {
439      throw new InitializationException(
440              ERR_DIRCFG_INVALID_SERVER_ROOT.get(
441                  instanceRoot.getAbsolutePath()));
442    }
443
444    return setPathProperty(PROPERTY_INSTANCE_ROOT, instanceRoot);
445  }
446
447
448  /**
449   * Retrieves the configuration file that should be used to
450   * initialize the Directory Server config handler.  If no default
451   * configuration file is specified, then the server will attempt to
452   * use "config/config.ldif" below the server root if it exists.
453   *
454   * @return  The configuration file that should be used to initialize
455   *          the Directory Server config handler, or {@code null} if
456   *          no configuration file is defined.
457   */
458  public File getConfigFile()
459  {
460    String configFilePath = getProperty(PROPERTY_CONFIG_FILE);
461    if (configFilePath == null)
462    {
463      File serverRoot = getServerRoot();
464      if (serverRoot != null)
465      {
466        File instanceRoot = getInstanceRootFromServerRoot(serverRoot);
467        File configDir = new File(instanceRoot, CONFIG_DIR_NAME);
468        File configFile = new File(configDir, CONFIG_FILE_NAME);
469        if (configFile.exists())
470        {
471          return configFile;
472        }
473      }
474
475      return null;
476    }
477    else
478    {
479      return new File(configFilePath);
480    }
481  }
482
483
484
485  /**
486   * Specifies the configuration file that should be used to
487   * initialize the Directory Server config handler.
488   *
489   * @param  configFile  The configuration file that should be used to
490   *                     initialize the Directory Server config
491   *                     handler.
492   *
493   * @return  The previously-defined configuration file, or
494   *          {@code null} if none was defined.
495   *
496   * @throws  InitializationException  If the Directory Server is
497   *                                   already running or there is a
498   *                                   problem with the provided
499   *                                   configuration file.
500   */
501  public File setConfigFile(File configFile)
502         throws InitializationException
503  {
504    checkServerIsRunning();
505
506    if (!configFile.exists() || !configFile.isFile())
507    {
508      throw new InitializationException(
509              ERR_DIRCFG_INVALID_CONFIG_FILE.get(
510                      configFile.getAbsolutePath()));
511    }
512
513    return setPathProperty(PROPERTY_CONFIG_FILE, configFile);
514  }
515
516
517
518  /**
519   * Retrieves the class that provides the Directory Server
520   * configuration handler implementation.  If no config handler class
521   * is defined, or if a problem occurs while attempting to determine
522   * the config handler class, then a default class of
523   * org.opends.server.extensions.ConfigFileHandler will be returned.
524   *
525   * @return  The class that provides the Directory Server
526   *          configuration handler implementation.
527   */
528  public Class getConfigClass()
529  {
530    String className = getProperty(PROPERTY_CONFIG_CLASS);
531    if (className == null)
532    {
533      return ConfigFileHandler.class;
534    }
535    else
536    {
537      try
538      {
539        return Class.forName(className);
540      }
541      catch (Exception e)
542      {
543        return ConfigFileHandler.class;
544      }
545    }
546  }
547
548
549
550  /**
551   * Specifies the class that provides the Directory Server
552   * configuration handler implementation.  The class must be a
553   * subclass of the org.opends.server.api.ConfigHandler superclass.
554   *
555   * @param  configClass  The class that proviedes the Directory
556   *                      Server configuration handler implementation.
557   *
558   * @return  The class that was previously configured to provide the
559   *          Directory Server configuration handler implementation,
560   *          or {@code null} if none was defined.
561   *
562   * @throws  InitializationException  If the Directory Server is
563   *                                   already running or there is a
564   *                                   problem with the provided
565   *                                   config handler class.
566   */
567  public Class setConfigClass(Class configClass)
568         throws InitializationException
569  {
570    checkServerIsRunning();
571
572    if (!ConfigHandler.class.isAssignableFrom(configClass))
573    {
574      throw new InitializationException(
575              ERR_DIRCFG_INVALID_CONFIG_CLASS.get(
576                      configClass.getName()));
577    }
578
579    String oldClassName = setProperty(PROPERTY_CONFIG_CLASS,
580                                      configClass.getName());
581    if (oldClassName == null)
582    {
583      return null;
584    }
585    else
586    {
587      try
588      {
589        return Class.forName(oldClassName);
590      }
591      catch (Exception e)
592      {
593        return null;
594      }
595    }
596  }
597
598
599
600  /**
601   * Indicates whether the Directory Server should attempt to start
602   * with the "last known good" configuration rather than the current
603   * active configuration file.  Note that if there is no "last known
604   * good" configuration file available, then the server should try to
605   * start using the current, active configuration file.  If no
606   * explicit value is defined, then a default result of {@code false}
607   * will be returned.
608   *
609   * @return  {@code true} if the Directory Server should attempt to
610   *          start using the "last known good" configuration, or
611   *          {@code false} if it should try to start using the
612   *          active configuration.
613   */
614  public boolean useLastKnownGoodConfiguration()
615  {
616    return isPropertyTrue(PROPERTY_USE_LAST_KNOWN_GOOD_CONFIG);
617  }
618
619  /**
620   * Indicates whether the property value is set and equal to "true" for the
621   * supplied property name.
622   *
623   * @param propertyName
624   *          the name of the property to be checked
625   * @return {@code true} if the property is set and the property value is
626   *         <code>"true"</code>, {@code false} otherwise .
627   */
628  private boolean isPropertyTrue(String propertyName)
629  {
630    return "true".equalsIgnoreCase(getProperty(propertyName));
631  }
632
633  /**
634   * Specifies whether the Directory Server should attempt to start
635   * using the last known good configuration rather than the
636   * current active configuration.
637   *
638   * @param  useLastKnownGoodConfiguration  Indicates whether the
639   *                                        Directory Server should
640   *                                        attempt to start using the
641   *                                        last known good
642   *                                        configuration.
643   *
644   * @return  The previous setting for this configuration option.  If
645   *          no previous value was specified, then {@code false} will
646   *          be returned.
647   *
648   * @throws  InitializationException  If the Directory Server is
649   *                                   already running.
650   */
651  public boolean setUseLastKnownGoodConfiguration(
652                      boolean useLastKnownGoodConfiguration)
653         throws InitializationException
654  {
655    return setBooleanProperty(PROPERTY_USE_LAST_KNOWN_GOOD_CONFIG,
656        useLastKnownGoodConfiguration);
657  }
658
659
660
661  /**
662   * Indicates whether the Directory Server should maintain an archive
663   * of previous configurations.  If no explicit value is defined,
664   * then a default result of {@code true} will be returned.
665   *
666   * @return  {@code true} if the Directory Server should maintain an
667   *          archive of previous configurations, or {@code false} if
668   *          not.
669   */
670  public boolean maintainConfigArchive()
671  {
672    String maintainArchiveStr =
673         getProperty(PROPERTY_MAINTAIN_CONFIG_ARCHIVE);
674    return maintainArchiveStr == null
675        || !"false".equalsIgnoreCase(maintainArchiveStr);
676  }
677
678
679
680  /**
681   * Specifies whether the Directory Server should maintain an archive
682   * of previous configurations.
683   *
684   * @param  maintainConfigArchive  Indicates whether the Directory
685   *                                Server should maintain an archive
686   *                                of previous configurations.
687   *
688   * @return  The previous setting for this configuration option.  If
689   *          no previous value was specified, then {@code true} will
690   *          be returned.
691   *
692   * @throws  InitializationException  If the Directory Server is
693   *                                   already running.
694   */
695  public boolean setMaintainConfigArchive(
696                      boolean maintainConfigArchive)
697         throws InitializationException
698  {
699    checkServerIsRunning();
700
701    String oldMaintainStr =
702         setProperty(PROPERTY_MAINTAIN_CONFIG_ARCHIVE,
703                     String.valueOf(maintainConfigArchive));
704    return oldMaintainStr == null || !"false".equalsIgnoreCase(oldMaintainStr);
705  }
706
707
708
709  /**
710   * Retrieves the maximum number of archived configurations that the
711   * Directory Server should maintain.  If no value is defined, then a
712   * value of zero will be returned.
713   *
714   * @return  The maximum number of archived configurations that the
715   *          Directory Server should maintain, or zero if there
716   *          should not be any limit.
717   */
718  public int getMaxConfigArchiveSize()
719  {
720    String maxSizeStr =
721         getProperty(PROPERTY_MAX_CONFIG_ARCHIVE_SIZE);
722    if (maxSizeStr == null)
723    {
724      return 0;
725    }
726
727    try
728    {
729      int maxSize = Integer.parseInt(maxSizeStr);
730      if (maxSize > 0)
731      {
732        return maxSize;
733      }
734      else
735      {
736        return 0;
737      }
738    }
739    catch (Exception e)
740    {
741      return 0;
742    }
743  }
744
745
746
747  /**
748   * Specifies the maximum number of archived configurations that the
749   * Directory Server should maintain.  A value that is less than or
750   * equal to zero may be used to indicate that there should not be
751   * any limit to the number of archived configurations.
752   *
753   * @param  maxConfigArchiveSize  The maximum number of archived
754   *                               configurations that the Directory
755   *                               Server should maintain.
756   *
757   * @return  The previous setting for this configuration option.  If
758   *          no previous value was specified, then zero will be
759   *          returned.
760   *
761   * @throws  InitializationException  If the Directory Server is
762   *                                   already running.
763   */
764  public int setMaxConfigArchiveSize(int maxConfigArchiveSize)
765         throws InitializationException
766  {
767    checkServerIsRunning();
768
769    if (maxConfigArchiveSize < 0)
770    {
771      maxConfigArchiveSize = 0;
772    }
773
774    String oldMaxSizeStr =
775         setProperty(PROPERTY_MAX_CONFIG_ARCHIVE_SIZE,
776                     String.valueOf(maxConfigArchiveSize));
777    if (oldMaxSizeStr == null)
778    {
779      return 0;
780    }
781    else
782    {
783      try
784      {
785        int oldMaxSize = Integer.parseInt(oldMaxSizeStr);
786        if (oldMaxSize > 0)
787        {
788          return oldMaxSize;
789        }
790        else
791        {
792          return 0;
793        }
794      }
795      catch (Exception e)
796      {
797        return 0;
798      }
799    }
800  }
801
802
803
804  /**
805   * Retrieves the directory that contains the server schema
806   * configuration files.  If no value is defined, but a default
807   * directory of "config/schema" exists below the server root, then
808   * that will be returned.
809   *
810   * @return  The directory that contains the server schema
811   *          configuration files, or {@code null} if none is defined.
812   */
813  public File getSchemaDirectory()
814  {
815    String schemaDirectoryPath =
816         getProperty(PROPERTY_SCHEMA_DIRECTORY);
817    if (schemaDirectoryPath == null)
818    {
819      File serverRoot = getServerRoot();
820      if (serverRoot != null)
821      {
822        File instanceRoot =
823          getInstanceRootFromServerRoot(serverRoot);
824        File schemaDir = new File(instanceRoot.getAbsolutePath()
825            + File.separator + PATH_SCHEMA_DIR);
826        if (schemaDir.exists() && schemaDir.isDirectory())
827        {
828          return schemaDir;
829        }
830      }
831      return null;
832    }
833    else
834    {
835      return new File(schemaDirectoryPath);
836    }
837  }
838
839
840
841  /**
842   * Specifies the directory that should contain the server schema
843   * configuration files.  It must exist and must be a directory.
844   *
845   * @param  schemaDirectory  The directory that should contain the
846   *                          server schema configuration files.
847   *
848   * @return  The previously-defined schema configuration directory,
849   *          or {@code null} if none was defined.
850   *
851   * @throws  InitializationException  If the Directory Server is
852   *                                   already running or there is a
853   *                                   problem with the provided
854   *                                   schema directory.
855   */
856  public File setSchemaDirectory(File schemaDirectory)
857         throws InitializationException
858  {
859    checkServerIsRunning();
860
861    if (!schemaDirectory.exists() || !schemaDirectory.isDirectory())
862    {
863      throw new InitializationException(
864              ERR_DIRCFG_INVALID_SCHEMA_DIRECTORY.get(
865                      schemaDirectory.getAbsolutePath()));
866    }
867
868    return setPathProperty(PROPERTY_SCHEMA_DIRECTORY, schemaDirectory);
869  }
870
871
872
873  /**
874   * Retrieves the directory that should be used to hold the server
875   * lock files.  If no value is defined, then the server will attempt
876   * to use a default directory of "locks" below the server root.
877   *
878   * @return  The directory that should be used to hold the server
879   *          lock files, or {@code null} if it cannot be determined.
880   */
881  public File getLockDirectory()
882  {
883    String lockFilePath = getProperty(PROPERTY_LOCK_DIRECTORY);
884    if (lockFilePath == null)
885    {
886      File serverRoot = getServerRoot();
887      if (serverRoot == null)
888      {
889        return null;
890      }
891      else
892      {
893        File instanceRoot = getInstanceRootFromServerRoot(serverRoot);
894        return new File(instanceRoot, LOCKS_DIRECTORY);
895      }
896    }
897    else
898    {
899      return new File(lockFilePath);
900    }
901  }
902
903
904
905  /**
906   * Specifies the directory that should be used to hold the server
907   * lock files.  If the specified path already exists, then it must
908   * be a directory and its contents must be writable by the server.
909   * If it does not exist, then its parent directory must exist and
910   * the server should have permission to create a new subdirectory in
911   * it.
912   *
913   * @param  lockDirectory  The directory that should be used to hold
914   *                        the server lock files.
915   *
916   * @return  The previously-defined lock directory, or {@code null}
917   *          if none was defined.
918   *
919   * @throws  InitializationException  If the Directory Server is
920   *                                   already running or there is a
921   *                                   problem with the provided lock
922   *                                   directory.
923   */
924  public File setLockDirectory(File lockDirectory)
925         throws InitializationException
926  {
927    checkServerIsRunning();
928
929    if (lockDirectory.exists())
930    {
931      if (! lockDirectory.isDirectory())
932      {
933        throw new InitializationException(
934                ERR_DIRCFG_INVALID_LOCK_DIRECTORY.get(
935                        lockDirectory.getAbsolutePath()));
936      }
937    }
938    else
939    {
940      File parentFile = lockDirectory.getParentFile();
941      if (!parentFile.exists() || !parentFile.isDirectory())
942      {
943        throw new InitializationException(
944                ERR_DIRCFG_INVALID_LOCK_DIRECTORY.get(
945                        lockDirectory.getAbsolutePath()));
946      }
947    }
948
949    return setPathProperty(PROPERTY_LOCK_DIRECTORY, lockDirectory);
950  }
951
952
953
954  /**
955   * Indicates whether the Directory Server startup process should
956   * skip the connection handler creation and initialization phases.
957   *
958   * @return  {@code true} if the Directory Server should not start
959   *          its connection handlers, or {@code false} if the
960   *          connection handlers should be enabled.
961   */
962  public boolean disableConnectionHandlers()
963  {
964    return isPropertyTrue(PROPERTY_DISABLE_CONNECTION_HANDLERS);
965  }
966
967  /**
968   * Indicates whether the Directory Server startup process should
969   * skip the synchronization provider creation and initialization
970   * phases.
971   *
972   * @return  {@code true} if the Directory Server should not start
973   *          its synchronization provider, or {@code false} if the
974   *          synchronization provider should be enabled.
975   */
976  public boolean disableSynchronization()
977  {
978    return isPropertyTrue(PROPERTY_DISABLE_SYNCHRONIZATION);
979  }
980
981  /**
982   * Indicates whether the Directory Server startup process should
983   * skip the synchronization between admin data and the
984   * configuration.
985   *
986   * @return  {@code true} if the Directory Server should start
987   *          synchronization between admin data and the
988   *          configuration.
989   */
990  public boolean disableAdminDataSynchronization()
991  {
992    return isPropertyTrue(PROPERTY_DISABLE_ADMIN_DATA_SYNCHRONIZATION);
993  }
994
995  /**
996   * Specifies whether the Directory Server startup process should
997   * skip the connection handler creation and initialization phases.
998   *
999   * @param  disableConnectionHandlers  Indicates whether the
1000   *                                    Directory Server should skip
1001   *                                    the connection handler
1002   *                                    creation and initialization
1003   *                                    phases.
1004   *
1005   * @return  The previous setting for this configuration option.  If
1006   *          no previous value was specified, then {@code false} will
1007   *          be returned.
1008   *
1009   * @throws  InitializationException  If the Directory Server is
1010   *                                   already running.
1011   */
1012  public boolean setDisableConnectionHandlers(
1013                      boolean disableConnectionHandlers)
1014         throws InitializationException
1015  {
1016    return setBooleanProperty(PROPERTY_DISABLE_CONNECTION_HANDLERS,
1017        disableConnectionHandlers);
1018  }
1019
1020  /**
1021   * Sets a boolean property.
1022   *
1023   * @param propertyName
1024   *          the property name to set
1025   * @param newValue
1026   *          the new value to set for the property
1027   * @return The previous setting for this configuration option. If no previous
1028   *         value was specified, then {@code false} will be returned.
1029   * @throws InitializationException
1030   *           If the Directory Server is already running or there is a problem
1031   *           with the provided server root.
1032   */
1033  private boolean setBooleanProperty(String propertyName, boolean newValue)
1034      throws InitializationException
1035  {
1036    checkServerIsRunning();
1037
1038    final String oldValue = setProperty(propertyName, String.valueOf(newValue));
1039    return "true".equalsIgnoreCase(oldValue);
1040  }
1041
1042  /**
1043   * Indicates whether all threads created by the Directory Server
1044   * should be created as daemon threads.
1045   *
1046   * @return  {@code true} if all threads created by the Directory
1047   *          Server should be created as daemon threads, or
1048   *          {@code false} if not.
1049   */
1050  public boolean forceDaemonThreads()
1051  {
1052    return isPropertyTrue(PROPERTY_FORCE_DAEMON_THREADS);
1053  }
1054
1055
1056
1057  /**
1058   * Specifies whether all threads created by the Directory Server
1059   * should be created as daemon threads.
1060   *
1061   * @param  forceDaemonThreads  Indicates whether all threads created
1062   *                             by the Directory Server should be
1063   *                             created as daemon threads.
1064   *
1065   * @return  The previous setting for this configuration option.  If
1066   *          no previous value was specified, then {@code false} will
1067   *          be returned.
1068   *
1069   * @throws  InitializationException  If the Directory Server is
1070   *                                   already running.
1071   */
1072  public boolean setForceDaemonThreads(boolean forceDaemonThreads)
1073         throws InitializationException
1074  {
1075    return setBooleanProperty(PROPERTY_FORCE_DAEMON_THREADS,
1076        forceDaemonThreads);
1077  }
1078
1079
1080
1081  /**
1082   * Indicates whether the Directory Server should be allowed to use
1083   * the {@code Runtime.exec()} method to be able to launch external
1084   * commands on the underlying system.
1085   *
1086   * @return  {@code true} if the Directory Server should be allowed
1087   *          to use {@code Runtime.exec()}, or {@code false} if not.
1088   */
1089  public boolean disableExec()
1090  {
1091    return isPropertyTrue(PROPERTY_DISABLE_EXEC);
1092  }
1093
1094
1095
1096  /**
1097   * Specifies whether the Directory Server should be allowed to use
1098   * the {@code Runtime.exec()} method to be able to launch external
1099   * commands on the underlying system.
1100   *
1101   * @param  disableExec  Indicates whether the Directory Server
1102   *                      should be allowed to launch external
1103   *                      commands on the underlying system.
1104   *
1105   * @return  The previous setting for this configuration option.  If
1106   *          no previous value was specified, then {@code false} will
1107   *          be returned.
1108   *
1109   * @throws  InitializationException  If the Directory Server is
1110   *                                   already running.
1111   */
1112  public boolean setDisableExec(boolean disableExec)
1113         throws InitializationException
1114  {
1115    return setBooleanProperty(PROPERTY_DISABLE_EXEC, disableExec);
1116  }
1117
1118
1119
1120  /** Throws an exception if server is running and it is not allowed. */
1121  private void checkServerIsRunning() throws InitializationException
1122  {
1123    if (checkIfServerIsRunning && DirectoryServer.isRunning())
1124    {
1125      throw new InitializationException(
1126              ERR_DIRCFG_SERVER_ALREADY_RUNNING.get());
1127    }
1128  }
1129}