blob: 3c7d3449fcf930203c4205d21dff6d4bafe412d2 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF 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.openejb.resource.jdbc;
import org.apache.commons.dbcp.ConnectionFactory;
import org.apache.commons.dbcp.DataSourceConnectionFactory;
import org.apache.commons.dbcp.managed.DataSourceXAConnectionFactory;
import org.apache.commons.dbcp.managed.LocalXAConnectionFactory;
import org.apache.commons.dbcp.managed.TransactionRegistry;
import org.apache.commons.dbcp.managed.XAConnectionFactory;
import org.apache.openejb.loader.SystemInstance;
import org.apache.openejb.resource.XAResourceWrapper;
import org.apache.openejb.util.LogCategory;
import org.apache.xbean.recipe.ObjectRecipe;
import org.apache.xbean.recipe.Option;
import javax.sql.DataSource;
import javax.sql.XADataSource;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.SQLException;
import java.util.Map;
import java.util.Properties;
/**
* @version $Rev: 1205747 $ $Date: 2011-11-23 23:53:38 -0800 (Wed, 23 Nov 2011) $
*/
public class DataSourceFactory {
public static DataSource create(final boolean managed, final Class impl, final String definition) throws IllegalAccessException, InstantiationException, IOException {
final org.apache.commons.dbcp.BasicDataSource ds;
if (DataSource.class.isAssignableFrom(impl) && !Boolean.parseBoolean(System.getProperty("org.apache.openejb.resource.jdbc.hot.deploy", "false"))) {
final ObjectRecipe recipe = new ObjectRecipe(impl);
recipe.allow(Option.CASE_INSENSITIVE_PROPERTIES);
recipe.allow(Option.IGNORE_MISSING_PROPERTIES);
recipe.allow(Option.NAMED_PARAMETERS);
recipe.setAllProperties(asProperties(definition));
DataSource dataSource = (DataSource) recipe.create();
if (managed) {
ds = new DbcpManagedDataSource(dataSource);
} else {
ds = new DbcpDataSource(dataSource);
}
} else {
ds = (org.apache.commons.dbcp.BasicDataSource) create(managed);
}
// force the driver class to be set
ds.setDriverClassName(impl.getName());
return ds;
}
private static Map<?, ?> asProperties(String definition) throws IOException {
final ByteArrayInputStream in = new ByteArrayInputStream(definition.getBytes());
final Properties properties = new Properties();
properties.load(in);
trimNotSupportedDataSourceProperties(properties);
return properties;
}
public static void trimNotSupportedDataSourceProperties(Properties properties) {
properties.remove("LoginTimeout");
}
public static DataSource create(boolean managed) {
org.apache.commons.dbcp.BasicDataSource ds;
if (managed) {
XAResourceWrapper xaResourceWrapper = SystemInstance.get().getComponent(XAResourceWrapper.class);
if (xaResourceWrapper != null) {
ds = new ManagedDataSourceWithRecovery(xaResourceWrapper);
} else {
ds = new BasicManagedDataSource();
}
} else {
ds = new BasicDataSource();
}
return ds;
}
public static class DbcpDataSource extends BasicDataSource {
private final DataSource dataSource;
public DbcpDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
@Override
protected ConnectionFactory createConnectionFactory() throws SQLException {
return new DataSourceConnectionFactory(dataSource, username, password);
}
@Override
public void setJdbcUrl(String url) {
// TODO This is a big whole and we will need to rework this
try {
// only works if hsql is available and datasource is an HSQL jdbcDataSource
final Class<?> hsql = this.getClass().getClassLoader().loadClass("org.hsqldb.jdbc.JDBCDataSource");
final Method setDatabase = hsql.getMethod("setDatabase", String.class);
setDatabase.setAccessible(true);
setDatabase.invoke(dataSource, url);
} catch (Throwable e) {
super.setUrl(url);
}
}
}
public static class DbcpManagedDataSource extends BasicManagedDataSource {
private final DataSource dataSource;
public DbcpManagedDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
@Override
public void setJdbcUrl(String url) {
// TODO This is a big whole and we will need to rework this
try {
// only works if hsql is available and datasource is an HSQL jdbcDataSource
final Class<?> hsql = this.getClass().getClassLoader().loadClass("org.hsqldb.jdbc.JDBCDataSource");
final Method setDatabase = hsql.getMethod("setDatabase", String.class);
setDatabase.setAccessible(true);
setDatabase.invoke(dataSource, url);
} catch (Throwable e) {
super.setUrl(url);
}
}
@Override
protected ConnectionFactory createConnectionFactory() throws SQLException {
if (dataSource instanceof XADataSource) {
// Create the XAConectionFactory using the XA data source
XADataSource xaDataSourceInstance = (XADataSource) dataSource;
XAConnectionFactory xaConnectionFactory = new DataSourceXAConnectionFactory(getTransactionManager(), xaDataSourceInstance, username, password);
setTransactionRegistry(xaConnectionFactory.getTransactionRegistry());
return xaConnectionFactory;
} else {
// If xa data source is not specified a DriverConnectionFactory is created and wrapped with a LocalXAConnectionFactory
ConnectionFactory connectionFactory = new DataSourceConnectionFactory(dataSource, username, password);
XAConnectionFactory xaConnectionFactory = new LocalXAConnectionFactory(getTransactionManager(), connectionFactory);
setTransactionRegistry(xaConnectionFactory.getTransactionRegistry());
return xaConnectionFactory;
}
}
public void setTransactionRegistry(TransactionRegistry registry) {
try {
final Field field = org.apache.commons.dbcp.managed.BasicManagedDataSource.class.getDeclaredField("transactionRegistry");
field.setAccessible(true);
field.set(this, registry);
} catch (Throwable e) {
throw new IllegalStateException(e);
}
}
}
}