/**
* Copyright (c) 2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you 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.apache.synapse.message.store.impl.jdbc.util;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.synapse.SynapseException;
import org.apache.synapse.commons.datasource.DataSourceFinder;
import org.apache.synapse.commons.datasource.DataSourceInformation;
import org.apache.synapse.commons.datasource.DataSourceRepositoryHolder;
import org.apache.synapse.commons.datasource.RepositoryBasedDataSourceFinder;
import org.apache.synapse.commons.datasource.factory.DataSourceFactory;
import org.apache.synapse.message.store.impl.jdbc.JDBCMessageStoreConstants;
import org.wso2.securevault.secret.SecretInformation;
import org.wso2.securevault.secret.SecretManager;
import javax.naming.Context;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Map;
import java.util.Properties;
/**
* Class <code>JDBCUtil</code> provides the Utility functions to create JDBC resources
*/
public class JDBCConfiguration {
/**
* Logger for the class
*/
private static final Log log = LogFactory.getLog(JDBCConfiguration.class);
/**
* Information about datasource
*/
private DataSourceInformation dataSourceInformation;
/**
* Name of the data source
*/
private String dataSourceName;
/**
* Jndi properties
*/
private Properties jndiProperties = new Properties();
/**
* Data source
*/
private DataSource dataSource;
/**
* Name of the table
*/
private String tableName;
/**
* Creating datasource at startup using configured parameters
*
* @param parameters - parameters given in configuration
*/
public void buildDataSource(Map<String, Object> parameters) {
try {
// Get datasource information
if ((parameters.get(JDBCMessageStoreConstants.JDBC_DSNAME)) != null) {
readLookupConfig(parameters);
dataSource = lookupDataSource();
} else if ((parameters.get(JDBCMessageStoreConstants.JDBC_CONNECTION_DRIVER)) != null) {
readCustomDataSourceConfig(parameters);
dataSource = createCustomDataSource();
} else {
handleException("The DataSource connection information must be specified for " +
"using a custom DataSource connection pool or for a JNDI lookup");
}
// Get table information
if (parameters.get(JDBCMessageStoreConstants.JDBC_TABLE) != null) {
tableName = (String) parameters.get(JDBCMessageStoreConstants.JDBC_TABLE);
} else {
tableName = JDBCMessageStoreConstants.JDBC_DEFAULT_TABLE_NAME;
}
} catch (Exception e) {
log.error("Error looking up DataSource connection information: ", e);
}
}
/**
* Reading lookup information for existing datasource
*
* @param parameters - parameters given in configuration
*/
private void readLookupConfig(Map<String, Object> parameters) {
String dataSourceName = (String) parameters.get(JDBCMessageStoreConstants.JDBC_DSNAME);
this.setDataSourceName(dataSourceName);
if (parameters.get(JDBCMessageStoreConstants.JDBC_ICCLASS) != null) {
Properties props = new Properties();
props.put(Context.INITIAL_CONTEXT_FACTORY, parameters.get(JDBCMessageStoreConstants.JDBC_ICCLASS));
props.put(Context.PROVIDER_URL, parameters.get(JDBCMessageStoreConstants.JDBC_CONNECTION_URL));
props.put(Context.SECURITY_PRINCIPAL, parameters.get(JDBCMessageStoreConstants.JDBC_USERNAME));
props.put(Context.SECURITY_CREDENTIALS, parameters.get(JDBCMessageStoreConstants.JDBC_PASSWORD));
this.setJndiProperties(props);
}
}
/**
* Configure for custom datasource
*
* @param parameters - parameters given in configuration
*/
private void readCustomDataSourceConfig(Map<String, Object> parameters) {
DataSourceInformation dataSourceInformation = new DataSourceInformation();
dataSourceInformation.setDriver((String) parameters.get(JDBCMessageStoreConstants.JDBC_CONNECTION_DRIVER));
dataSourceInformation.setUrl((String) parameters.get(JDBCMessageStoreConstants.JDBC_CONNECTION_URL));
SecretInformation secretInformation = new SecretInformation();
secretInformation.setUser((String) parameters.get(JDBCMessageStoreConstants.JDBC_USERNAME));
secretInformation.setAliasSecret((String) parameters.get(JDBCMessageStoreConstants.JDBC_PASSWORD));
dataSourceInformation.setSecretInformation(secretInformation);
this.setDataSourceInformation(dataSourceInformation);
}
/**
* Lookup the DataSource on JNDI using the specified name and optional properties
*
* @return a DataSource looked up using the specified JNDI properties
*/
private DataSource lookupDataSource() {
DataSource dataSource = null;
RepositoryBasedDataSourceFinder finder = DataSourceRepositoryHolder.getInstance()
.getRepositoryBasedDataSourceFinder();
if (finder.isInitialized()) {
// First try a lookup based on the data source name only
dataSource = finder.find(dataSourceName);
}
if (dataSource == null) {
// Decrypt the password if needed
String password = jndiProperties.getProperty(Context.SECURITY_CREDENTIALS);
if (password != null && !"".equals(password)) {
jndiProperties.put(Context.SECURITY_CREDENTIALS, getActualPassword(password));
}
// Lookup the data source using the specified jndi properties
dataSource = DataSourceFinder.find(dataSourceName, jndiProperties);
if (dataSource == null) {
handleException("Cannot find a DataSource " + dataSourceName + " for given JNDI" +
" properties :" + jndiProperties);
}
}
if (dataSource != null) {
log.info("Successfully looked up datasource " + dataSourceName);
}
return dataSource;
}
/**
* Create a custom DataSource using the specified data source information.
*
* @return a DataSource created using specified properties
*/
protected DataSource createCustomDataSource() {
DataSource dataSource = DataSourceFactory.createDataSource(dataSourceInformation);
if (dataSource != null) {
log.info("Successfully created data source for " + dataSourceInformation.getUrl());
}
return dataSource;
}
/**
* Get the password from SecretManager . here only use SecretManager
*
* @param aliasPassword alias password
* @return if the SecretManager is initiated , then , get the corresponding secret
* , else return alias itself
*/
private String getActualPassword(String aliasPassword) {
SecretManager secretManager = SecretManager.getInstance();
if (secretManager.isInitialized()) {
return secretManager.getSecret(aliasPassword);
}
return aliasPassword;
}
/**
* Get a Connection from current datasource
*
* @return - Connection
* @throws java.sql.SQLException - Failure in creating datasource connection
*/
public Connection getConnection() throws SQLException {
Connection con = getDataSource().getConnection();
if (con == null) {
String msg = "Connection from DataSource " + getDSName() + " is null.";
throw new SynapseException(msg);
}
return con;
}
/**
* Return the name or (hopefully) unique connection URL specific to the DataSource being used
* This is used for logging purposes only
*
* @return a unique name or URL to refer to the DataSource being used
*/
public String getDSName() {
if (dataSourceName != null) {
return dataSourceName;
} else if (dataSourceInformation != null) {
String name = dataSourceInformation.getUrl();
if (name == null) {
name = dataSourceInformation.getDatasourceName();
}
return name;
}
return null;
}
/**
* Set DataSourceInformation
*
* @param dataSourceInformation - information to set
*/
public void setDataSourceInformation(DataSourceInformation dataSourceInformation) {
this.dataSourceInformation = dataSourceInformation;
}
/**
* Set JNDI Properties
*
* @param jndiProperties - properties to set
*/
public void setJndiProperties(Properties jndiProperties) {
this.jndiProperties = jndiProperties;
}
/**
* Get datasource
*
* @return - Datasource currently in use
*/
public DataSource getDataSource() {
return dataSource;
}
/**
* Get datasource name currently in use
*
* @param dataSourceName - Datasource name
*/
public void setDataSourceName(String dataSourceName) {
this.dataSourceName = dataSourceName;
}
/**
* Table name in use
*
* @return - Name of the table
*/
public String getTableName() {
return tableName;
}
/**
* Handle Exceptions during process
*
* @param o - Exception needs to handle
*/
private void handleException(Object o) {
log.error(o);
}
}