/**
* Copyright (C) 2012-2013 Selventa, Inc.
*
* This file is part of the OpenBEL Framework.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The OpenBEL Framework is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the OpenBEL Framework. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms under LGPL v3:
*
* This license does not authorize you and you are prohibited from using the
* name, trademarks, service marks, logos or similar indicia of Selventa, Inc.,
* or, in the discretion of other licensors or authors of the program, the
* name, trademarks, service marks, logos or similar indicia of such authors or
* licensors, in any marketing or advertising materials relating to your
* distribution of the program or any covered product. This restriction does
* not waive or limit your obligation to keep intact all copyright notices set
* forth in the program as delivered to you.
*
* If you distribute the program in whole or in part, or any modified version
* of the program, and you assume contractual liability to the recipient with
* respect to the program or modified version, then you will indemnify the
* authors and licensors of the program for any liabilities that these
* contractual assumptions directly impose on those licensors and authors.
*/
package org.openbel.framework.common.cfg;
import static java.lang.System.*;
import static org.openbel.framework.common.BELUtilities.asPath;
import static org.openbel.framework.common.PathConstants.*;
import static org.openbel.framework.common.Strings.*;
import static org.openbel.framework.common.enums.ExitCode.MISSING_SYSTEM_CONFIGURATION;
import static org.openbel.framework.common.enums.ExitCode.UNRECOVERABLE_ERROR;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.openbel.framework.common.BELRuntimeException;
import org.openbel.framework.common.PathConstants;
/**
* Provides system configuration capabilities.
* <p>
* Two types of configuration exist within the BEL framework, system
* configuration and {@link RuntimeConfiguration runtime configuration}. System
* configuration allows access and modification of settings that affect the
* system's behavior, i.e., the installation of the BEL framework.
* </p>
*
* @version 3.0.0
*/
public final class SystemConfiguration extends Configuration {
private static SystemConfiguration self;
/**
* KAM URL setting name: {@value #KAMSTORE_URL_DESC}
*/
public static final String KAMSTORE_URL_DESC = "kamstore_url";
/**
* KAM user setting name: {@value #KAMSTORE_USER_DESC}
*/
public static final String KAMSTORE_USER_DESC = "kamstore_user";
/**
* KAM password setting name: {@value #KAMSTORE_PASSWORD_DESC}
*/
public static final String KAMSTORE_PASSWORD_DESC = "kamstore_password";
/**
* KAM password setting name: {@value #SYSTEM_MANAGED_SCHEMAS}
*/
public static final String SYSTEM_MANAGED_SCHEMAS =
"system_managed_schemas";
/**
* KamStore catalog schema setting name:
* {@value #KAMSTORE_CATALOG_SCHEMA_DESC}
*/
public static final String KAMSTORE_CATALOG_SCHEMA_DESC =
"kamstore_catalog_schema";
/**
* KamStore KAM schema prefix setting name:
* {@value #KAMSTORE_SCHEMA_PREFIX_DESC}
*/
public static final String KAMSTORE_SCHEMA_PREFIX_DESC =
"kamstore_schema_prefix";
/**
* Framework working area: {@value #FRAMEWORK_WORKING_AREA_DESC}
*/
public static final String FRAMEWORK_WORKING_AREA_DESC =
"belframework_work";
/**
* Framework cache directory setting name:
* {@value #FRAMEWORK_CACHE_DIRECTORY_DESC}
*/
public static final String FRAMEWORK_CACHE_DIRECTORY_DESC =
"belframework_cache";
/**
* Application log path: {@value #APPLICATION_LOG_PATH_DESC}
*/
public static final String APPLICATION_LOG_PATH_DESC =
"application_log_path";
/**
* URL to the BELFramework resource index: {@value #RESOURCE_INDEX_URL_DESC}
*/
public static final String RESOURCE_INDEX_URL_DESC =
"resource_index_url";
/**
* Location of BEL Templates (for BELWorkbench document creation):
* {@value #BEL_TEMPLATE_LOCATION}
*
* @deprecated Deprecated as of version 3.0.0; no equivalent replacement
*/
@Deprecated
public static final String BEL_TEMPLATE_LOCATION = "beltemplate_path";
/**
* Defines the default value, {@value} , for the
* {@value #KAMSTORE_CATALOG_SCHEMA_DESC} setting.
*/
public static final String DEFAULT_KAM_CATALOG_SCHEMA = "kam_catalog";
/**
* Defines the default value, {@value} , for the
* {@value #KAMSTORE_SCHEMA_PREFIX_DESC} setting.
*/
private static final String DEFAULT_KAM_SCHEMA_PREFIX = "kam";
/**
* Defines the default value, {@value} , for the
* {@value #SYSTEM_MANAGED_SCHEMAS} setting.
*/
private static final String DEFAULT_SYSTEM_MANAGED_SCHEMAS = "1";
private String kamURL;
private String kamUser;
private String kamPassword;
private String kamCatalogSchema;
private String kamSchemaPrefix;
private String systemManagedSchemas;
private File configurationFile;
private File workingDirectory;
private File cacheDirectory;
private File applicationLogPath;
private String resourceIndexURL;
private File belTemplateDirectory;
/**
* Creates a system configuration instance.
* <p>
* The configuration file to be used is
* {@link PathConstants#SYSCONFIG_FILENAME} in
* {@link PathConstants#SYS_PATH}.
* </p>
*
* @throws IOException Thrown if an I/O error occurs
*/
private SystemConfiguration() throws IOException {
super(defaultSysCfg());
init();
}
/**
* Creates a system configuration instance, using {@code file} as the
* configuration source.
*
* @param file Configuration file
* @throws IOException Thrown if an I/O error occurs
*/
private SystemConfiguration(final File file) throws IOException {
super(file);
this.configurationFile = file;
init();
}
/**
* Creates a system configuration instance, using {@code map} as the
* configuration source.
*
* @param map Map of string name-values
*/
private SystemConfiguration(final Map<String, String> map) {
super(map);
init();
}
/**
* Creates the system configuration as defined by the environment.
*
* @return {@link SystemConfiguration}
* @throws IOException Thrown if an I/O error occurs
*/
public static synchronized SystemConfiguration createSystemConfiguration()
throws IOException {
if (self == null) {
if (getenv(BELFRAMEWORK_HOME_ENV_VAR) == null) {
String err = MISSING_SYSCFG;
err = err.concat(": environment variable not set ");
err = err.concat(BELFRAMEWORK_HOME_ENV_VAR);
throw new IOException(err);
}
self = new SystemConfiguration();
}
return self;
}
/**
* Creates the system configuration from the provided file, which may be
* null.
*
* @param file System configuration file, which may be null
* @return {@link SystemConfiguration}
* @throws IOException Thrown if an I/O error occurs
*/
public static synchronized SystemConfiguration createSystemConfiguration(
final File file) throws IOException {
if (self == null) {
if (file == null) {
if (getenv(BELFRAMEWORK_HOME_ENV_VAR) == null) {
String err = MISSING_SYSCFG;
err = err.concat(": environment variable not set ");
err = err.concat(BELFRAMEWORK_HOME_ENV_VAR);
throw new IOException(err);
}
self = new SystemConfiguration();
} else {
self = new SystemConfiguration(file);
}
}
return self;
}
/**
* Creates the system configuration from the provided map.
* <p>
*
* <pre>
* <code>
* map.put(KAMSTORE_URL_DESC, "mysql://...");
* map.put(FRAMEWORK_WORKING_AREA_DESC, "{home}/BEL_Framework");
* createSystemConfiguration(map);
* </code>
* </pre>
*
* </p>
*
* @param map Map of string name-values
* @return {@link SystemConfiguration}
* @see #APPLICATION_LOG_PATH_DESC
* @see #FRAMEWORK_CACHE_DIRECTORY_DESC
* @see #FRAMEWORK_WORKING_AREA_DESC
* @see #KAMSTORE_CATALOG_SCHEMA_DESC
* @see #KAMSTORE_PASSWORD_DESC
* @see #KAMSTORE_SCHEMA_PREFIX_DESC
* @see #KAMSTORE_URL_DESC
* @see #KAMSTORE_USER_DESC
* @see #RESOURCE_INDEX_URL_DESC
* @see #SYSTEM_MANAGED_SCHEMAS
*/
public static synchronized SystemConfiguration createSystemConfiguration(
final Map<String, String> map) {
if (self == null) {
self = new SystemConfiguration(map);
}
return self;
}
/**
* Returns the system configuration.
* <p>
* It is an error to access the system configuration before it has been
* created. As a result, this method throws {@link IllegalStateException} to
* indicate this has occurred.
* </p>
*
* @return {@link SystemConfiguration}
* @see #createSystemConfiguration(File)
* @throws IllegalStateException Thrown if no system configuration has been
* created
*/
public static synchronized SystemConfiguration getSystemConfiguration() {
if (self == null) {
throw new IllegalStateException(
"System configuration has not been created.");
}
return self;
}
/**
* Destroys the system configuration.
* <p>
* It is an error to destroy the system configuration before it has been
* created. As a result, this method throws {@link IllegalStateException} to
* indicate this has occurred.
* </p>
*
* @see #createSystemConfiguration(File)
*/
protected static synchronized void destroySystemConfiguration() {
if (self == null) {
throw new IllegalStateException(
"System configuration has not been created.");
}
self = null;
}
/**
* {@inheritDoc}
*/
@Override
protected void processSetting(String name, String value) {
if (KAMSTORE_URL_DESC.equals(name)) {
kamURL = value;
} else if (KAMSTORE_USER_DESC.equals(name)) {
kamUser = value;
} else if (KAMSTORE_PASSWORD_DESC.equals(name)) {
kamPassword = value;
} else if (KAMSTORE_CATALOG_SCHEMA_DESC.equals(name)) {
kamCatalogSchema = value;
} else if (KAMSTORE_SCHEMA_PREFIX_DESC.equals(name)) {
kamSchemaPrefix = value;
} else if (FRAMEWORK_WORKING_AREA_DESC.equals(name)) {
final String workingPath = asPath(value, NESTED_OUTPUT_DIRECTORY);
workingDirectory = new File(workingPath);
} else if (FRAMEWORK_CACHE_DIRECTORY_DESC.equals(name)) {
cacheDirectory = new File(value);
} else if (APPLICATION_LOG_PATH_DESC.equals(name)) {
applicationLogPath = new File(value);
} else if (RESOURCE_INDEX_URL_DESC.equals(name)) {
resourceIndexURL = value;
} else if (BEL_TEMPLATE_LOCATION.equals(name)) {
belTemplateDirectory = new File(value);
} else if (SYSTEM_MANAGED_SCHEMAS.equals(name)) {
systemManagedSchemas = value;
}
}
/**
* {@inheritDoc}
*/
@Override
protected void initializeDefaults() {
String err = "A BEL Framework system configuration must be present";
if (configurationFile != null) {
err += " (using " + configurationFile + ")";
}
throw new BELRuntimeException(err, MISSING_SYSTEM_CONFIGURATION);
}
/**
* {@inheritDoc}
*/
@Override
protected void readComplete() {
Set<String> unsetStrings = new HashSet<String>();
if (kamURL == null || kamURL.isEmpty()) {
unsetStrings.add(KAMSTORE_URL_DESC);
}
if (resourceIndexURL == null || resourceIndexURL.isEmpty()) {
unsetStrings.add(RESOURCE_INDEX_URL_DESC);
}
if (workingDirectory == null) {
String value = getProperty("java.io.tmpdir");
String pathel2 = DEFAULT_OUTPUT_DIRECTORY;
String pathel3 = NESTED_OUTPUT_DIRECTORY;
value = asPath(value, pathel2, pathel3);
workingDirectory = new File(value);
}
validateOutputPath(workingDirectory);
if (cacheDirectory == null) {
String value = getProperty("user.home");
value = asPath(value, DEFAULT_CACHE_DIRECTORY);
cacheDirectory = new File(value);
}
validateOutputPath(cacheDirectory);
if (applicationLogPath == null) {
String outputPath = workingDirectory.getAbsolutePath();
applicationLogPath = new File(outputPath);
}
validateOutputPath(applicationLogPath);
if (kamCatalogSchema == null) {
kamCatalogSchema = DEFAULT_KAM_CATALOG_SCHEMA;
}
if (kamSchemaPrefix == null) {
kamSchemaPrefix = DEFAULT_KAM_SCHEMA_PREFIX;
}
if (systemManagedSchemas == null) {
systemManagedSchemas = DEFAULT_SYSTEM_MANAGED_SCHEMAS;
}
if (belTemplateDirectory == null) {
String value = getProperty("user.home");
value = asPath(value, DEFAULT_BEL_TEMPLATE_DIRECTORY);
belTemplateDirectory = new File(value);
}
validateOutputPath(belTemplateDirectory);
if (!unsetStrings.isEmpty()) {
final StringBuilder bldr = new StringBuilder();
bldr.append("The configuration file is not complete.");
bldr.append("\n(missing");
for (final String setting : unsetStrings) {
bldr.append(" ");
bldr.append(setting);
}
bldr.append(")");
final String err = bldr.toString();
throw new BELRuntimeException(err, UNRECOVERABLE_ERROR);
}
// Five-by-five.
}
/**
* {@inheritDoc}
*/
@Override
protected Map<String, String> defaults() {
Map<String, String> ret = new HashMap<String, String>();
String value = getProperty("java.io.tmpdir");
value = asPath(value, DEFAULT_OUTPUT_DIRECTORY);
ret.put(FRAMEWORK_WORKING_AREA_DESC, value);
value = getProperty("user.home");
value = asPath(value, DEFAULT_CACHE_DIRECTORY);
ret.put(FRAMEWORK_CACHE_DIRECTORY_DESC, value);
value = getProperty("java.io.tmpdir");
value = asPath(value, DEFAULT_OUTPUT_DIRECTORY);
ret.put(APPLICATION_LOG_PATH_DESC, value);
return ret;
}
/**
* Returns the KAM URL system configuration setting.
*
* @return {@link String}, the KAM store database URL, which cannot be null
*/
public final String getKamURL() {
return kamURL;
}
/**
* Returns the KAM user system configuration setting.
*
* @return {@link String}, the KAM database username, which can be null
*/
public final String getKamUser() {
return kamUser;
}
/**
* Returns the KAM password configuration setting.
*
* @return {@link String}, the KAM database password, which can be null
*/
public final String getKamPassword() {
return kamPassword;
}
/**
* Returns the KAM catalog schema name.
*
* @return {@link String}, the KAM catalog schema name
*/
public final String getKamCatalogSchema() {
return kamCatalogSchema;
}
/**
* Returns the KAM schema prefix.
*
* @return {@link String}, the KAM schema prefix
*/
public final String getKamSchemaPrefix() {
return kamSchemaPrefix;
}
/**
* Returns the framework working directory system configuration setting.
*
* @return Non-null, writable directory
*/
public final File getWorkingDirectory() {
return workingDirectory;
}
/**
* Returns the framework cache directory system configuration setting.
*
* @return Non-null, writable directory
*/
public final File getCacheDirectory() {
return cacheDirectory;
}
/**
* Returns true if the OpenBEL Framework is managing the KAMStore schemas
* false otherwise.
*
* @return Non-null, writable directory
*/
public final boolean getSystemManagedSchemas() {
if ("1".equals(systemManagedSchemas)) {
return true;
}
return false;
}
/**
* Returns the application log path system configuration setting.
*
* @return Non-null, writable directory
*/
public final File getApplicationLogPath() {
return applicationLogPath;
}
/**
* Returns the URL to the OpenBEL Framework resource index.
*
* @return Non-null, string
*/
public String getResourceIndexURL() {
return resourceIndexURL;
}
/**
* Returns the BEL Template directory system configuration setting.
*
* @return Non-null, writable directory
* @deprecated Deprecated as of version 3.0.0; no equivalent replacement
*/
@Deprecated
public final File getBELTemplateDirectory() {
return belTemplateDirectory;
}
private static File defaultSysCfg() {
if (SYS_PATH == null) return null;
return new File(asPath(SYS_PATH.getAbsolutePath(), SYSCONFIG_FILENAME));
}
/**
* Prints the default system configuration.
*
* @param args Ignored command-line arguments
*/
public static void main(String... args) {
final String cfgpath = "../docs/configuration/belframework.cfg";
final File cfgfile = new File(cfgpath);
try {
SystemConfiguration syscfg = createSystemConfiguration(cfgfile);
out.println(syscfg.defaultConfiguration());
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Throws a system configuration error if the {@code path} cannot be written
* to. If {@code path} does not exist, an attempt to create it will be made.
*
* @param path Path for validation
*/
private void validateOutputPath(final File path) {
if (path.canWrite()) return;
// If the path doesn't exist...
if (!path.exists()) {
// ... try creating it...
if (!path.mkdirs()) {
// ... or die trying.
String err = DIRECTORY_CREATION_FAILED.concat(path.toString());
throw new BELRuntimeException(err, UNRECOVERABLE_ERROR);
}
return;
}
// ... can't write to it.
String err = CANT_WRITE_TO_PATH.concat(path.toString());
throw new BELRuntimeException(err, UNRECOVERABLE_ERROR);
}
}