001package org.nuxeo.runtime.datasource.geronimo; 002 003import java.sql.Connection; 004import java.sql.SQLException; 005import java.sql.SQLFeatureNotSupportedException; 006import java.util.Hashtable; 007import java.util.logging.Logger; 008 009import javax.naming.Context; 010import javax.naming.Name; 011import javax.naming.NamingException; 012import javax.naming.RefAddr; 013import javax.naming.Reference; 014import javax.resource.ResourceException; 015import javax.resource.spi.InvalidPropertyException; 016import javax.resource.spi.ManagedConnectionFactory; 017import javax.sql.XADataSource; 018 019import org.apache.commons.logging.LogFactory; 020import org.nuxeo.runtime.datasource.PooledDataSourceRegistry; 021import org.nuxeo.runtime.datasource.PooledDataSourceRegistry.PooledDataSource; 022import org.nuxeo.runtime.jtajca.NuxeoConnectionManagerConfiguration; 023import org.nuxeo.runtime.jtajca.NuxeoConnectionManagerFactory; 024import org.nuxeo.runtime.jtajca.NuxeoContainer; 025import org.nuxeo.runtime.jtajca.NuxeoContainer.ConnectionManagerWrapper; 026import org.tranql.connector.NoExceptionsAreFatalSorter; 027import org.tranql.connector.jdbc.JDBCDriverMCF; 028import org.tranql.connector.jdbc.LocalDataSourceWrapper; 029import org.tranql.connector.jdbc.TranqlDataSource; 030import org.tranql.connector.jdbc.XADataSourceWrapper; 031 032public class PooledDataSourceFactory implements PooledDataSourceRegistry.Factory { 033 034 protected static class DataSource extends TranqlDataSource implements PooledDataSource { 035 036 protected ConnectionManagerWrapper wrapper; 037 038 public DataSource(ManagedConnectionFactory mcf, ConnectionManagerWrapper wrapper) { 039 super(mcf, wrapper); 040 this.wrapper = wrapper; 041 } 042 043 @Override 044 public void dispose() { 045 wrapper.dispose(); 046 } 047 048 @Override 049 public Connection getConnection(boolean noSharing) throws SQLException { 050 if (!noSharing) { 051 return getConnection(); 052 } 053 wrapper.enterNoSharing(); 054 try { 055 return getConnection(); 056 } finally { 057 wrapper.exitNoSharing(); 058 } 059 } 060 061 @Override 062 public Logger getParentLogger() throws SQLFeatureNotSupportedException { 063 throw new SQLFeatureNotSupportedException("not yet available"); 064 } 065 } 066 067 @Override 068 public Object getObjectInstance(Object obj, Name name, Context ctx, Hashtable<?, ?> environment) { 069 Reference ref = (Reference) obj; 070 ManagedConnectionFactory mcf; 071 ConnectionManagerWrapper cm; 072 try { 073 mcf = createFactory(ref, ctx); 074 cm = createManager(ref, ctx); 075 } catch (ResourceException | NamingException e) { 076 throw new RuntimeException(e); 077 } 078 return new DataSource(mcf, cm); 079 } 080 081 protected ConnectionManagerWrapper createManager(Reference ref, Context ctx) throws ResourceException { 082 NuxeoConnectionManagerConfiguration config = NuxeoConnectionManagerFactory.getConfig(ref); 083 String className = ref.getClassName(); 084 config.setXAMode(XADataSource.class.getName().equals(className)); 085 return NuxeoContainer.initConnectionManager(config); 086 } 087 088 protected ManagedConnectionFactory createFactory(Reference ref, Context ctx) throws NamingException, 089 InvalidPropertyException { 090 String className = ref.getClassName(); 091 if (XADataSource.class.getName().equals(className)) { 092 String user = refAttribute(ref, "User", ""); 093 String password = refAttribute(ref, "Password", ""); 094 String name = refAttribute(ref, "dataSourceJNDI", null); 095 XADataSource ds = NuxeoContainer.lookup(name, XADataSource.class); 096 XADataSourceWrapper wrapper = new XADataSourceWrapper(ds); 097 wrapper.setUserName(user); 098 wrapper.setPassword(password); 099 return wrapper; 100 } 101 if (javax.sql.DataSource.class.getName().equals(className)) { 102 String user = refAttribute(ref, "username", ""); 103 if (user.isEmpty()) { 104 user = refAttribute(ref, "user", ""); 105 if (!user.isEmpty()) { 106 LogFactory.getLog(PooledDataSourceFactory.class).warn( 107 "wrong attribute 'user' in datasource descriptor, should use 'username' instead"); 108 } 109 } 110 String password = refAttribute(ref, "password", ""); 111 String dsname = refAttribute(ref, "dataSourceJNDI", ""); 112 if (!dsname.isEmpty()) { 113 javax.sql.DataSource ds = NuxeoContainer.lookup(dsname, DataSource.class); 114 LocalDataSourceWrapper wrapper = new LocalDataSourceWrapper(ds); 115 wrapper.setUserName(user); 116 wrapper.setPassword(password); 117 return wrapper; 118 } 119 String name = refAttribute(ref, "driverClassName", null); 120 String url = refAttribute(ref, "url", null); 121 String sqlExceptionSorter = refAttribute(ref, "sqlExceptionSorter", 122 NoExceptionsAreFatalSorter.class.getName()); 123 boolean commitBeforeAutocommit = Boolean.valueOf(refAttribute(ref, "commitBeforeAutocommit", "true")).booleanValue(); 124 JDBCDriverMCF factory = new JDBCDriverMCF(); 125 factory.setDriver(name); 126 factory.setUserName(user); 127 factory.setPassword(password); 128 factory.setConnectionURL(url); 129 factory.setExceptionSorterClass(sqlExceptionSorter); 130 factory.setCommitBeforeAutocommit(commitBeforeAutocommit); 131 return factory; 132 } 133 throw new IllegalArgumentException("unsupported class " + className); 134 } 135 136 protected String refAttribute(Reference ref, String key, String defvalue) { 137 RefAddr addr = ref.get(key); 138 if (addr == null) { 139 if (defvalue == null) { 140 throw new IllegalArgumentException(key + " address is mandatory"); 141 } 142 return defvalue; 143 } 144 return (String) addr.getContent(); 145 } 146 147}