Java tutorial
/* * Copyright (c) 2000-2004 Netspective Communications LLC. All rights reserved. * * Netspective Communications LLC ("Netspective") permits redistribution, modification and use of this file in source * and binary form ("The Software") under the Netspective Source License ("NSL" or "The License"). The following * conditions are provided as a summary of the NSL but the NSL remains the canonical license and must be accepted * before using The Software. Any use of The Software indicates agreement with the NSL. * * 1. Each copy or derived work of The Software must preserve the copyright notice and this notice unmodified. * * 2. Redistribution of The Software is allowed in object code form only (as Java .class files or a .jar file * containing the .class files) and only as part of an application that uses The Software as part of its primary * functionality. No distribution of the package is allowed as part of a software development kit, other library, * or development tool without written consent of Netspective. Any modified form of The Software is bound by these * same restrictions. * * 3. Redistributions of The Software in any form must include an unmodified copy of The License, normally in a plain * ASCII text file unless otherwise agreed to, in writing, by Netspective. * * 4. The names "Netspective", "Axiom", "Commons", "Junxion", and "Sparx" are trademarks of Netspective and may not be * used to endorse or appear in products derived from The Software without written consent of Netspective. * * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT A WARRANTY OF ANY KIND. ALL EXPRESS OR IMPLIED REPRESENTATIONS AND * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, * ARE HEREBY DISCLAIMED. * * NETSPECTIVE AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE OR ANY THIRD PARTY AS A * RESULT OF USING OR DISTRIBUTING THE SOFTWARE. IN NO EVENT WILL NETSPECTIVE OR ITS LICENSORS BE LIABLE FOR ANY LOST * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THE SOFTWARE, EVEN * IF IT HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. */ package com.netspective.axiom.connection; import java.sql.Connection; import java.sql.SQLException; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; import javax.naming.NamingException; import javax.sql.DataSource; import org.apache.commons.dbcp.ConnectionFactory; import org.apache.commons.dbcp.DriverManagerConnectionFactory; import org.apache.commons.dbcp.PoolableConnectionFactory; import org.apache.commons.dbcp.PoolingDataSource; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.commons.pool.ObjectPool; import org.apache.commons.pool.impl.GenericObjectPool; import com.netspective.axiom.ConnectionProvider; import com.netspective.axiom.ConnectionProviderEntries; import com.netspective.axiom.ConnectionProviderEntry; import com.netspective.commons.value.ValueContext; import com.netspective.commons.value.ValueSource; import com.netspective.commons.value.source.StaticValueSource; import com.netspective.commons.xdm.XdmBitmaskedFlagsAttribute; import com.netspective.commons.xdm.XdmEnumeratedAttribute; import com.netspective.commons.xdm.XmlDataModelSchema; public class JakartaCommonsDbcpConnectionProvider implements ConnectionProvider { private static final Log log = LogFactory.getLog(JakartaCommonsDbcpConnectionProvider.class); private Map dataSourcesInfo = Collections.synchronizedMap(new HashMap()); private Map dataSources = Collections.synchronizedMap(new HashMap()); private int dataSourceInfoIndex = 0; private String name = "jakarta-dbcp"; public static final XmlDataModelSchema.Options XML_DATA_MODEL_SCHEMA_OPTIONS = new XmlDataModelSchema.Options() .setIgnorePcData(true); public static class DataSourceInfo { public static final XmlDataModelSchema.Options XML_DATA_MODEL_SCHEMA_OPTIONS = new XmlDataModelSchema.Options() .setIgnorePcData(true); private String name; private ValueSource driverClass = new StaticValueSource(""); private ValueSource url = new StaticValueSource(""); private ValueSource user = new StaticValueSource(""); private ValueSource password = new StaticValueSource(""); private GenericObjectPool.Config poolConfig = new GenericObjectPool.Config(); private TestOnActionsFlags testFlags = createTestFlags(); public String getName() { return name; } public void setName(String name) { this.name = name; } public ValueSource getDriverClass() { return driverClass; } public void setDriverClass(ValueSource driverClass) { this.driverClass = driverClass; } public ValueSource getUrl() { return url; } public void setUrl(ValueSource url) { this.url = url; } public ValueSource getUser() { return user; } public void setUser(ValueSource user) { this.user = user; } public ValueSource getPassword() { return password; } public void setPassword(ValueSource password) { this.password = password; } public void setMaxConnections(int maxConns) { this.poolConfig.maxActive = maxConns; } public void setMaxIdleConnections(int maxIdleConns) { this.poolConfig.maxIdle = maxIdleConns; } public void setMaxWait(long maxWait) { this.poolConfig.maxWait = maxWait; } public void setTimeBetweenEvictions(long timeBetweenEvictions) { this.poolConfig.timeBetweenEvictionRunsMillis = timeBetweenEvictions; } public void setMinEvictableIdleTime(long minEvictableIdleTime) { this.poolConfig.minEvictableIdleTimeMillis = minEvictableIdleTime; } public void setNumTestsPerEviction(int numTestsPerEviction) { this.poolConfig.numTestsPerEvictionRun = numTestsPerEviction; } public GenericObjectPool.Config getPoolConfig() { return poolConfig; } //****************************************************************** static public class TestOnActionsFlags extends XdmBitmaskedFlagsAttribute { public static final XmlDataModelSchema.Options XML_DATA_MODEL_SCHEMA_OPTIONS = new XmlDataModelSchema.Options() .setIgnorePcData(true); private static final int TEST_ON_BORROW = 1; private static final int TEST_ON_RETURN = TEST_ON_BORROW * 2; private static final int TEST_WHILE_IDLE = TEST_ON_RETURN * 2; private static FlagDefn[] FLAG_DEFNS = new FlagDefn[] { new FlagDefn(ACCESS_XDM, "TEST_ON_BORROW", TEST_ON_BORROW), new FlagDefn(ACCESS_XDM, "TEST_ON_RETURN", TEST_ON_RETURN), new FlagDefn(ACCESS_XDM, "TEST_WHILE_IDLE", TEST_WHILE_IDLE), }; public FlagDefn[] getFlagsDefns() { return FLAG_DEFNS; } } static public class ExhaustedAction extends XdmEnumeratedAttribute { public static final XmlDataModelSchema.Options XML_DATA_MODEL_SCHEMA_OPTIONS = new XmlDataModelSchema.Options() .setIgnorePcData(true); private static final String[] VALUES = new String[] { "WHEN_EXHAUSTED_FAIL", "WHEN_EXHAUSTED_BLOCK", "WHEN_EXHAUSTED_GROW" }; public String[] getValues() { return VALUES; } } public TestOnActionsFlags createTestFlags() { return new TestOnActionsFlags(); } public void setTestFlags(TestOnActionsFlags testFlags) { this.testFlags.copy(testFlags); poolConfig.testOnBorrow = testFlags.flagIsSet(TestOnActionsFlags.TEST_ON_BORROW); poolConfig.testOnReturn = testFlags.flagIsSet(TestOnActionsFlags.TEST_ON_RETURN); poolConfig.testWhileIdle = testFlags.flagIsSet(TestOnActionsFlags.TEST_WHILE_IDLE); } public ExhaustedAction createExhaustedAction() { return new ExhaustedAction(); } public void setExhaustedAction(ExhaustedAction exhaustedAction) { poolConfig.whenExhaustedAction = (byte) exhaustedAction.getValueIndex(); } } public DataSourceInfo createDataSource() { return new DataSourceInfo(); } public void addDataSource(DataSourceInfo dataSourceInfo) { if (dataSourceInfo.getName() == null || dataSourceInfo.getName().equals("")) { dataSourceInfo.setName("data-source-" + this.dataSourceInfoIndex); } this.dataSourceInfoIndex++; dataSourcesInfo.put(dataSourceInfo.getName(), dataSourceInfo); //TODO: Figure out how to set the default data source on SqlManager //if (dataSourceInfo.isDefault()) Do something } public class DbcpPoolingDataSource extends PoolingDataSource { public DbcpPoolingDataSource(ObjectPool objectPool) { super(objectPool); } public ObjectPool getPool() { return _pool; } } protected DataSource createDataSource(ValueContext vc, String dataSourceId) throws NamingException { DataSourceInfo dataSourceInfo = (DataSourceInfo) dataSourcesInfo.get(dataSourceId); if (dataSourceInfo == null) throw new NamingException("Data Source: '" + dataSourceId + "' not defined as a data source for Jakarta Commons DBCP provider."); String driverClassName = dataSourceInfo.driverClass.getTextValueOrBlank(vc); try { Class.forName(driverClassName); } catch (ClassNotFoundException cnfe) { log.error("Driver '" + driverClassName + "' not found for name '" + dataSourceId + "'"); throw new NamingException("Driver '" + driverClassName + "' not found for name '" + dataSourceId + "'"); } if (log.isDebugEnabled()) { log.debug("Initializing data source: '" + dataSourceInfo.getName() + "'\n" + " driver: '" + driverClassName + "'\n" + " url: '" + dataSourceInfo.url.getTextValueOrBlank(vc) + "'\n" + " user: '" + dataSourceInfo.user.getTextValueOrBlank(vc) + "'\n" + " password: '" + dataSourceInfo.password.getTextValueOrBlank(vc) + "'"); } ObjectPool connectionPool = new GenericObjectPool(null, dataSourceInfo.getPoolConfig()); ConnectionFactory connectionFactory = new DriverManagerConnectionFactory( dataSourceInfo.url.getTextValueOrBlank(vc), dataSourceInfo.user.getTextValueOrBlank(vc), dataSourceInfo.password.getTextValueOrBlank(vc)); try { //The reference to this object is not used within this method. It's constuctor sets a reference of itself //in the conectionPool object we pass as a parameter. PoolableConnectionFactory poolableConnectionFactory = new PoolableConnectionFactory(connectionFactory, connectionPool, null, null, false, true); } catch (IllegalStateException e) { log.error("Trying to reset the pool factory for data source: '" + dataSourceInfo.name + "' when the pool objects are already in use, thus the pool is active."); return null; } catch (Exception e) //Generic Exception being caught here because Constructor of PoolableConnectionFactory is declared that way { log.error( "An Exception was encountered when creating the pool factory in the Jakarta Commons DBCP framework.", e); return null; } DbcpPoolingDataSource dataSource = new DbcpPoolingDataSource(connectionPool); return dataSource; } /** * Returns the configured info object associated with a datasource. This will contain more information then what * a {@link javax.sql.DataSource} will reveal. * * @param dataSourceId datasource name * * @return DataSourceInfo object configured in the connection provider */ public DataSourceInfo getDataSourceInfo(String dataSourceId) { return (DataSourceInfo) dataSourcesInfo.get(dataSourceId); } public DataSource getDataSource(ValueContext vc, String dataSourceId) throws NamingException { DataSource dataSource = (DataSource) dataSources.get(dataSourceId); if (dataSource == null) { dataSource = createDataSource(vc, dataSourceId); if (dataSource != null) dataSources.put(dataSourceId, dataSource); } return dataSource; } public String getConnectionProviderName() { return name; } public void setName(String name) { this.name = name; } public final Connection getConnection(ValueContext vc, String dataSourceId) throws NamingException, SQLException { if (dataSourceId == null) throw new NamingException("name is NULL in " + this.getClass().getName() + ".getConnection(String)"); DataSource source = getDataSource(vc, dataSourceId); if (source == null) { if (log.isDebugEnabled()) log.debug("name not found in " + JakartaCommonsDbcpConnectionProvider.class.getName() + ".getConnection('" + dataSourceId + "'). Available: " + getAvailableDataSources()); throw new NamingException( "Data source '" + dataSourceId + "' not found in Jakarta Commons DBCP provider."); } return source.getConnection(); } public ConnectionProviderEntry getDataSourceEntry(ValueContext vc, String dataSourceId) { try { DataSource source = getDataSource(vc, dataSourceId); if (source == null) return null; return getDataSourceEntry(dataSourceId, source); } catch (Exception ex) { log.error(JakartaCommonsDbcpConnectionProvider.class.getName() + ".getDataSourceEntry('" + dataSourceId + "')", ex); return null; } } public ConnectionProviderEntry getDataSourceEntry(String dataSourceId, DataSource source) throws SQLException { BasicConnectionProviderEntry result = new BasicConnectionProviderEntry(); result.init(dataSourceId, source); return result; } public Set getAvailableDataSources() { return dataSourcesInfo.keySet(); } public ConnectionProviderEntries getDataSourceEntries(ValueContext vc) { ConnectionProviderEntries entries = new BasicConnectionProviderEntries(); Set available = getAvailableDataSources(); for (Iterator i = available.iterator(); i.hasNext();) { ConnectionProviderEntry entry = getDataSourceEntry(vc, (String) i.next()); if (entry != null) entries.add(entry); } return entries; } public Class getUnderlyingImplementationClass() { return DataSourceInfo.class; } }