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}