// // Copyright 2010 Cinch Logic Pty Ltd. // // http://www.chililog.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package org.chililog.server.common; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.Hashtable; import java.util.Properties; import java.util.UUID; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.WordUtils; /** * <p> * AppProperties provides strongly typed access to configuration information in the <code>app.properties</code> file. * </p> * * <p> * The <code>app.properties</code> file in the classpath contains the default configuration. * </p> * * <p> * For example, if you created the file <code>/usr/local/chililog/config/app.properties</code>, then set the following * JVM option. <code>-Dchililog.config.directory=/usr/local/chililog/config</code>. * </p> * * <h3>Example</h3> * * <pre> * AppProperties.getInstance().getJsonPretty(); * </pre> * * <h3>Property Loading</h3> * * We use convention to load the properties. * <ol> * <li>We search for all fields with upper case letters in their names. For example, <code>APP_NAME<code>.</li> * <li>We search for the corresponding field cache variable. The field name is converted to camel case and prefixed with * underscore. For example, <code>_appName</code></li> * <li>Next, we search for a load method to parse the entry in the property file. The field name is converted to camel * case and prefixed with "load". For example, <code>loadAppName</code></li> * <li>If the method is found, it is called and the result is used to set the cache variable identified in step #2.</li> * </ol> * * * @author vibul * @since 1.0 */ public class AppProperties { private static Log4JLogger _logger = Log4JLogger.getLogger(AppProperties.class); private static final String APP_PROPERTY_FILE_NAME = "app.properties"; /** * Returns the singleton instance for this class */ public static AppProperties getInstance() { return SingletonHolder.INSTANCE; } /** * SingletonHolder is loaded on the first execution of Singleton.getInstance() or the first access to * SingletonHolder.INSTANCE, not before. * * @see http://en.wikipedia.org/wiki/Singleton_pattern */ private static class SingletonHolder { public static final AppProperties INSTANCE = new AppProperties(); } /** * <p> * Singleton constructor that parses and loads the required application properties. * </p> * * <p> * If there are any errors, the JVM is terminated. Without valid application properties, we will fall over elsewhere * so might as well terminate here. * </p> */ private AppProperties() { try { loadProperties(); } catch (Exception e) { _logger.error(e, "Error loading application properties: " + e.getMessage()); System.exit(1); } } /** * <p> * Loads the configuration information from the <code>app.properties</code> file and caches then as strongly typed * values. This method is NOT thread-safe and should only be called for unit-testing. * </p> * * <p> * <code>LoadProperties</code> first loads the default settings form the <code>app.properties</code> file the root * classpath and then any overrides from the <code>app.properties</code> file located in the in directory specified * in the "chililog.config.dir" system property. * </p> * * @throws Exception */ public void loadProperties() throws Exception { Properties properties = readPropertiesFile(); parseProperties(properties); } /** * <p> * Loads the configuration information from the <code>app.properties</code> file. * </p> * * <p> * <code>LoadProperties</code> first loads the default settings form the <code>app.properties</code> file the root * classpath and then any overrides from the <code>app.properties</code> file located in the in directory specified * in the "chililog.config.dir" system property. * </p> * * @throws IOException * @throws FileNotFoundException */ static Properties readPropertiesFile() throws FileNotFoundException, IOException { FileInputStream fis = null; try { Properties properties = new Properties(); // Load default from class path InputStream is = AppProperties.class.getClassLoader().getResourceAsStream(APP_PROPERTY_FILE_NAME); if (is == null) { throw new FileNotFoundException("'app.properties' file not found in classpath"); } properties.load(is); is.close(); return properties; } finally { if (fis != null) { fis.close(); } } } /** * <p> * Parses the properties into strongly typed class fields. * </p> * * <p> * Use reflection to simulate the likes of: <code>_appName = loadAppName(properties);</code> * </p> * * @param properties * Properties to parse * @throws Exception */ private void parseProperties(Properties properties) throws Exception { Class<AppProperties> cls = AppProperties.class; Field[] ff = cls.getDeclaredFields(); for (Field f : ff) { // Look for field names like APP_NAME String propertyNameFieldName = f.getName(); if (!propertyNameFieldName.matches("^[A-Z0-9_]+$")) { continue; } // Build cache field (_appName) and method (loadAppName) methods String baseName = WordUtils.capitalizeFully(propertyNameFieldName, new char[] { '_' }); baseName = baseName.replace("_", ""); String cacheMethodName = "load" + baseName; String cacheFieldName = "_" + StringUtils.uncapitalize(baseName); // If field not exist, then skip Field cacheField = null; try { cacheField = cls.getDeclaredField(cacheFieldName); } catch (NoSuchFieldException e) { continue; } // Get and set the value Method m = cls.getDeclaredMethod(cacheMethodName, Properties.class); Object cacheValue = m.invoke(null, properties); cacheField.set(this, cacheValue); } return; } // ***************************************************************************************************************** // ***************************************************************************************************************** // Miscellaneous // ***************************************************************************************************************** // ***************************************************************************************************************** /** * If true, JSON serialization is to be human readable. If false, white spaces will be eliminated. */ public boolean getJsonPretty() { return _jsonPretty; } static final String JSON_PRETTY = "json.pretty"; private boolean _jsonPretty = false; static boolean loadJsonPretty(Properties properties) { return loadBoolean(properties, JSON_PRETTY, false); } // ***************************************************************************************************************** // ***************************************************************************************************************** // Database // ***************************************************************************************************************** // ***************************************************************************************************************** /** * Returns the IP address of the mongoDB Database Server */ public String getDbIpAddress() { return _dbIpAddress; } static final String DB_IP_ADDRESS = "db.ip_address"; private String _dbIpAddress = null; static String loadDbIpAddress(Properties properties) { return loadString(properties, DB_IP_ADDRESS); } /** * Returns the IP port that the mongoDB Database Server is listening on. Defaults to 27017 if not set. */ public int getDbIpPort() { return _dbIpPort; } static final String DB_IP_PORT = "db.ip_port"; private int _dbIpPort = 0; static int loadDbIpPort(Properties properties) { return loadInt(properties, DB_IP_PORT, 27017); } /** * Returns the name of the database within the mongoDB server to use */ public String getDbName() { return _dbName; } static final String DB_NAME = "db.name"; private String _dbName = null; static String loadDbName(Properties properties) { return loadString(properties, DB_NAME); } /** * Returns the usename to use for authenticating of the mongoDB database */ public String getDbUserName() { return _dbUserName; } static final String DB_USER_NAME = "db.username"; private String _dbUserName = null; static String loadDbUserName(Properties properties) { return loadString(properties, DB_USER_NAME); } /** * Returns the password to use for authenticating of the mongoDB database */ public String getDbPassword() { return _dbPassword; } static final String DB_PASSWORD = "db.password"; private String _dbPassword = null; static String loadDbPassword(Properties properties) { return loadString(properties, DB_PASSWORD); } /** * Returns the number of connections per host. The default is 10. */ public int getDbConnectionsPerHost() { return _dbConnectionsPerHost; } static final String DB_CONNECTIONS_PER_HOST = "db.connections_per_host"; private int _dbConnectionsPerHost = 0; static int loadDbConnectionsPerHost(Properties properties) { return loadInt(properties, DB_CONNECTIONS_PER_HOST, 10); } // ***************************************************************************************************************** // ***************************************************************************************************************** // Message Queue // ***************************************************************************************************************** // ***************************************************************************************************************** /** * Returns The name of the ChiliLog system user. This auto-create user will have permission to manage all aspects of * ChiliLog. If it is not set, then we generate a random one. It should be set for load-balanced installations. */ public String getMqSystemUsername() { return _mqSystemUsername; } static final String MQ_SYSTEM_USERNAME = "mq.system_username"; private String _mqSystemUsername = null; static String loadMqSystemUsername(Properties properties) { String s = loadString(properties, MQ_SYSTEM_USERNAME, StringUtils.EMPTY); if (StringUtils.isBlank(s)) { s = "systemuser_" + UUID.randomUUID().toString(); } return s; } /** * Returns The password of the ChiliLog system user. This auto-create user will have permission to manage all * aspects of ChiliLog. If it is not set, then we generate a random one. */ public String getMqSystemPassword() { return _mqSystemPassword; } static final String MQ_SYSTEM_PASSWORD = "mq.system_password"; private String _mqSystemPassword = null; static String loadMqSystemPassword(Properties properties) { String s = loadString(properties, MQ_SYSTEM_PASSWORD, StringUtils.EMPTY); if (StringUtils.isBlank(s)) { s = UUID.randomUUID().toString(); } return s; } /** * Returns Flag to indicate if journalling is enabled or not. If so, then messages from message queues flagged as * durable will be persisted (or journalled). Default is false. */ public boolean getMqJournallingEnabled() { return _mqJournallingEnabled; } static final String MQ_JOURNALLING_ENABLED = "mq.journalling_enabled"; private boolean _mqJournallingEnabled = false; static boolean loadMqJournallingEnabled(Properties properties) { return loadBoolean(properties, MQ_JOURNALLING_ENABLED, false); } /** * Returns the directory to store journal files */ public String getMqJournalDirectory() { return _mqJournalDirectory; } static final String MQ_JOURNAL_DIRECTORY = "mq.journal_directory"; private String _mqJournalDirectory = null; static String loadMqJournalDirectory(Properties properties) { String s = loadString(properties, MQ_JOURNAL_DIRECTORY); return s; } /** * Returns the directory to store paging files. */ public String getMqPagingDirectory() { return _mqPagingDirectory; } static final String MQ_PAGING_DIRECTORY = "mq.paging_directory"; private String _mqPagingDirectory = null; static String loadMqPagingDirectory(Properties properties) { String s = loadString(properties, MQ_PAGING_DIRECTORY); return s; } /** * Returns the time period in milliseconds during which an authenticated user is valid and credentials will not be * validated by calling JAAS. Defaults to 10000 (10 seconds). */ public int getMqSecurityInvalidationInterval() { return _mqSecurityInvalidationInterval; } static final String MQ_SECURITY_INVALIDATION_INTERVAL = "mq.security_invalidation_interval"; private int _mqSecurityInvalidationInterval = 10000; static int loadMqSecurityInvalidationInterval(Properties properties) { int i = loadInt(properties, MQ_SECURITY_INVALIDATION_INTERVAL, 10000); return i; } /** * Returns Flag to indicate if message queue clustering is to be used. Default is false. */ public boolean getMqClusteredEnabled() { return _mqClusteredEnabled; } static final String MQ_CLUSTERED_ENABLED = "mq.clustered_enabled"; private boolean _mqClusteredEnabled = false; static boolean loadMqClusteredEnabled(Properties properties) { return loadBoolean(properties, MQ_CLUSTERED_ENABLED, false); } /** * Returns the maximum number of delivery attempts that will be made before a message is deleted or placed on the * dead letter queue. A message is catergorised as failed if it has been acknowledge AND its transactional session * is rolled back. */ public int getMqRedeliveryMaxAttempts() { return _mqRedeliveryMaxAttempts; } static final String MQ_REDELIVERY_MAX_ATTEMPTS = "mq.redelivery.max_attempts"; private int _mqRedeliveryMaxAttempts = -1; static int loadMqRedeliveryMaxAttempts(Properties properties) { return loadInt(properties, MQ_REDELIVERY_MAX_ATTEMPTS); } /** * Returns the number of milliseconds before a re-delivery of a failed message is made. */ public int getMqRedeliveryDelayMilliseconds() { return _mqRedeliveryDelayMilliseconds; } static final String MQ_REDELIVERY_DELAY_MILLISECONDS = "mq.redelivery.delay_milliseconds"; private int _mqRedeliveryDelayMilliseconds = -1; static int loadMqRedeliveryDelayMilliseconds(Properties properties) { return loadInt(properties, MQ_REDELIVERY_DELAY_MILLISECONDS); } /** * Returns the address to send for undelivered messages */ public String getMqDeadLetterAddress() { return _mqDeadLetterAddress; } static final String MQ_DEAD_LETTER_ADDRESS = "mq.dead_letter_address"; private String _mqDeadLetterAddress = null; static String loadMqDeadLetterAddress(Properties properties) { return loadString(properties, MQ_DEAD_LETTER_ADDRESS, null); } // ***************************************************************************************************************** // ***************************************************************************************************************** // PUB SUB // ***************************************************************************************************************** // ***************************************************************************************************************** /** * Returns Flag to indicate if the message queue HornetQ and JMS protocols are to be enabled for pubsub use */ public boolean getPubSubCoreProtocolEnabled() { return _pubSubCoreProtocolEnabled; } static final String PUB_SUB_CORE_PROTOCOL_ENABLED = "pubsub.core.enabled"; private boolean _pubSubCoreProtocolEnabled = false; static boolean loadPubSubCoreProtocolEnabled(Properties properties) { return loadBoolean(properties, PUB_SUB_CORE_PROTOCOL_ENABLED, false); } /** * Returns configuration settings for the message queue HornetQ and JMS protocols */ public Hashtable<String, Object> getPubSubCoreProtocolConfig() { return _pubSubCoreProtocolConfig; } static final String PUB_SUB_CORE_PROTOCOL_CONFIG = "pubsub.core."; private Hashtable<String, Object> _pubSubCoreProtocolConfig = null; static Hashtable<String, Object> loadPubSubCoreProtocolConfig(Properties properties) { Hashtable<String, Object> m = new Hashtable<String, Object>(); for (Object key : properties.keySet()) { String keyAsString = (String) key; if (keyAsString.startsWith(PUB_SUB_CORE_PROTOCOL_CONFIG) && !keyAsString.equalsIgnoreCase("pubsub.core.enabled")) { String value = properties.getProperty(keyAsString); if (!StringUtils.isBlank(value)) { m.put(keyAsString.substring(PUB_SUB_CORE_PROTOCOL_CONFIG.length()), value); } } } return m; } /** * Returns Flag to indicate if the JSON HTTP protocol is to be enabled for pubsub use */ public boolean getPubSubJsonHttpEnabled() { return _pubSubJsonHttpEnabled; } static final String PUB_SUB_JSON_HTTP_ENABLED = "pubsub.json-http.enabled"; private boolean _pubSubJsonHttpEnabled = false; static boolean loadPubSubJsonHttpEnabled(Properties properties) { return loadBoolean(properties, PUB_SUB_JSON_HTTP_ENABLED, false); } /** * Returns the IP address to use for binding our UI web server */ public String getPubSubJsonHttpHost() { return _pubSubJsonHttpHost; } static final String PUB_SUB_JSON_HTTP_HOST = "pubsub.json-http.host"; private String _pubSubJsonHttpHost = null; static String loadPubSubJsonHttpHost(Properties properties) { return loadString(properties, PUB_SUB_JSON_HTTP_HOST); } /** * Returns the IP port to use for binding our UI web server */ public int getPubSubJsonHttpPort() { return _pubSubJsonHttpPort; } static final String PUB_SUB_JSON_HTTP_PORT = "pubsub.json-http.port"; private int _pubSubJsonHttpPort = 0; static int loadPubSubJsonHttpPort(Properties properties) { return loadInt(properties, PUB_SUB_JSON_HTTP_PORT, 61615); } /** * Returns the maximum number of active threads used by netty to execute our handler */ public int getPubSubJsonHttpNettyWorkerThreadPoolSize() { return _pubSubJsonHttpNettyWorkerThreadPoolSize; } static final String PUB_SUB_JSON_HTTP_NETTY_WORKER_THREAD_POOL_SIZE = "pubsub.json-http.netty_worker_thread_pool.size"; private int _pubSubJsonHttpNettyWorkerThreadPoolSize = 0; static int loadPubSubJsonHttpNettyWorkerThreadPoolSize(Properties properties) { return loadInt(properties, PUB_SUB_JSON_HTTP_NETTY_WORKER_THREAD_POOL_SIZE, 0); } /** * Returns the maximum number of active threads used by netty to execute our handler */ public int getPubSubJsonHttpNettyHandlerThreadPoolSize() { return _pubSubJsonHttpNettyHandlerThreadPoolSize; } static final String PUB_SUB_JSON_HTTP_NETTY_HANDLER_THREAD_POOL_SIZE = "pubsub.json-http.netty_handler_thread_pool.size"; private int _pubSubJsonHttpNettyHandlerThreadPoolSize = 0; static int loadPubSubJsonHttpNettyHandlerThreadPoolSize(Properties properties) { return loadInt(properties, PUB_SUB_JSON_HTTP_NETTY_HANDLER_THREAD_POOL_SIZE, 16); } /** * Returns Flag to indicate if the SSL is to be supported */ public boolean getPubSubJsonHttpSslEnabled() { return _pubSubJsonHttpSslEnabled; } static final String PUB_SUB_JSON_HTTP_SSL_ENABLED = "pubsub.json-http.ssl_enabled"; private boolean _pubSubJsonHttpSslEnabled = false; static boolean loadPubSubJsonHttpSslEnabled(Properties properties) { return loadBoolean(properties, PUB_SUB_JSON_HTTP_SSL_ENABLED, false); } /** * Returns the path to the key store to use for SSL */ public String getPubSubJsonHttpKeyStorePath() { return _pubSubJsonHttpKeyStorePath; } static final String PUB_SUB_JSON_HTTP_KEY_STORE_PATH = "pubsub.json-http.key_store_path"; private String _pubSubJsonHttpKeyStorePath = null; static String loadPubSubJsonHttpKeyStorePath(Properties properties) { return loadString(properties, PUB_SUB_JSON_HTTP_KEY_STORE_PATH, null); } /** * Returns the password to the key store to use for SSL */ public String getPubSubJsonHttpKeyStorePassword() { return _pubSubJsonHttpKeyStorePassword; } static final String PUB_SUB_JSON_HTTP_KEY_STORE_PASSWORD = "pubsub.json-http.key_store_password"; private String _pubSubJsonHttpKeyStorePassword = null; static String loadPubSubJsonHttpKeyStorePassword(Properties properties) { return loadString(properties, PUB_SUB_JSON_HTTP_KEY_STORE_PASSWORD, null); } /** * Returns the password to the key inside to the key store to use for SSL */ public String getPubSubJsonHttpKeyStoreKeyPassword() { return _pubSubJsonHttpKeyStoreKeyPassword; } static final String PUB_SUB_JSON_HTTP_KEY_STORE_KEY_PASSWORD = "pubsub.json-http.key_store_key_password"; private String _pubSubJsonHttpKeyStoreKeyPassword = null; static String loadPubSubJsonHttpKeyStoreKeyPassword(Properties properties) { return loadString(properties, PUB_SUB_JSON_HTTP_KEY_STORE_KEY_PASSWORD, null); } /** * Returns the path to the trust store to use for SSL */ public String getPubSubJsonHttpTrustStorePath() { return _pubSubJsonHttpTrustStorePath; } static final String PUB_SUB_JSON_HTTP_TRUST_STORE_PATH = "pubsub.json-http.trust_store_path"; private String _pubSubJsonHttpTrustStorePath = null; static String loadPubSubJsonHttpTrustStorePath(Properties properties) { return loadString(properties, PUB_SUB_JSON_HTTP_TRUST_STORE_PATH, null); } /** * Returns the password to the trust store to use for SSL */ public String getPubSubJsonHttpTrustStorePassword() { return _pubSubJsonHttpTrustStorePassword; } static final String PUB_SUB_JSON_HTTP_TRUST_STORE_PASSWORD = "pubsub.json-http.trust_store_password"; private String _pubSubJsonHttpTrustStorePassword = null; static String loadPubSubJsonHttpTrustStorePassword(Properties properties) { return loadString(properties, PUB_SUB_JSON_HTTP_TRUST_STORE_PASSWORD, null); } // ***************************************************************************************************************** // ***************************************************************************************************************** // WORKBENCH // ***************************************************************************************************************** // ***************************************************************************************************************** /** * Returns Flag to indicate if the workbench service is to be enabled */ public boolean getWorkbenchEnabled() { return _workbenchEnabled; } static final String WORKBENCH_ENABLED = "workbench.enabled"; private boolean _workbenchEnabled = true; static boolean loadWorkbenchEnabled(Properties properties) { return loadBoolean(properties, WORKBENCH_ENABLED, true); } /** * <p> * Returns the IP address to use for binding our WorkBench web server * </p> * <p> * Can specify <tt>0.0.0.0</tt> which means any address. Can also specify comma separated hostnames/ip address. e.g. * <tt>localhost,192.168.1.1</tt> * </p> */ public String getWorkbenchHost() { return _workbenchHost; } static final String WORKBENCH_HOST = "workbench.host"; private String _workbenchHost = null; static String loadWorkbenchHost(Properties properties) { return loadString(properties, WORKBENCH_HOST); } /** * Returns the IP port to use for binding our WorkBench web server */ public int getWorkbenchPort() { return _workbenchPort; } static final String WORKBENCH_PORT = "workbench.port"; private int _workbenchPort = 0; static int loadWorkbenchPort(Properties properties) { return loadInt(properties, WORKBENCH_PORT, 8989); } /** * Returns the maximum number of threads in the thread pool used by netty for processing channels */ public int getWorkbenchNettyWorkerThreadPoolSize() { return _workbenchNettyWorkerThreadPoolSize; } static final String WORKBENCH_NETTY_WORKER_THREAD_POOL_SIZE = "workbench.netty_worker_thread_pool.size"; private int _workbenchNettyWorkerThreadPoolSize = 0; static int loadWorkbenchNettyWorkerThreadPoolSize(Properties properties) { return loadInt(properties, WORKBENCH_NETTY_WORKER_THREAD_POOL_SIZE, 0); } /** * Returns the maximum number of threads in the thread pool used by netty to execute our handler */ public int getWorkbenchNettyHandlerThreadPoolSize() { return _workbenchNettyHandlerThreadPoolSize; } static final String WORKBENCH_NETTY_HANDLER_THREAD_POOL_SIZE = "workbench.netty_handler_thread_pool.size"; private int _workbenchNettyHandlerThreadPoolSize = 0; static int loadWorkbenchNettyHandlerThreadPoolSize(Properties properties) { return loadInt(properties, WORKBENCH_NETTY_HANDLER_THREAD_POOL_SIZE, 16); } /** * Returns maximum total size of the queued events per channel. 0 to disable. Defaults to 0. */ public long getWorkbenchNettyHandlerThreadPoolMaxChannelMemorySize() { return _workbenchNettyHandlerThreadPoolMaxChannelMemorySize; } static final String WORKBENCH_NETTY_HANDLER_THREAD_POOL_MAX_CHANNEL_MEMORY_SIZE = "workbench.netty_handler_thread_pool.max_channel_memory_size"; private long _workbenchNettyHandlerThreadPoolMaxChannelMemorySize = 0; static long loadWorkbenchNettyHandlerThreadPoolMaxChannelMemorySize(Properties properties) { return loadLong(properties, WORKBENCH_NETTY_HANDLER_THREAD_POOL_MAX_CHANNEL_MEMORY_SIZE, 0); } /** * Returns maximum total size of the queued events for this pool. 0 to disable. Defaults to 0 */ public long getWorkbenchNettyHandlerThreadPoolMaxTotalMemorySize() { return _workbenchNettyHandlerThreadPoolMaxTotalMemorySize; } static final String WORKBENCH_NETTY_HANDLER_THREAD_POOL_MAX_TOTAL_MEMORY_SIZE = "workbench.netty_handler_thread_pool.max_total_memory_size"; private long _workbenchNettyHandlerThreadPoolMaxTotalMemorySize = 0; static long loadWorkbenchNettyHandlerThreadPoolMaxTotalMemorySize(Properties properties) { return loadLong(properties, WORKBENCH_NETTY_HANDLER_THREAD_POOL_MAX_TOTAL_MEMORY_SIZE, 0); } /** * Returns the amount of time for an inactive thread before it is terminated. Defaults to 3 seconds. */ public int getWorkbenchNettyHandlerThreadPoolKeepAliveSeconds() { return _workbenchNettyHandlerThreadPoolKeepAliveSeconds; } static final String WORKBENCH_NETTY_HANDLER_THREAD_POOL_KEEP_ALIVE_SECONDS = "workbench.netty_handler_thread_pool.keep_alive_seconds"; private int _workbenchNettyHandlerThreadPoolKeepAliveSeconds = 0; static int loadWorkbenchNettyHandlerThreadPoolKeepAliveSeconds(Properties properties) { return loadInt(properties, WORKBENCH_NETTY_HANDLER_THREAD_POOL_KEEP_ALIVE_SECONDS, 3); } /** * Returns Flag to indicate if the SSL is to be supported */ public boolean getWorkbenchSslEnabled() { return _workbenchSslEnabled; } static final String WORKBENCH_SSL_ENABLED = "workbench.ssl_enabled"; private boolean _workbenchSslEnabled = false; static boolean loadWorkbenchSslEnabled(Properties properties) { return loadBoolean(properties, WORKBENCH_SSL_ENABLED, false); } /** * Returns the path to the key store to use for SSL */ public String getWorkbenchKeyStorePath() { return _workbenchKeyStorePath; } static final String WORKBENCH_KEY_STORE_PATH = "workbench.key_store_path"; private String _workbenchKeyStorePath = null; static String loadWorkbenchKeyStorePath(Properties properties) { return loadString(properties, WORKBENCH_KEY_STORE_PATH, null); } /** * Returns the password to the key store to use for SSL */ public String getWorkbenchKeyStorePassword() { return _workbenchKeyStorePassword; } static final String WORKBENCH_KEY_STORE_PASSWORD = "workbench.key_store_password"; private String _workbenchKeyStorePassword = null; static String loadWorkbenchKeyStorePassword(Properties properties) { return loadString(properties, WORKBENCH_KEY_STORE_PASSWORD, null); } /** * Returns the password to the key inside to the key store to use for SSL */ public String getWorkbenchKeyStoreKeyPassword() { return _workbenchKeyStoreKeyPassword; } static final String WORKBENCH_KEY_STORE_KEY_PASSWORD = "workbench.key_store_key_password"; private String _workbenchKeyStoreKeyPassword = null; static String loadWorkbenchKeyStoreKeyPassword(Properties properties) { return loadString(properties, WORKBENCH_KEY_STORE_KEY_PASSWORD, null); } /** * Returns the path to the trust store to use for SSL */ public String getWorkbenchTrustStorePath() { return _workbenchTrustStorePath; } static final String WORKBENCH_TRUST_STORE_PATH = "workbench.trust_store_path"; private String _workbenchTrustStorePath = null; static String loadWorkbenchTrustStorePath(Properties properties) { return loadString(properties, WORKBENCH_TRUST_STORE_PATH, null); } /** * Returns the password to the trust store to use for SSL */ public String getWorkbenchTrustStorePassword() { return _workbenchTrustStorePassword; } static final String WORKBENCH_TRUST_STORE_PASSWORD = "workbench.trust_store_password"; private String _workbenchTrustStorePassword = null; static String loadWorkbenchTrustStorePassword(Properties properties) { return loadString(properties, WORKBENCH_TRUST_STORE_PASSWORD, null); } /** * Returns the password to the trust store to use for SSL */ public String getWorkbenchStaticFilesDirectory() { return _workbenchStaticFilesDirectory; } static final String WORKBENCH_STATIC_FILES_DIRECTORY = "workbench.static_files.directory"; private String _workbenchStaticFilesDirectory = null; static String loadWorkbenchStaticFilesDirectory(Properties properties) { return loadString(properties, WORKBENCH_STATIC_FILES_DIRECTORY, "."); } /** * Returns the number of seconds static files are cached in the browser */ public int getWorkbenchStaticFilesCacheSeconds() { return _workbenchStaticFilesCacheSeconds; } static final String WORKBENCH_STATIC_FILES_CACHE_SECONDS = "workbench.static_files.cache_seconds"; private int _workbenchStaticFilesCacheSeconds = 0; static int loadWorkbenchStaticFilesCacheSeconds(Properties properties) { return loadInt(properties, WORKBENCH_STATIC_FILES_CACHE_SECONDS, 0); } /** * Returns the salt to use for hashing of the authentication token */ public byte[] getWorkbenchApiAuthenticationHashSalt() { return _workbenchApiAuthenticationHashSalt; } static final String WORKBENCH_API_AUTHENTICATION_HASH_SALT = "workbench.api.authentication.hash_salt"; private byte[] _workbenchApiAuthenticationHashSalt = null; static byte[] loadWorkbenchApiAuthenticationHashSalt(Properties properties) { try { return loadString(properties, WORKBENCH_API_AUTHENTICATION_HASH_SALT).getBytes("UTF-8"); } catch (Exception ex) { return loadString(properties, WORKBENCH_API_AUTHENTICATION_HASH_SALT).getBytes(); } } /** * Returns the password to use for authentication token encryption */ public byte[] getWorkbenchApiAuthenticationEncryptionPassword() { return _workbenchApiAuthenticationEncryptionPassword; } static final String WORKBENCH_API_AUTHENTICATION_ENCRYPTION_PASSWORD = "workbench.api.authentication.encyrption_password"; private byte[] _workbenchApiAuthenticationEncryptionPassword = null; static byte[] loadWorkbenchApiAuthenticationEncryptionPassword(Properties properties) { try { return loadString(properties, WORKBENCH_API_AUTHENTICATION_ENCRYPTION_PASSWORD).getBytes("UTF-8"); } catch (Exception ex) { return loadString(properties, WORKBENCH_API_AUTHENTICATION_ENCRYPTION_PASSWORD).getBytes(); } } // ************************************************************************************************************* // LOAD METHODS // ************************************************************************************************************* /** * Loads a string. If it is blank (whitespace, empty or null), then exception is thrown. * * @param properties * Properties to lookup * @param name * Name of the property * * @return Value of the property named <code>name</code>. * @throws IllegalArgumentException * if the value of the named properties is blank */ private static String loadString(Properties properties, String name) { String s = properties.getProperty(name); if (StringUtils.isBlank(s)) { throw new IllegalArgumentException(String.format("The property '%s' in '%s' is blank.'", name, APP_PROPERTY_FILE_NAME)); } return s; } /** * Loads a string. If it is blank (whitespace, empty or null), then return the <code>defaultValue</code> * * @param properties * Properties to lookup * @param name * Name of the property * @param defaultValue * Value to return if property value is blank. * @return Value of the property named <code>name</code>. If whitespace, empty or null, then return the * <code>defaultValue</code> */ private static String loadString(Properties properties, String name, String defaultValue) { String s = properties.getProperty(name); if (StringUtils.isBlank(s)) { return defaultValue; } return s; } /** * Loads an int value. If not set, an exception is thrown * * @param properties * Properties to lookup * @param name * Name of the property * * @return Value of the property named <code>name</code>. * @throws IllegalArgumentException * if the value of the named properties is blank */ private static int loadInt(Properties properties, String name) { String s = loadString(properties, name); return Integer.parseInt(s); } /** * Loads an int value. If it is blank (whitespace, empty or null), then return the <code>defaultValue</code> * * @param properties * Properties to lookup * @param name * Name of the property * @param defaultValue * Value to return if property value is blank. * @return Value of the property named <code>name</code>. If whitespace, empty or null, then return the * <code>defaultValue</code> */ private static int loadInt(Properties properties, String name, int defaultValue) { String s = loadString(properties, name, null); if (s == null) { return defaultValue; } return Integer.parseInt(s); } /** * Loads a Long value. If it is blank (whitespace, empty or null), then return the <code>defaultValue</code> * * @param properties * Properties to lookup * @param name * Name of the property * @param defaultValue * Value to return if property value is blank. * @return Value of the property named <code>name</code>. If whitespace, empty or null, then return the * <code>defaultValue</code> */ private static long loadLong(Properties properties, String name, int defaultValue) { String s = loadString(properties, name, null); if (s == null) { return defaultValue; } return Long.parseLong(s); } /** * Loads an boolean value. If not set, an exception is thrown * * @param properties * Properties to lookup * @param name * Name of the property * * @return Value of the property named <code>name</code>. * @throws IllegalArgumentException * if the value of the named properties is blank */ @SuppressWarnings("unused") private static boolean loadBoolean(Properties properties, String name) { String s = loadString(properties, name); return Boolean.parseBoolean(s); } /** * Loads a boolean value. If it is blank (whitespace, empty or null), then return the <code>defaultValue</code> * * @param properties * Properties to lookup * @param name * Name of the property * @param defaultValue * Value to return if property value is blank. * @return Value of the property named <code>name</code>. If whitespace, empty or null, then return the * <code>defaultValue</code> */ private static boolean loadBoolean(Properties properties, String name, boolean defaultValue) { String s = loadString(properties, name, null); if (s == null) { return defaultValue; } return Boolean.parseBoolean(s); } /** * Returns a string representation of the parsed properties */ public String toString() { StringBuilder sb = new StringBuilder(); Class<AppProperties> cls = AppProperties.class; for (Field f : cls.getDeclaredFields()) { // Look for field names like APP_NAME String propertyNameFieldName = f.getName(); if (!propertyNameFieldName.matches("^[A-Z0-9_]+$")) { continue; } // Build cache field (_appName) and method (loadAppName) methods String baseName = WordUtils.capitalizeFully(propertyNameFieldName, new char[] { '_' }); baseName = baseName.replace("_", ""); String cacheFieldName = "_" + StringUtils.uncapitalize(baseName); // If field not exist, then skip Field cacheField = null; try { cacheField = cls.getDeclaredField(cacheFieldName); } catch (NoSuchFieldException e) { continue; } // Get the value try { Object o = cacheField.get(this); sb.append(f.get(null)); sb.append(" = "); sb.append(o == null ? "<not set>" : o.toString()); sb.append("\n"); } catch (Exception e) { sb.append("ERROR: Cannot load value for: " + propertyNameFieldName); } } return sb.toString(); } }