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 2006-2010 Sun Microsystems, Inc.
025 *      Portions Copyright 2011-2015 ForgeRock AS
026 */
027package org.opends.quicksetup;
028
029import static com.forgerock.opendj.util.OperatingSystem.*;
030
031import static org.opends.messages.QuickSetupMessages.*;
032
033import java.io.BufferedReader;
034import java.io.File;
035import java.io.FileReader;
036import java.io.IOException;
037import java.util.Set;
038import java.util.concurrent.Callable;
039import java.util.concurrent.ExecutionException;
040import java.util.concurrent.FutureTask;
041
042import org.forgerock.i18n.LocalizableMessage;
043import org.forgerock.i18n.slf4j.LocalizedLogger;
044import org.opends.quicksetup.util.Utils;
045import org.opends.server.util.CollectionUtils;
046import org.opends.server.util.SetupUtils;
047
048/**
049 * This class represents the physical state of an OpenDJ installation. All the
050 * operations are dependent upon the root directory that is specified in the
051 * constructor.
052 */
053public final class Installation
054{
055
056  /** Relative path to bootstrap OpenDJ jar file. */
057  public static final String OPENDJ_BOOTSTRAP_JAR_RELATIVE_PATH = "lib/bootstrap.jar";
058  /** Relative path to bootstrap-client OpenDJ jar file. */
059  public static final String OPENDJ_BOOTSTRAP_CLIENT_JAR_RELATIVE_PATH = "lib/bootstrap-client.jar";
060
061  /** The relative path where all the Windows binaries (batch files) are. */
062  public static final String WINDOWS_BINARIES_PATH_RELATIVE = "bat";
063  /** The relative path where all the UNIX binaries (scripts) are. */
064  public static final String UNIX_BINARIES_PATH_RELATIVE = "bin";
065  /** The relative path where all the MacOS X Applications are. */
066  public static final String MAC_APPLICATIONS_PATH_RELATIVE = "bin";
067  /** The relative path where all the libraries (jar files) are. */
068  public static final String LIBRARIES_PATH_RELATIVE = SetupUtils.LIBRARIES_PATH_RELATIVE;
069  /** The relative path where the resources directory (to customize the product) is. */
070  public static final String RESOURCES_PATH_RELATIVE = "resources";
071  /** The relative path where customer classes are. */
072  public static final String CLASSES_PATH_RELATIVE = "classes";
073  /** The relative path where the database files are. */
074  public static final String DATABASES_PATH_RELATIVE = "db";
075  /** The relative path where the log files are. */
076  public static final String LOGS_PATH_RELATIVE = "logs";
077  /** The relative path where the LDIF files are. */
078  public static final String LDIFS_PATH_RELATIVE = "ldif";
079  /** The relative path where the backup files are. */
080  public static final String BACKUPS_PATH_RELATIVE = "bak";
081  /** The relative path where the config files are. */
082  public static final String CONFIG_PATH_RELATIVE = "config";
083  /** The relative path where the config files are. */
084  public static final String HISTORY_PATH_RELATIVE = "history";
085  /** Path to the config/upgrade directory where upgrade base files are stored. */
086  public static final String UPGRADE_PATH = "upgrade";
087  /** Relative path to the locks directory. */
088  public static final String LOCKS_PATH_RELATIVE = "locks";
089  /** Relative path to the locks directory. */
090  public static final String TMP_PATH_RELATIVE = "tmp";
091  /** The relative path to the current Configuration LDIF file. */
092  public static final String CURRENT_CONFIG_FILE_NAME = "config.ldif";
093  /** The relative path to the current Configuration LDIF file. */
094  public static final String BASE_CONFIG_FILE_PREFIX = "config.ldif.";
095  /** The relative path to the instance.loc file. */
096  public static final String INSTANCE_LOCATION_PATH_RELATIVE = "instance.loc";
097  /** The path to the instance.loc file. */
098  public static final String INSTANCE_LOCATION_PATH = "/etc/opendj/"
099      + INSTANCE_LOCATION_PATH_RELATIVE;
100  /** The relative path to tmpl_instance. */
101  public static final String TEMPLATE_RELATIVE_PATH = "template";
102  /** The relative path to buildinfo file. */
103  public static final String BUILDINFO_RELATIVE_PATH = "buildinfo";
104  /** The UNIX setup script file name. */
105  public static final String UNIX_SETUP_FILE_NAME = "setup";
106  /** The Windows setup batch file name. */
107  public static final String WINDOWS_SETUP_FILE_NAME = "setup.bat";
108  /** The UNIX uninstall script file name. */
109  public static final String UNIX_UNINSTALL_FILE_NAME = "uninstall";
110  /** The Windows uninstall batch file name. */
111  public static final String WINDOWS_UNINSTALL_FILE_NAME = "uninstall.bat";
112  /** The UNIX upgrade script file name. */
113  public static final String UNIX_UPGRADE_FILE_NAME = "upgrade";
114  /** The UNIX start script file name. */
115  public static final String UNIX_START_FILE_NAME = "start-ds";
116  /** The Windows start batch file name. */
117  public static final String WINDOWS_START_FILE_NAME = "start-ds.bat";
118  /** The UNIX stop script file name. */
119  public static final String UNIX_STOP_FILE_NAME = "stop-ds";
120  /** The Windows stop batch file name. */
121  public static final String WINDOWS_STOP_FILE_NAME = "stop-ds.bat";
122  /** The UNIX control panel script file name. */
123  public static final String UNIX_CONTROLPANEL_FILE_NAME = "control-panel";
124  /** The Windows control panel batch file name. */
125  public static final String WINDOWS_CONTROLPANEL_FILE_NAME = "control-panel.bat";
126  /** The MacOS X Java application stub name. */
127  public static final String MAC_JAVA_APP_STUB_NAME = "JavaApplicationStub";
128  /** The MacOS X control panel application bundle name. */
129  public static final String MAC_CONTROLPANEL_FILE_NAME = "ControlPanel.app";
130  /** The UNIX status command line script file name. */
131  public static final String UNIX_STATUSCLI_FILE_NAME = "status";
132  /** The Windows status command line batch file name. */
133  public static final String WINDOWS_STATUSCLI_FILE_NAME = "status.bat";
134  /** The UNIX import LDIF script file name. */
135  public static final String UNIX_IMPORT_LDIF = "import-ldif";
136  /** The Windows import LDIF batch file name. */
137  public static final String WINDOWS_IMPORT_LDIF = "import-ldif.bat";
138
139  /**
140   * Name of the file kept in the history directory containing logs of upgrade
141   * and reversions.
142   */
143  public static final String HISTORY_LOG_FILE_NAME = "log";
144  /** The default java properties file. */
145  public static final String DEFAULT_JAVA_PROPERTIES_FILE = "java.properties";
146  /** The default java properties file relative path. */
147  public static final String RELATIVE_JAVA_PROPERTIES_FILE =
148      CONFIG_PATH_RELATIVE + File.separator + "java.properties";
149  /** The set java home and arguments properties file for Windows. */
150  public static final String SET_JAVA_PROPERTIES_FILE_WINDOWS = "set-java-home.bat";
151  /** Script utils file for UNIX systems. */
152  public static final String SCRIPT_UTIL_FILE_UNIX = "_script-util.sh";
153  /** Script utils file for Windows. */
154  public static final String SCRIPT_UTIL_FILE_WINDOWS = "_script-util.bat";
155  /** The set java home and arguments properties file for UNIX systems. */
156  public static final String SET_JAVA_PROPERTIES_FILE_UNIX = "set-java-home";
157
158  /** Directories required to be present for this installation to be considered valid. */
159  public static final String[] REQUIRED_DIRECTORIES = new String[] {
160      CONFIG_PATH_RELATIVE, DATABASES_PATH_RELATIVE, LIBRARIES_PATH_RELATIVE };
161
162  /** The default base DN prompted to user in setup interactive mode. */
163  public static final String DEFAULT_INTERACTIVE_BASE_DN = "dc=example,dc=com";
164
165  /**
166   * Performs validation on the specified file to make sure that it is an actual
167   * OpenDJ installation.
168   *
169   * @param rootDirectory
170   *          File directory candidate
171   * @throws IllegalArgumentException
172   *           if root directory does not appear to be an OpenDJ installation
173   *           root. The thrown exception contains a localized message
174   *           indicating the reason why <code>rootDirectory</code> is not a
175   *           valid OpenDJ install root.
176   */
177  public static void validateRootDirectory(File rootDirectory)
178      throws IllegalArgumentException
179  {
180    LocalizableMessage failureReason = null;
181    if (rootDirectory == null)
182    {
183      failureReason = INFO_ERROR_INSTALL_ROOT_DIR_NULL.get();
184    }
185    else if (!rootDirectory.exists())
186    {
187      failureReason = INFO_ERROR_INSTALL_ROOT_DIR_NO_EXIST.get(Utils
188          .getPath(rootDirectory));
189    }
190    else if (!rootDirectory.isDirectory())
191    {
192      failureReason = INFO_ERROR_INSTALL_ROOT_DIR_NOT_DIR.get(Utils
193          .getPath(rootDirectory));
194    }
195    else
196    {
197      String[] children = rootDirectory.list();
198      if (children != null)
199      {
200        Set<String> childrenSet = CollectionUtils.newHashSet(children);
201        for (String dir : REQUIRED_DIRECTORIES)
202        {
203          if (!childrenSet.contains(dir))
204          {
205            failureReason = INFO_ERROR_INSTALL_ROOT_DIR_NO_DIR.get(
206                Utils.getPath(rootDirectory), dir);
207          }
208        }
209      }
210      else
211      {
212        failureReason = INFO_ERROR_INSTALL_ROOT_DIR_EMPTY.get(Utils
213            .getPath(rootDirectory));
214      }
215    }
216    if (failureReason != null)
217    {
218      throw new IllegalArgumentException(failureReason.toString());
219    }
220  }
221
222
223
224  private static Installation local;
225
226
227
228  /**
229   * Obtains the installation by reading the classpath of the running JVM to
230   * determine the location of the jars and determine the installation root.
231   *
232   * @return Installation obtained by reading the classpath
233   */
234  public static Installation getLocal()
235  {
236    if (local == null)
237    {
238
239      // This allows testing of configuration components when the OpenDJ.jar
240      // in the classpath does not necessarily point to the server's
241      String installRoot = System.getProperty("org.opends.quicksetup.Root");
242      String instanceRoot = System
243          .getProperty("org.opends.quicksetup.instance");
244
245      if (installRoot == null)
246      {
247        installRoot = Utils.getInstallPathFromClasspath();
248      }
249      if (instanceRoot == null)
250      {
251        instanceRoot = Utils.getInstancePathFromInstallPath(installRoot);
252      }
253      local = new Installation(installRoot, instanceRoot);
254    }
255    return local;
256  }
257
258
259
260  private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
261
262  private File rootDirectory;
263  private File instanceDirectory;
264
265  private Status status;
266
267  private Configuration configuration;
268  private Configuration baseConfiguration;
269
270  private BuildInformation buildInformation;
271  private BuildInformation instanceInformation;
272
273
274  /**
275   * Creates a new instance from a root directory specified as a string.
276   *
277   * @param rootDirectory
278   *          of this installation
279   * @param instanceRootDirectory
280   *          The instance root directory
281   */
282  public Installation(String rootDirectory, String instanceRootDirectory)
283  {
284    this(new File(rootDirectory), new File(instanceRootDirectory));
285  }
286
287
288
289  /**
290   * Creates a new instance from a root directory specified as a File.
291   *
292   * @param rootDirectory
293   *          of this installation
294   * @param instanceDirectory
295   *          of the instance
296   */
297  public Installation(File rootDirectory, File instanceDirectory)
298  {
299    setRootDirectory(rootDirectory);
300    setInstanceDirectory(instanceDirectory);
301  }
302
303
304
305  /**
306   * Gets the top level directory of an OpenDJ installation.
307   *
308   * @return File object representing the top level directory of and OpenDJ
309   *         installation
310   */
311  public File getRootDirectory()
312  {
313    return this.rootDirectory;
314  }
315
316
317
318  /**
319   * Gets the top level directory of an OpenDJ instance.
320   *
321   * @return File object representing the top level directory of and OpenDK
322   *         installation
323   */
324  public File getInstanceDirectory()
325  {
326    return this.instanceDirectory;
327  }
328
329
330
331  /**
332   * Sets the root directory of this installation.
333   *
334   * @param rootDirectory
335   *          File of this installation
336   */
337  public void setRootDirectory(File rootDirectory)
338  {
339
340    // Hold off on doing validation of rootDirectory since
341    // some applications (like the Installer) create an Installation
342    // before the actual bits have been laid down on the file system.
343    this.rootDirectory = rootDirectory;
344
345    // Obtaining build information is a fairly time consuming operation.
346    // Try to get a head start if possible.
347    if (isValid(rootDirectory))
348    {
349      try
350      {
351        BuildInformation bi = getBuildInformation();
352        logger.info(LocalizableMessage.raw("build info for " + rootDirectory.getName() + ": "
353            + bi));
354      }
355      catch (ApplicationException e)
356      {
357        logger.info(LocalizableMessage.raw("error determining build information", e));
358      }
359    }
360  }
361
362
363
364  /**
365   * Sets the root directory of this instance.
366   *
367   * @param instanceDirectory
368   *          File of this instance
369   */
370  public void setInstanceDirectory(File instanceDirectory)
371  {
372    // Hold off on doing validation of rootDirectory since
373    // some applications (like the Installer) create an Installation
374    // before the actual bits have been laid down on the filesystem.
375    this.instanceDirectory = instanceDirectory;
376
377    // Obtaining build information is a fairly time consuming operation.
378    // Try to get a head start if possible.
379    if (isValid(instanceDirectory))
380    {
381      try
382      {
383        BuildInformation bi = getBuildInformation();
384        logger.info(LocalizableMessage.raw("build info for " + instanceDirectory.getName()
385            + ": " + bi));
386      }
387      catch (ApplicationException e)
388      {
389        logger.info(LocalizableMessage.raw("error determining build information", e));
390      }
391    }
392  }
393
394
395
396  /**
397   * Indicates whether or not this installation appears to be an actual OpenDJ
398   * installation.
399   *
400   * @param file
401   *          The root directory
402   * @return boolean where true indicates that this does indeed appear to be a
403   *         valid OpenDJ installation; false otherwise
404   */
405  public boolean isValid(File file)
406  {
407    try
408    {
409      validateRootDirectory(file);
410      return true;
411    }
412    catch (IllegalArgumentException e)
413    {
414      return false;
415    }
416  }
417
418
419
420  /**
421   * Creates a string explaining why this is not a legitimate OpenDJ
422   * installation. Null if this is in fact a valid installation.
423   *
424   * @return localized message indicating the reason this is not an OpenDJ
425   *         installation
426   */
427  public String getInvalidityReason()
428  {
429    try
430    {
431      validateRootDirectory(rootDirectory);
432      return null;
433    }
434    catch (IllegalArgumentException e)
435    {
436      return e.getLocalizedMessage();
437    }
438  }
439
440
441
442  /**
443   * Gets the Configuration object representing this file. The current
444   * configuration is stored in config/config.ldif.
445   *
446   * @return Configuration representing the current configuration.
447   */
448  public Configuration getCurrentConfiguration()
449  {
450    if (configuration == null)
451    {
452      configuration = new Configuration(this, getCurrentConfigurationFile());
453    }
454    return configuration;
455  }
456
457
458
459  /**
460   * Gets the Configuration object representing this file. The base
461   * configuration is stored in config/upgrade/config.ldif.[svn rev].
462   *
463   * @return Configuration object representing the base configuration.
464   * @throws ApplicationException
465   *           if there was a problem determining the svn rev number.
466   */
467  public Configuration getBaseConfiguration() throws ApplicationException
468  {
469    if (baseConfiguration == null)
470    {
471      baseConfiguration = new Configuration(this, getBaseConfigurationFile());
472    }
473    return baseConfiguration;
474  }
475
476
477
478  /**
479   * Gets the current status of this installation.
480   *
481   * @return Status object representing the state of this installation.
482   */
483  public Status getStatus()
484  {
485    if (status == null)
486    {
487      status = new Status(this);
488    }
489    return status;
490  }
491
492
493
494  /**
495   * Returns the path to the libraries.
496   *
497   * @return the path to the libraries.
498   */
499  public File getLibrariesDirectory()
500  {
501    return new File(getRootDirectory(), LIBRARIES_PATH_RELATIVE);
502  }
503
504
505
506  /**
507   * Returns the path to the resources directory.
508   *
509   * @return the path to the resources directory.
510   */
511  public File getResourcesDirectory()
512  {
513    return new File(getRootDirectory(), RESOURCES_PATH_RELATIVE);
514  }
515
516
517
518  /**
519   * Returns the path to the classes directory.
520   *
521   * @return the path to the classes directory.
522   */
523  public File getClassesDirectory()
524  {
525    return new File(getRootDirectory(), CLASSES_PATH_RELATIVE);
526  }
527
528
529
530  /**
531   * Creates a File object representing config/upgrade/schema.ldif.current which
532   * the server creates the first time it starts if there are schema
533   * customizations.
534   *
535   * @return File object with no
536   */
537  public File getSchemaConcatFile()
538  {
539    return new File(getConfigurationUpgradeDirectory(), "schema.ldif.current");
540  }
541
542
543
544  /**
545   * Creates a File object representing config/upgrade/schema.ldif.current which
546   * the server creates the first time it starts if there are schema
547   * customizations.
548   *
549   * @return File object with no
550   * @throws ApplicationException
551   *           if there was a problem determining the svn revision number
552   */
553  public File getBaseSchemaFile() throws ApplicationException
554  {
555    return new File(getConfigurationUpgradeDirectory(),
556        "schema.ldif." + getInstanceSvnRev());
557  }
558
559
560
561  /**
562   * Creates a File object representing config/upgrade/schema.ldif.current which
563   * the server creates the first time it starts if there are schema
564   * customizations.
565   *
566   * @return File object with no
567   * @throws ApplicationException
568   *           if there was a problem determining the svn revision number
569   */
570  public File getBaseConfigurationFile() throws ApplicationException
571  {
572    return new File(getConfigurationUpgradeDirectory(),
573        BASE_CONFIG_FILE_PREFIX + getInstanceSvnRev());
574  }
575
576
577
578  /**
579   * Gets the SVN revision number of the build.
580   *
581   * @return Integer representing the svn number
582   * @throws ApplicationException
583   *           if for some reason the number could not be determined
584   */
585  public Integer getSvnRev() throws ApplicationException
586  {
587    BuildInformation bi = getBuildInformation();
588    return bi.getRevisionNumber();
589  }
590
591
592
593  /**
594   * Gets the SVN revision number of the instance.
595   *
596   * @return Integer representing the svn number
597   * @throws ApplicationException
598   *           if for some reason the number could not be determined
599   */
600  public Integer getInstanceSvnRev() throws ApplicationException
601  {
602    BuildInformation bi = getInstanceBuildInformation();
603    return bi.getRevisionNumber();
604  }
605
606
607
608  /**
609   * Returns the path to the configuration file of the directory server. Note
610   * that this method assumes that this code is being run locally.
611   *
612   * @return the path of the configuration file of the directory server.
613   */
614  public File getCurrentConfigurationFile()
615  {
616    return new File(getConfigurationDirectory(), CURRENT_CONFIG_FILE_NAME);
617  }
618
619
620
621  /**
622   * Returns the relative path of the directory containing the binaries/scripts
623   * of the Open DS installation. The path is relative to the installation path.
624   *
625   * @return the relative path of the directory containing the binaries/scripts
626   *         of the Open DS installation.
627   */
628  public File getBinariesDirectory()
629  {
630    String binDir = isWindows() ? WINDOWS_BINARIES_PATH_RELATIVE : UNIX_BINARIES_PATH_RELATIVE;
631    return new File(getRootDirectory(), binDir);
632  }
633
634
635
636  /**
637   * Returns the path to the database files under the install path.
638   *
639   * @return the path to the database files under the install path.
640   */
641  public File getDatabasesDirectory()
642  {
643    return new File(getInstanceDirectory(), DATABASES_PATH_RELATIVE);
644  }
645
646
647
648  /**
649   * Returns the path to the backup files under the install path.
650   *
651   * @return the path to the backup files under the install path.
652   */
653  public File getBackupDirectory()
654  {
655    return new File(getInstanceDirectory(), BACKUPS_PATH_RELATIVE);
656  }
657
658
659
660  /**
661   * Returns the path to the config files under the install path.
662   *
663   * @return the path to the config files under the install path.
664   */
665  public File getConfigurationDirectory()
666  {
667    return new File(getInstanceDirectory(), CONFIG_PATH_RELATIVE);
668  }
669
670
671
672  /**
673   * Returns the path to the log files under the install path.
674   *
675   * @return the path to the log files under the install path.
676   */
677  public File getLogsDirectory()
678  {
679    return new File(getInstanceDirectory(), LOGS_PATH_RELATIVE);
680  }
681
682
683
684  /**
685   * Returns the directory where the lock files are stored.
686   *
687   * @return the path to the lock files.
688   */
689  public File getLocksDirectory()
690  {
691    return new File(getInstanceDirectory(), LOCKS_PATH_RELATIVE);
692  }
693
694
695
696  /**
697   * Gets the directory used to store the template configuration.
698   *
699   * @return The directory used to store the template configuration.
700   */
701  public File getTemplateDirectory()
702  {
703    return new File(getRootDirectory(), TEMPLATE_RELATIVE_PATH);
704  }
705
706
707
708  /**
709   * Gets the directory used to store files temporarily.
710   *
711   * @return File temporary directory
712   */
713  public File getTemporaryDirectory()
714  {
715    return new File(getInstanceDirectory(), TMP_PATH_RELATIVE);
716  }
717
718
719
720  /**
721   * Returns the directory where the lock files are stored.
722   *
723   * @return the path to the lock files.
724   */
725  public File getHistoryDirectory()
726  {
727    return new File(getInstanceDirectory(), HISTORY_PATH_RELATIVE);
728  }
729
730
731
732  /**
733   * Creates a new directory in the history directory appropriate for backing up
734   * an installation during an upgrade.
735   *
736   * @return File representing a new backup directory. The directory can be
737   *         assumed to exist if this method returns cleanly.
738   * @throws IOException
739   *           if an error occurred creating the directory.
740   */
741  public File createHistoryBackupDirectory() throws IOException
742  {
743    File backupDirectory = new File(getHistoryDirectory(), Long.toString(System
744        .currentTimeMillis()));
745    if (backupDirectory.exists())
746    {
747      backupDirectory.delete();
748    }
749    if (!backupDirectory.mkdirs())
750    {
751      throw new IOException("failed to create history backup directory");
752    }
753    return backupDirectory;
754  }
755
756
757
758  /**
759   * Gets the log file where the history of upgrades and reversions is kept.
760   *
761   * @return File containing upgrade/reversion history.
762   */
763  public File getHistoryLogFile()
764  {
765    return new File(getHistoryDirectory(), HISTORY_LOG_FILE_NAME);
766  }
767
768
769
770  /**
771   * Gets the directory config/upgrade.
772   *
773   * @return File representing the config/upgrade directory
774   */
775  public File getConfigurationUpgradeDirectory()
776  {
777    return new File(getConfigurationDirectory(), UPGRADE_PATH);
778  }
779
780
781
782  /**
783   * Gets the directory where the upgrader stores files temporarily.
784   *
785   * @return File representing the upgrader's temporary directory
786   */
787  public File getTemporaryUpgradeDirectory()
788  {
789    return new File(getTemporaryDirectory(), UPGRADE_PATH);
790  }
791
792
793
794  /**
795   * Gets the file for invoking a particular command appropriate for the current
796   * operating system.
797   *
798   * @param command
799   *          name of the command
800   * @return File representing the command
801   */
802  public File getCommandFile(String command)
803  {
804    String filename = isWindows() ? command + ".bat" : command;
805    return new File(getBinariesDirectory(), filename);
806  }
807
808
809
810  /**
811   * Gets the file responsible for stopping the server appropriate for the
812   * current operating system.
813   *
814   * @return File representing the stop command
815   */
816  public File getServerStartCommandFile()
817  {
818    String startFileName = isWindows() ? WINDOWS_START_FILE_NAME : UNIX_START_FILE_NAME;
819    return new File(getBinariesDirectory(), startFileName);
820  }
821
822
823
824  /**
825   * Gets the file responsible for stopping the server appropriate for the
826   * current operating system.
827   *
828   * @return File representing the stop command
829   */
830  public File getServerStopCommandFile()
831  {
832    String stopFileName = isWindows() ? WINDOWS_STOP_FILE_NAME : UNIX_STOP_FILE_NAME;
833    return new File(getBinariesDirectory(), stopFileName);
834  }
835
836
837
838  /**
839   * Returns the 'ldif' directory.
840   *
841   * @return the 'ldif' directory.
842   */
843  public File getLdifDirectory()
844  {
845    return new File(getRootDirectory(), LDIFS_PATH_RELATIVE);
846  }
847
848
849
850  /**
851   * Returns the path to the quicksetup jar file.
852   *
853   * @return the path to the quicksetup jar file.
854   */
855  public File getQuicksetupJarFile()
856  {
857    return new File(getLibrariesDirectory(), "quicksetup.jar");
858  }
859
860
861
862  /**
863   * Returns the path to the opends jar file.
864   *
865   * @return the path to the opends jar file.
866   */
867  public File getOpenDSJarFile()
868  {
869    return new File(getLibrariesDirectory(), "OpenDJ.jar");
870  }
871
872
873
874  /**
875   * Returns the path to the uninstall.bat file.
876   *
877   * @return the path to the uninstall.bat file.
878   */
879  public File getUninstallBatFile()
880  {
881    return new File(getRootDirectory(), "uninstall.bat");
882  }
883
884
885
886  /**
887   * Gets the control panel command file appropriate for the current operating
888   * system.
889   *
890   * @return File object representing the control panel command
891   */
892  public File getControlPanelCommandFile()
893  {
894    if (isWindows())
895    {
896      return new File(getBinariesDirectory(), WINDOWS_CONTROLPANEL_FILE_NAME);
897    }
898    else if (isMacOS())
899    {
900      String binDir = getRootDirectory() + File.separator + MAC_APPLICATIONS_PATH_RELATIVE;
901      return new File(binDir, MAC_CONTROLPANEL_FILE_NAME);
902    }
903    else
904    {
905      return new File(getBinariesDirectory(), UNIX_CONTROLPANEL_FILE_NAME);
906    }
907  }
908
909
910
911   /**
912   * Gets information about the build that was used to produce the bits for this
913   * installation.
914   *
915   * @return BuildInformation object describing this installation
916   * @throws ApplicationException
917   *           if there is a problem obtaining the build information
918   */
919  public BuildInformation getBuildInformation() throws ApplicationException
920  {
921    return getBuildInformation(true);
922  }
923
924
925
926  /**
927   * Gets information about the build that was used to produce the bits for this
928   * installation.
929   *
930   * @param useCachedVersion
931   *          where true indicates that a potentially cached version of the
932   *          build information is acceptable for use; false indicates the the
933   *          build information will be created from scratch which is
934   *          potentially time consuming
935   * @return BuildInformation object describing this installation
936   * @throws ApplicationException
937   *           if there is a problem obtaining the build information
938   */
939  public BuildInformation getBuildInformation(boolean useCachedVersion)
940      throws ApplicationException
941  {
942    if (buildInformation == null || !useCachedVersion)
943    {
944      FutureTask<BuildInformation> ft = new FutureTask<>(
945          new Callable<BuildInformation>()
946          {
947            @Override
948            public BuildInformation call() throws ApplicationException
949            {
950              return BuildInformation.create(Installation.this);
951            }
952          });
953      new Thread(ft).start();
954      try
955      {
956        buildInformation = ft.get();
957      }
958      catch (InterruptedException e)
959      {
960        logger.info(LocalizableMessage.raw("interrupted trying to get build information", e));
961      }
962      catch (ExecutionException e)
963      {
964        throw (ApplicationException) e.getCause();
965      }
966    }
967    return buildInformation;
968  }
969
970
971
972  /**
973   * Gets information about the build that was used to produce the instance.
974   *
975   * @return BuildInformation object describing this instance
976   */
977  public BuildInformation getInstanceBuildInformation()
978  {
979    return getInstanceBuildInformation(true);
980  }
981
982
983
984  /**
985   * Gets information about the build that was used to produce the instance.
986   *
987   * @param useCachedVersion
988   *          where true indicates that a potentially cached version of the
989   *          build information is acceptable for use; false indicates the build
990   *          information will be created from scratch which is potentially time
991   *          consuming
992   * @return BuildInformation object describing this instance
993   */
994  public BuildInformation getInstanceBuildInformation(boolean useCachedVersion)
995  {
996    if (instanceInformation == null || !useCachedVersion)
997    {
998      try
999      {
1000        File bif = new File(getConfigurationDirectory(), BUILDINFO_RELATIVE_PATH);
1001        if (bif.exists())
1002        {
1003          // Read the first line and close the file.
1004          try (BufferedReader reader = new BufferedReader(new FileReader(bif)))
1005          {
1006            String line = reader.readLine();
1007            instanceInformation = BuildInformation.fromBuildString(line);
1008          }
1009        }
1010        else
1011        {
1012          return getBuildInformation();
1013        }
1014      }
1015      catch (Exception e)
1016      {
1017        logger.error(LocalizableMessage.raw("error getting build information for current instance", e));
1018      }
1019    }
1020    return instanceInformation;
1021  }
1022}