001/* 002 * (C) Copyright 2013 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * Stephane Lacoin 018 */ 019package org.nuxeo.runtime.datasource.geronimo; 020 021import java.sql.Connection; 022import java.sql.SQLException; 023import java.sql.SQLFeatureNotSupportedException; 024import java.util.Hashtable; 025import java.util.logging.Logger; 026 027import javax.naming.Context; 028import javax.naming.Name; 029import javax.naming.NamingException; 030import javax.naming.RefAddr; 031import javax.naming.Reference; 032import javax.resource.ResourceException; 033import javax.resource.spi.InvalidPropertyException; 034import javax.resource.spi.ManagedConnectionFactory; 035import javax.sql.XADataSource; 036 037import org.apache.commons.logging.LogFactory; 038import org.nuxeo.runtime.datasource.PooledDataSourceRegistry; 039import org.nuxeo.runtime.datasource.PooledDataSourceRegistry.PooledDataSource; 040import org.nuxeo.runtime.jtajca.NuxeoConnectionManagerConfiguration; 041import org.nuxeo.runtime.jtajca.NuxeoConnectionManagerFactory; 042import org.nuxeo.runtime.jtajca.NuxeoContainer; 043import org.nuxeo.runtime.jtajca.NuxeoContainer.ConnectionManagerWrapper; 044import org.tranql.connector.NoExceptionsAreFatalSorter; 045import org.tranql.connector.jdbc.JDBCDriverMCF; 046import org.tranql.connector.jdbc.LocalDataSourceWrapper; 047import org.tranql.connector.jdbc.TranqlDataSource; 048import org.tranql.connector.jdbc.XADataSourceWrapper; 049 050public class PooledDataSourceFactory implements PooledDataSourceRegistry.Factory { 051 052 protected static class DataSource extends TranqlDataSource implements PooledDataSource { 053 054 protected ConnectionManagerWrapper wrapper; 055 056 public DataSource(ManagedConnectionFactory mcf, ConnectionManagerWrapper wrapper) { 057 super(mcf, wrapper); 058 this.wrapper = wrapper; 059 } 060 061 @Override 062 public void dispose() { 063 wrapper.dispose(); 064 } 065 066 @Override 067 public Connection getConnection(boolean noSharing) throws SQLException { 068 if (!noSharing) { 069 return getConnection(); 070 } 071 wrapper.enterNoSharing(); 072 try { 073 return getConnection(); 074 } finally { 075 wrapper.exitNoSharing(); 076 } 077 } 078 079 @Override 080 public Logger getParentLogger() throws SQLFeatureNotSupportedException { 081 throw new SQLFeatureNotSupportedException("not yet available"); 082 } 083 } 084 085 @Override 086 public Object getObjectInstance(Object obj, Name name, Context ctx, Hashtable<?, ?> environment) { 087 Reference ref = (Reference) obj; 088 ManagedConnectionFactory mcf; 089 ConnectionManagerWrapper cm; 090 try { 091 mcf = createFactory(ref, ctx); 092 cm = createManager(ref, ctx); 093 } catch (ResourceException | NamingException e) { 094 throw new RuntimeException(e); 095 } 096 return new DataSource(mcf, cm); 097 } 098 099 protected ConnectionManagerWrapper createManager(Reference ref, Context ctx) throws ResourceException { 100 NuxeoConnectionManagerConfiguration config = NuxeoConnectionManagerFactory.getConfig(ref); 101 String className = ref.getClassName(); 102 config.setXAMode(XADataSource.class.getName().equals(className)); 103 return NuxeoContainer.initConnectionManager(config); 104 } 105 106 protected ManagedConnectionFactory createFactory(Reference ref, Context ctx) throws NamingException, 107 InvalidPropertyException { 108 String className = ref.getClassName(); 109 if (XADataSource.class.getName().equals(className)) { 110 String user = refAttribute(ref, "User", ""); 111 String password = refAttribute(ref, "Password", ""); 112 String name = refAttribute(ref, "dataSourceJNDI", null); 113 XADataSource ds = NuxeoContainer.lookup(name, XADataSource.class); 114 XADataSourceWrapper wrapper = new XADataSourceWrapper(ds); 115 wrapper.setUserName(user); 116 wrapper.setPassword(password); 117 return wrapper; 118 } 119 if (javax.sql.DataSource.class.getName().equals(className)) { 120 String user = refAttribute(ref, "username", ""); 121 if (user.isEmpty()) { 122 user = refAttribute(ref, "user", ""); 123 if (!user.isEmpty()) { 124 LogFactory.getLog(PooledDataSourceFactory.class).warn( 125 "wrong attribute 'user' in datasource descriptor, should use 'username' instead"); 126 } 127 } 128 String password = refAttribute(ref, "password", ""); 129 String dsname = refAttribute(ref, "dataSourceJNDI", ""); 130 if (!dsname.isEmpty()) { 131 javax.sql.DataSource ds = NuxeoContainer.lookup(dsname, DataSource.class); 132 LocalDataSourceWrapper wrapper = new LocalDataSourceWrapper(ds); 133 wrapper.setUserName(user); 134 wrapper.setPassword(password); 135 return wrapper; 136 } 137 String name = refAttribute(ref, "driverClassName", null); 138 String url = refAttribute(ref, "url", null); 139 String sqlExceptionSorter = refAttribute(ref, "sqlExceptionSorter", 140 NoExceptionsAreFatalSorter.class.getName()); 141 boolean commitBeforeAutocommit = Boolean.valueOf(refAttribute(ref, "commitBeforeAutocommit", "true")).booleanValue(); 142 JDBCDriverMCF factory = new JDBCDriverMCF(); 143 factory.setDriver(name); 144 factory.setUserName(user); 145 factory.setPassword(password); 146 factory.setConnectionURL(url); 147 factory.setExceptionSorterClass(sqlExceptionSorter); 148 factory.setCommitBeforeAutocommit(commitBeforeAutocommit); 149 return factory; 150 } 151 throw new IllegalArgumentException("unsupported class " + className); 152 } 153 154 protected String refAttribute(Reference ref, String key, String defvalue) { 155 RefAddr addr = ref.get(key); 156 if (addr == null) { 157 if (defvalue == null) { 158 throw new IllegalArgumentException(key + " address is mandatory"); 159 } 160 return defvalue; 161 } 162 return (String) addr.getContent(); 163 } 164 165}