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