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