/*
* This software is distributed under the terms of the FSF
* Gnu Lesser General Public License (see lgpl.txt).
*
* This program is distributed WITHOUT ANY WARRANTY. See the
* GNU General Public License for more details.
*/
package com.scooterframework.orm.sqldataexpress.config;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Observable;
import java.util.Observer;
import java.util.Properties;
import java.util.Set;
import javax.sql.DataSource;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import com.mchange.v2.c3p0.DataSources;
import com.scooterframework.admin.ApplicationConfig;
import com.scooterframework.admin.PropertyFileChangeMonitor;
import com.scooterframework.admin.PropertyReader;
import com.scooterframework.common.logging.LogUtil;
import com.scooterframework.common.util.Converters;
import com.scooterframework.common.util.NamedProperties;
import com.scooterframework.common.util.PropertyFileUtil;
import com.scooterframework.common.util.Util;
import com.scooterframework.orm.sqldataexpress.connection.DatabaseConnectionContext;
import com.scooterframework.transaction.Transaction;
/**
* <p>DatabaseConfig class configs the data access application during startup
* time. After instantiated, it is a readonly object. </p>
*
* <p>Mappings between sql data type name, sql data typ code and java type name
* are specified here. By default, all entries in java.sql.Type class are listed here.</p>
*
* <p>Developers can override or add more here. See below for examples.</p>
*
* <p>All items are of the following format separated by comma. </p>
* <pre>
* Format: {sql data type name}:{sql data type}:{java class name}
*
* ARRAY:2003:java.sql.Array //Types.ARRAY
* BIGINT:-5:java.lang.Long //Types.BIGINT
* BINARY:-2:byte[] //Types.BINARY
* BIT:-7:java.lang.Boolean //Types.BIT
* BLOB:2004:java.sql.Blob //Types.BLOB
* BOOLEAN:16:java.lang.Boolean //Types.BOOLEAN
* CHAR:1:java.lang.String //Types.CHAR
* CLOB:2005:java.sql.Clob //Types.CLOB
* DATALINK:70:java.lang.Object //Types.DATALINK
* DATE:91:java.sql.Timestamp //Types.DATE
* DECIMAL:3:java.lang.BigDecimal //Types.DECIMAL
* DISTINCT:2001:java.lang.Object //Types.DISTINCT
* DOUBLE:8:java.lang.Double //Types.DOUBLE
* FLOAT:6:java.lang.Double //Types.FLOAT
* INTEGER:4:java.lang.Integer //Types.INTEGER
* JAVA_OBJECT:2000:java.lang.Object //Types.JAVA_OBJECT
* LONGVARBINARY:-4:byte[] //Types.LONGVARBINARY
* LONGVARCHAR:-1:java.lang.String //Types.LONGVARCHAR
* LONGVARCHAR:-15:java.lang.String //Types.NCHAR
* NCLOB:2011:java.sql.Clob //Types.NCLOB
* NULL:0:java.lang.Object //Types.NULL
* NUMERIC:2:java.lang.BigDecimal //Types.NUMERIC
* NVARCHAR:-9:java.lang.String //Types.NVARCHAR
* OTHER:1111:java.lang.Object //Types.OTHER
* REAL:7:java.lang.Double //Types.REAL
* REF:2006:java.sql.Ref //Types.REF
* ROWID:-8:java.lang.Integer //Types.ROWID
* SMALLINT:5:java.lang.Integer //Types.SMALLINT
* SQLXML:2009:java.lang.String //Types.SQLXML
* STRUCT:2002:java.sql.Struct //Types.STRUCT
* TIME:92:java.sql.Time //Types.TIME
* TIMESTAMP:93:java.sql.Timestamp //Types.TIMESTAMP
* TINYINT:-6:java.lang.Integer //Types.TINYINT
* VARBINARY:-3:byte[] //Types.VARBINARY
* VARCHAR:12:java.lang.String //Types.VARCHAR
* Special for ORACLE:
* NUMBER:2:java.lang.BigDecimal //Types.NUMERIC
* VARCHAR2:12:java.lang.String //Types.VARCHAR
* </pre>
*
* <p>Developers can add more types at startup time by adding those types
* in database property file.</p>
*
* @author (Fei) John Chen
*/
public class DatabaseConfig extends Observable implements Observer {
private LogUtil log = LogUtil.getLogger(this.getClass().getName());
/**
* A hyphen "-" is used to link composite primary key fields.
*/
public static final String PRIMARY_KEY_SEPARATOR = "-";
/**
* Property file for database properties.
*/
public static final String DATA_PROPERTIES_FILE = "database.properties";
/**
* All allowed transaction types: "JDBC JTA CMT"
*/
public static final String ALLOWED_TRANSACTION_TYPES = "JDBC JTA CMT";
/**
* Key to represent a property in database connection properties.
*/
public static final String KEY_DB_CONNECTION_NAME_PREFIX = "database.connection";
/**
* Key to represent connection <tt>name</tt> property in database connection properties.
*/
public static final String KEY_DB_CONNECTION_NAME = "name";
/**
* Key to represent <tt>transactionType</tt> property in database connection properties.
*/
public static final String KEY_DB_CONNECTION_TRANSACTION_TYPE = "transaction.type";
/**
* Key to represent <tt>dataSourceName</tt> property in database connection properties.
*/
public static final String KEY_DB_CONNECTION_DATASOURCE_NAME = "data_source_name";
/**
* Key to represent <tt>beforeConenction</tt> property in database connection properties.
*/
public static final String KEY_DB_CONNECTION_BEFORE = "before_connection";
/**
* Key to represent <tt>afterConnection</tt> property in database connection properties.
*/
public static final String KEY_DB_CONNECTION_AFTER = "after_connection";
/**
* Key to represent <tt>timeout</tt> property in database connection properties.
*/
public static final String KEY_DB_CONNECTION_TIMEOUT = "timeout";
/**
* Key to represent <tt>username</tt> property in database connection properties.
*/
public static final String KEY_DB_CONNECTION_USERNAME = "username";
/**
* Key to represent <tt>password</tt> property in database connection properties.
*/
public static final String KEY_DB_CONNECTION_PASSWORD = "password";
/**
* Key to represent <tt>driver</tt> property in database connection properties.
*/
public static final String KEY_DB_CONNECTION_DRIVER = "driver";
/**
* Key to represent <tt>url</tt> property in database connection properties.
*/
public static final String KEY_DB_CONNECTION_URL = "url";
/**
* Key to represent <tt>readonly</tt> property in database connection properties.
*/
public static final String KEY_DB_CONNECTION_READONLY = "readonly";
/**
* Key to represent <tt>readonly</tt> property in database connection properties.
*/
public static final String KEY_DB_CONNECTION_AUTOCOMMIT = "autocommit";
/**
* Key to represent <tt>transactionIsolationLevel</tt> property in database connection properties.
*/
public static final String KEY_DB_CONNECTION_TRANSACTION_ISOLATION_LEVEL = "transaction_isolation_level";
/**
* Key to represent <tt>vendor</tt> property in database connection properties.
*/
public static final String KEY_DB_CONNECTION_VENDOR = "vendor";
/**
* Key to represent <tt>schema</tt> property in database connection properties.
*/
public static final String KEY_DB_CONNECTION_SCHEMA = "schema";
/**
* Key to represent <tt>use_login_as_schema</tt> property in database connection properties.
*/
public static final String KEY_DB_CONNECTION_USE_LOGIN_AS_SCHEMA = "use_login_as_schema";
/**
* Key to represent <tt>use_login_for_connection</tt> property in database connection properties.
*/
public static final String KEY_DB_CONNECTION_USE_LOGIN_FOR_CONNECTION = "use_login_for_connection";
/**
* Key to represent <tt>adapterClassName</tt> property in database connection properties.
*/
public static final String KEY_DB_CONNECTION_ADAPTER_CLASS_NAME = "adapterClassName";
/**
* Key to represent <tt>max_pool_size</tt> property in database connection properties.
*/
public static final String KEY_DB_CONNECTION_MAX_POOL_SIZE = "max_pool_size";
/**
* Key to represent <tt>min_pool_size</tt> property in database connection properties.
*/
public static final String KEY_DB_CONNECTION_MIN_POOL_SIZE = "min_pool_size";
/**
* Key to represent <tt>acquire_increment</tt> property in database connection properties.
*/
public static final String KEY_DB_CONNECTION_ACQUIRE_INCREMENT = "acquire_increment";
/**
* Key to represent <tt>initial_pool_size</tt> property in database connection properties.
*/
public static final String KEY_DB_CONNECTION_INITIAL_POOL_SIZE = "initial_pool_size";
/**
* Key to represent <tt>max_idle_time</tt> property in database connection properties.
*/
public static final String KEY_DB_CONNECTION_MAX_IDLE_TIME = "max_idle_time";
public static final String BUILTIN_DATABASE_NAME_H2 = "H2";
public static final String BUILTIN_DATABASE_NAME_HSQLDB = "HsqlDB";
public static final String BUILTIN_DATABASE_NAME_MYSQL = "MySQL";
public static final String BUILTIN_DATABASE_NAME_ORACLE = "Oracle";
public static final String BUILTIN_DATABASE_NAME_POSTGRESQL = "PostgreSQL";
public static final String BUILTIN_DATABASE_NAME_SQLSERVER = "SQLServer";
public static final String BUILTIN_DATABASE_NAME_SYBASE = "Sybase";
public static final Set<String> ALL_BUILTIN_DATABASE_VENDORS = new HashSet<String>();
//****************************************************
// Default values for keys in the properties file
//****************************************************
public static final String DEFAULT_VALUE_defaultTransactionType = Transaction.JDBC_TRANSACTION_TYPE;
public static final String DEFAULT_VALUE_defaultDatabaseConnection = null;
public static final String DEFAULT_VALUE_gloablTableNamingPrefix = "";
public static final String DEFAULT_VALUE_gloablTableNamingSuffix = "";
public static final String DEFAULT_VALUE_usePluralTableName = "true";
public static final String DEFAULT_VALUE_autoAuditCreate = null;
public static final String DEFAULT_VALUE_autoAuditUpdate = null;
public static final String DEFAULT_VALUE_additionalSQLDataTypeMapping = null;
public static final int DEFAULT_VALUE_max_pool_size = 5;
public static final int DEFAULT_VALUE_min_pool_size = 3;
public static final int DEFAULT_VALUE_acquire_increment = 3;
public static final int DEFAULT_VALUE_initial_pool_size = 3;
public static final int DEFAULT_VALUE_max_idle_time = 0;
private static final DatabaseConfig me = new DatabaseConfig();
private Properties appProperties = null;
private String defaultTransactionType = DEFAULT_VALUE_defaultTransactionType;
private String defaultDatabaseConnection = DEFAULT_VALUE_defaultDatabaseConnection;
private String gloablTableNamingPrefix = DEFAULT_VALUE_gloablTableNamingPrefix;
private String gloablTableNamingSuffix = DEFAULT_VALUE_gloablTableNamingSuffix;
private String usePluralTableName = DEFAULT_VALUE_usePluralTableName;
private String autoAuditCreate = DEFAULT_VALUE_autoAuditCreate;
private String autoAuditUpdate = DEFAULT_VALUE_autoAuditUpdate;
private String additionalSQLDataTypeMapping = DEFAULT_VALUE_additionalSQLDataTypeMapping;
private List<String> autoAuditListForCreate = null;
private List<String> autoAuditListForUpdate = null;
private Map<String, NamedProperties> databaseConnectionsMap = new HashMap<String, NamedProperties>();
private List<String> referenceDataNames = new ArrayList<String>();
private Map<String, NamedProperties> referenceDataMap = new HashMap<String, NamedProperties>();
private Map<String, ComboPooledDataSource> connectionPoolDataSourcesMap = new HashMap<String, ComboPooledDataSource>();
/**
* <p>A map of SQL data type name and its corresponding type (Integer).</p>
*/
public final Map<String, Integer> allSQLDataNameTypesMap = new HashMap<String, Integer>();
/**
* <p>A map of SQL data type code and its corresponding java class type name.</p>
*/
public final Map<Integer, String> allSQLTypeJavaNamesMap = new HashMap<Integer, String>();
private DatabaseConfig() {
init();
PropertyFileChangeMonitor.getInstance().registerObserver(this, DATA_PROPERTIES_FILE);
}
private void clear() {
if (autoAuditListForCreate != null) autoAuditListForCreate.clear();
if (autoAuditListForUpdate != null) autoAuditListForUpdate.clear();
databaseConnectionsMap.clear();
referenceDataNames.clear();
referenceDataMap.clear();
allSQLDataNameTypesMap.clear();
allSQLTypeJavaNamesMap.clear();
connectionPoolDataSourcesMap.clear();
}
private void init() {
clear();
ALL_BUILTIN_DATABASE_VENDORS.add(BUILTIN_DATABASE_NAME_H2.toUpperCase());
ALL_BUILTIN_DATABASE_VENDORS.add(BUILTIN_DATABASE_NAME_HSQLDB.toUpperCase());
ALL_BUILTIN_DATABASE_VENDORS.add(BUILTIN_DATABASE_NAME_MYSQL.toUpperCase());
ALL_BUILTIN_DATABASE_VENDORS.add(BUILTIN_DATABASE_NAME_ORACLE.toUpperCase());
ALL_BUILTIN_DATABASE_VENDORS.add(BUILTIN_DATABASE_NAME_POSTGRESQL.toUpperCase());
ALL_BUILTIN_DATABASE_VENDORS.add(BUILTIN_DATABASE_NAME_SQLSERVER.toUpperCase());
ALL_BUILTIN_DATABASE_VENDORS.add(BUILTIN_DATABASE_NAME_SYBASE.toUpperCase());
List<String> allSQLTypesList = new ArrayList<String>();
allSQLTypesList.add("ARRAY:2003:java.sql.Array"); //Types.ARRAY
allSQLTypesList.add("BIGINT:-5:java.lang.Long"); //Types.BIGINT
allSQLTypesList.add("BINARY:-2:byte[]"); //Types.BINARY
allSQLTypesList.add("BIT:-7:java.lang.Boolean"); //Types.BIT
allSQLTypesList.add("BLOB:2004:java.sql.Blob"); //Types.BLOB
allSQLTypesList.add("BOOLEAN:16:java.lang.Boolean"); //Types.BOOLEAN
allSQLTypesList.add("CHAR:1:java.lang.String"); //Types.CHAR
allSQLTypesList.add("CLOB:2005:java.sql.Clob"); //Types.CLOB
allSQLTypesList.add("DATALINK:70:java.lang.Object"); //Types.DATALINK
allSQLTypesList.add("DATE:91:java.sql.Timestamp"); //Types.DATE
allSQLTypesList.add("DECIMAL:3:java.lang.BigDecimal"); //Types.DECIMAL
allSQLTypesList.add("DISTINCT:2001:java.lang.Object"); //Types.DISTINCT
allSQLTypesList.add("DOUBLE:8:java.lang.Double"); //Types.DOUBLE
allSQLTypesList.add("FLOAT:6:java.lang.Double"); //Types.FLOAT
allSQLTypesList.add("INTEGER:4:java.lang.Integer"); //Types.INTEGER
allSQLTypesList.add("JAVA_OBJECT:2000:java.lang.Object"); //Types.JAVA_OBJECT
allSQLTypesList.add("LONGVARCHAR:-16:java.lang.String"); //Types.LONGNVARCHAR
allSQLTypesList.add("LONGVARBINARY:-4:byte[]"); //Types.LONGVARBINARY
allSQLTypesList.add("LONGVARCHAR:-1:java.lang.String"); //Types.LONGVARCHAR
allSQLTypesList.add("NCHAR:-15:java.lang.String"); //Types.NCHAR
allSQLTypesList.add("CLOB:2011:java.sql.Clob"); //Types.NCLOB
allSQLTypesList.add("NVARCHAR:-9:java.lang.String"); //Types.NVARCHAR
allSQLTypesList.add("NULL:0:java.lang.Object"); //Types.NULL
allSQLTypesList.add("NUMERIC:2:java.lang.BigDecimal"); //Types.NUMERIC
allSQLTypesList.add("OTHER:1111:java.lang.Object"); //Types.OTHER
allSQLTypesList.add("REAL:7:java.lang.Double"); //Types.REAL
allSQLTypesList.add("REF:2006:java.sql.Ref"); //Types.REF
allSQLTypesList.add("ROWID:-8:java.lang.Integer"); //Types.ROWID
allSQLTypesList.add("SMALLINT:5:java.lang.Integer"); //Types.SMALLINT
allSQLTypesList.add("SQLXML:2009:java.lang.String"); //Types.SQLXML
allSQLTypesList.add("STRUCT:2002:java.sql.Struct"); //Types.STRUCT
allSQLTypesList.add("TIME:92:java.sql.Time"); //Types.TIME
allSQLTypesList.add("TIMESTAMP:93:java.sql.Timestamp"); //Types.TIMESTAMP
allSQLTypesList.add("TINYINT:-6:java.lang.Integer"); //Types.TINYINT
allSQLTypesList.add("VARBINARY:-3:byte[]"); //Types.VARBINARY
allSQLTypesList.add("VARCHAR:12:java.lang.String"); //Types.VARCHAR
allSQLTypesList.add("NUMBER:2:java.lang.BigDecimal"); //Types.NUMERIC
allSQLTypesList.add("VARCHAR2:12:java.lang.String"); //Types.VARCHAR
loadProperties();
defaultTransactionType = getProperty("default.transaction.type", DEFAULT_VALUE_defaultTransactionType);
if (ALLOWED_TRANSACTION_TYPES.indexOf(defaultTransactionType) == -1) {
throw new IllegalArgumentException("The value of default.transaction.type " +
"\"" + defaultTransactionType + "\" in properties file is " +
"not valid. The allowed transaction types are \"" + ALLOWED_TRANSACTION_TYPES + "\".");
}
gloablTableNamingPrefix = getProperty("global.table.naming.prefix", DEFAULT_VALUE_gloablTableNamingPrefix);
gloablTableNamingSuffix = getProperty("global.table.naming.suffix", DEFAULT_VALUE_gloablTableNamingSuffix);
usePluralTableName = getProperty("use.plural.table.name", DEFAULT_VALUE_usePluralTableName);
String nameValueSpliter = "=";
String propertyDelimiter = ",";
Enumeration<?> en = appProperties.keys();
while (en.hasMoreElements()) {
String key = (String) en.nextElement();
if (key == null) continue;
if (key.startsWith("database.connection")) {
String name = key.substring(key.lastIndexOf('.') + 1);
Properties p = PropertyFileUtil.parseNestedPropertiesFromLine(getProperty(key), nameValueSpliter, propertyDelimiter);
p.setProperty(KEY_DB_CONNECTION_NAME, name);
checkConnectionPoolProperties(name, p);
if (databaseConnectionsMap.containsKey(name)) {
NamedProperties np = databaseConnectionsMap.get(name);
np.setProperties(p);
}
else {
NamedProperties np = new NamedProperties(name, p);
databaseConnectionsMap.put(name, np);
}
}
else
if (key.startsWith("reference.data")) {
String name = key.substring(key.lastIndexOf('.') + 1);
Properties p = PropertyFileUtil.parseNestedPropertiesFromLine(getProperty(key), nameValueSpliter, propertyDelimiter);
if (referenceDataMap.containsKey(name)) {
NamedProperties np = referenceDataMap.get(name);
np.setProperties(p);
}
else {
NamedProperties np = new NamedProperties(name, p);
referenceDataNames.add(name);
referenceDataMap.put(name, np);
}
}
}
defaultDatabaseConnection = getProperty("default.database.connection.name", DEFAULT_VALUE_defaultDatabaseConnection);
if (defaultDatabaseConnection != null && !databaseConnectionsMap.keySet().contains(defaultDatabaseConnection)) {
log.error("There is no definition for default database connection " + defaultDatabaseConnection);
}
autoAuditCreate = getProperty("autoaudit.create.timestamp.fields", DEFAULT_VALUE_autoAuditCreate);
if (autoAuditCreate != null) {
autoAuditListForCreate = Converters.convertStringToList(autoAuditCreate.toLowerCase());
}
autoAuditUpdate = getProperty("autoaudit.update.timestamp.fields", DEFAULT_VALUE_autoAuditUpdate);
if (autoAuditUpdate != null) {
autoAuditListForUpdate = Converters.convertStringToList(autoAuditUpdate.toLowerCase());
}
//populate sql maps
additionalSQLDataTypeMapping = getProperty("additional_sql_data_type_mapping", DEFAULT_VALUE_additionalSQLDataTypeMapping);
allSQLTypesList.addAll(Converters.convertStringToList(additionalSQLDataTypeMapping));
allSQLDataNameTypesMap.clear();
allSQLTypeJavaNamesMap.clear();
int totalTypes = allSQLTypesList.size();
for (int i = 0; i < totalTypes; i++) {
String entry = allSQLTypesList.get(i);
String[] items = entry.split(":");
String typeName = items[0].trim();
String typeCode = items[1].trim();
String javaName = items[2].trim();
Integer sqlDataTypeCode = Util.getSafeInteger(typeCode);
allSQLDataNameTypesMap.put(typeName, sqlDataTypeCode);
allSQLTypeJavaNamesMap.put(sqlDataTypeCode, javaName);
}
}
private void checkConnectionPoolProperties(String connectionName, Properties p) {
boolean autoCommit = ("true".equalsIgnoreCase(p.getProperty(DatabaseConnectionContext.KEY_AUTOCOMMIT)))?true:false;
String maxPoolSize = p.getProperty(KEY_DB_CONNECTION_MAX_POOL_SIZE, "" + DEFAULT_VALUE_max_pool_size);
if (Integer.parseInt(maxPoolSize) == 0) {
p.setProperty(KEY_DB_CONNECTION_MAX_POOL_SIZE, maxPoolSize);
log.debug("No connection pool for " + connectionName + ", because max_pool_size is " + maxPoolSize);
return;
}
Properties c3p0props = new Properties();
c3p0props.setProperty("maxPoolSize", maxPoolSize);
String minPoolSize = p.getProperty(KEY_DB_CONNECTION_MIN_POOL_SIZE, "" + DEFAULT_VALUE_min_pool_size);
p.setProperty(KEY_DB_CONNECTION_MIN_POOL_SIZE, minPoolSize);
c3p0props.setProperty("minPoolSize", minPoolSize);
String acquireIncrement = p.getProperty(KEY_DB_CONNECTION_ACQUIRE_INCREMENT, "" + DEFAULT_VALUE_acquire_increment);
p.setProperty(KEY_DB_CONNECTION_ACQUIRE_INCREMENT, acquireIncrement);
c3p0props.setProperty("acquireIncrement", acquireIncrement);
String initialPoolSize = p.getProperty(KEY_DB_CONNECTION_INITIAL_POOL_SIZE, "" + DEFAULT_VALUE_initial_pool_size);
p.setProperty(KEY_DB_CONNECTION_INITIAL_POOL_SIZE, initialPoolSize);
c3p0props.setProperty("initialPoolSize", initialPoolSize);
String maxIdleTime = p.getProperty(KEY_DB_CONNECTION_MAX_IDLE_TIME, "" + DEFAULT_VALUE_max_idle_time);
p.setProperty(KEY_DB_CONNECTION_MAX_IDLE_TIME, maxIdleTime);
c3p0props.setProperty("maxIdleTime", maxIdleTime);
try {
String driver = p.getProperty(KEY_DB_CONNECTION_DRIVER);
if (driver == null) throw new IllegalArgumentException("Driver class is not specified for connection " + connectionName);
String url = p.getProperty(KEY_DB_CONNECTION_URL);
if (url == null) throw new IllegalArgumentException("Database url is not specified for connection " + connectionName);
String username = p.getProperty(KEY_DB_CONNECTION_USERNAME);
String password = p.getProperty(KEY_DB_CONNECTION_PASSWORD);
System.setProperty("com.mchange.v2.c3p0.management.ManagementCoordinator", "com.mchange.v2.c3p0.management.NullManagementCoordinator");
ComboPooledDataSource cpds = new ComboPooledDataSource(connectionName);
cpds.setDriverClass(driver);
cpds.setJdbcUrl(url);
cpds.setUser(username);
cpds.setPassword(password);
cpds.setAutoCommitOnClose(autoCommit);
cpds.setMaxPoolSize(Integer.parseInt(maxPoolSize));
cpds.setMinPoolSize(Integer.parseInt(minPoolSize));
cpds.setAcquireIncrement(Integer.parseInt(acquireIncrement));
cpds.setInitialPoolSize(Integer.parseInt(initialPoolSize));
cpds.setMaxIdleTime(Integer.parseInt(maxIdleTime));
connectionPoolDataSourcesMap.put(connectionName, cpds);
log.debug("created ds for " + connectionName + " with properties: " + c3p0props);
} catch (Throwable e) {
log.error("Failed to create data source for " + connectionName + " with properties: " + c3p0props + ": " + e.getMessage());
}
}
private void loadProperties() {
if (appProperties != null) appProperties.clear();
appProperties = PropertyReader.loadPropertiesFromFile(DATA_PROPERTIES_FILE);
if (appProperties == null) appProperties = new Properties();
}
public static DatabaseConfig getInstance() {
return me;
}
/**
* Returns map of sql data type name / data type code.
* @return map
*/
public Map<String, Integer> getSQLDataNameTypesMap() {
return allSQLDataNameTypesMap;
}
/**
* Returns map of sql data type code / java type name.
* @return map
*/
public Map<Integer, String> getSQLTypeJavaNamesMap() {
return allSQLTypeJavaNamesMap;
}
/**
* Required method by <tt>Observer</tt> interface.
*/
public void update(Observable o, Object arg) {
init();
super.setChanged();
super.notifyObservers();
}
/**
* Returns all properties.
*/
public Properties getProperties() {
return appProperties;
}
/**
* Returns a String property corresponding to a key.
*/
public String getProperty(String key) {
return appProperties.getProperty(key);
}
/**
* Returns a String property corresponding to a key. If the returned
* property is null, the default value of the property is returned.
*/
public String getProperty(String key, String defaultValue) {
return appProperties.getProperty(key, defaultValue);
}
/**
* Returns default transaction type
*/
public String getDefaultTransactionType() {
return defaultTransactionType;
}
/**
* Returns global table naming prefix
*/
public String getGlobalTableNamingPrefix() {
return gloablTableNamingPrefix;
}
/**
* Returns global table naming suffix
*/
public String getGlobalTableNamingSuffix() {
return gloablTableNamingSuffix;
}
/**
* Checks if using plural nones as table name
*/
public boolean usePluralTableName() {
return ("true".equalsIgnoreCase(usePluralTableName))?true:false;
}
/**
* Returns a full table name. A full table name includes global table name
* prefix and suffix.
*
* <p>
* For example, in a crm schema, all tables might have prefix "CRM_".
* Therefore, a <tt>USER</tt> table's full name is <tt>CRM_USER</tt>.
* </p>
*
* @param table a slim table name
* @return a full table name
*/
public String getFullTableName(String table) {
if (table == null) throw new IllegalArgumentException("Error in getFullTableName(): table cannot be null.");
if (table.indexOf('.') != -1) return table;
String tablePrefix = getGlobalTableNamingPrefix();
String tableSuffix = getGlobalTableNamingSuffix();
String fullTableName = table;
if (!fullTableName.toUpperCase().startsWith(tablePrefix.toUpperCase())) fullTableName = tablePrefix + fullTableName;
if (!fullTableName.toUpperCase().endsWith(tableSuffix.toUpperCase())) fullTableName = fullTableName + tableSuffix;
return fullTableName;
}
/**
* Returns a simple table name. A simple table name does not include global
* table name prefix and suffix.
*
* <p>
* For example, if the table name is "CRM_users_US" which has a prefix
* "CRM_" and a suffix "_US", the returned slim table name is just
* "users". Both the prefix and the suffix are removed in the return value.
* </p>
*
* @param fullTableName a full table name
* @return a simple table name
*/
public String getSimpleTableName(String fullTableName) {
String tablePrefix = getGlobalTableNamingPrefix().toUpperCase();
String tableSuffix = getGlobalTableNamingSuffix().toUpperCase();
String slimName = fullTableName.toUpperCase();
if (slimName.startsWith(tablePrefix)) slimName = slimName.substring(tablePrefix.length());
if (slimName.endsWith(tableSuffix)) slimName = slimName.substring(0, slimName.length() - tableSuffix.length());
return slimName;
}
/**
* Checks if the current running environment is development environment.
*
* @return true if the current running environment is development.
*/
public boolean isInDevelopmentEnvironment() {
return ApplicationConfig.getInstance().isInDevelopmentEnvironment();
}
/**
* Returns default database connection name
*/
public String getDefaultDatabaseConnectionName() {
return defaultDatabaseConnection;
}
public String tryToUseTestDatabaseConnection() {
String testDatabaseConnectionName = null;
if (defaultDatabaseConnection.endsWith("_development")) {
int lastUnderscore = defaultDatabaseConnection.indexOf('_');
testDatabaseConnectionName = defaultDatabaseConnection.substring(0, lastUnderscore);
testDatabaseConnectionName = testDatabaseConnectionName + "_test";
if (getPredefinedDatabaseConnectionProperties(testDatabaseConnectionName).size() > 0) {
defaultDatabaseConnection = testDatabaseConnectionName;
}
}
return testDatabaseConnectionName;
}
public void restoreDefaultDatabaseConnectionName() {
defaultDatabaseConnection = getProperty("default.database.connection.name", DEFAULT_VALUE_defaultDatabaseConnection);
}
/**
* Returns default database connection properties
*/
public Properties getDefaultDatabaseConnectionProperties() {
return getPredefinedDatabaseConnectionProperties(getDefaultDatabaseConnectionName());
}
/**
* Returns database connection properties
*/
public Properties getPredefinedDatabaseConnectionProperties(String connName) {
if (connName == null)
throw new IllegalArgumentException("Error in " +
"getPredefinedDatabaseConnectionProperties: connName cannot be null.");
NamedProperties np = databaseConnectionsMap.get(connName);
return (np != null)?np.getProperties():(new Properties());
}
/**
* Returns database connection names
*/
public Iterator<String> getPredefinedDatabaseConnectionNames() {
return databaseConnectionsMap.keySet().iterator();
}
/**
* Returns properties of reference data specified by the name
*/
public Properties getReferenceDataProperties(String referenceDataName) {
NamedProperties np = referenceDataMap.get(referenceDataName);
return (np != null)?np.getProperties():(new Properties());
}
/**
* Returns a list of all reference data names
*
* @return list of reference data names
*/
public List<String> getReferenceDataNames() {
return referenceDataNames;
}
/**
* Returns a map of all reference data
*
* @return map of reference data
*/
public Map<String, NamedProperties> getReferenceDataMap() {
return referenceDataMap;
}
/**
* Checks if auto audit is allowed for create operation.
*/
public boolean allowAutoAuditCreate() {
return (autoAuditCreate != null)?true:false;
}
/**
* Checks if auto audit is allowed for update operation.
*/
public boolean allowAutoAuditUpdate() {
return (autoAuditUpdate != null)?true:false;
}
/**
* Returns list of potential column names that are automatically audited
* for create operation.
*/
public List<String> getAutoAuditListForCreate() {
return autoAuditListForCreate;
}
/**
* Returns list of potential column names that are automatically audited
* for update operation.
*/
public List<String> getAutoAuditListForUpdate() {
return autoAuditListForUpdate;
}
/**
* Checks if a column is auto audited for create operation.
*/
public boolean isAutoAuditCreate(String column) {
if (autoAuditListForCreate != null && column != null) {
return autoAuditListForCreate.contains(column.toLowerCase());
}
return false;
}
/**
* Checks if a column is auto audited for update operation.
*/
public boolean isAutoAuditUpdate(String column) {
if (autoAuditListForUpdate != null && column != null) {
return autoAuditListForUpdate.contains(column.toLowerCase());
}
return false;
}
/**
* Checks if a vendor name is allowed.
*/
public static boolean isBuiltInVendorName(String vendor) {
if (vendor == null)
throw new IllegalArgumentException("Vendor name is empty.");
return ALL_BUILTIN_DATABASE_VENDORS.contains(vendor.toUpperCase());
}
/**
* Returns pooled data source for a connection name
*/
public DataSource getPooledDataSource(String connectionName) {
return connectionPoolDataSourcesMap.get(connectionName);
}
/**
* Returns pooled data source for default connection name
*/
public DataSource getPooledDataSource() {
return getPooledDataSource(getDefaultDatabaseConnectionName());
}
/**
* Destroys all connection pools if there is any.
*/
public void destroy() {
try {
for (Map.Entry<String, ComboPooledDataSource> entry : connectionPoolDataSourcesMap.entrySet()) {
DataSources.destroy(entry.getValue());
}
} catch (SQLException ex) {
log.error("ERROR ERROR ERROR failed to close connection pool: " + ex.getMessage());
}
}
}