package net.ttddyy.dsproxy.support.jndi; import net.ttddyy.dsproxy.listener.logging.CommonsLogLevel; import net.ttddyy.dsproxy.listener.QueryExecutionListener; import net.ttddyy.dsproxy.listener.logging.SLF4JLogLevel; import net.ttddyy.dsproxy.support.ProxyDataSourceBuilder; import net.ttddyy.dsproxy.transform.ParameterTransformer; import net.ttddyy.dsproxy.transform.QueryTransformer; import javax.naming.*; import javax.naming.spi.ObjectFactory; import javax.sql.DataSource; import java.util.HashSet; import java.util.Hashtable; import java.util.Set; /** * JNDI ObjectFactory to create {@link net.ttddyy.dsproxy.support.ProxyDataSource}. * * <pre>{@code * <Resource name="jdbc/global/myProxy" * auth="Container" * type="net.ttddyy.dsproxy.support.ProxyDataSource" * factory="net.ttddyy.dsproxy.support.jndi.ProxyDataSourceObjectFactory" * description="ds" * listeners="count,sysout,org.example.SampleListener" * proxyName="DS-PROXY" * format="json" * dataSource="[REFERENCE_TO_ACTUAL_DATASOURCE_RESOURCE]" <!-- ex: java:jdbc/global/myDS --> * /> * }</pre> * * Parameters: * <ul> * <li> <b>dataSource <i>(required)</i></b>: Reference to actual datasource resource. ex: java:jdbc/global/myDS * <li> <b>proxyName</b>: ProxyDataSource name * <li> <b>logLevel</b>: Loglevel for commons-logging or slf4j. ex: DEBUG, INFO, etc. * <li> <b>listeners</b>: Fully qualified class name of `QueryExecutionListener` implementation class,or predefined values below. Can be comma delimited. * <li> <b>queryTransformer</b>: Fully qualified class name of `QueryTransformer` implementation class. * <li> <b>parameterTransformer</b>: Fully qualified class name of `ParameterTransformer` implementation class. * </ul> * * <i>listeners</i> parameter: * <ul> * <li> <b>sysout</b>: alias to `net.ttddyy.dsproxy.listener.logging.SystemOutQueryLoggingListener` * <li> <b>commons</b>: alias to `net.ttddyy.dsproxy.listener.logging.CommonsQueryLoggingListener` * <li> <b>slf4j</b>: alias to `net.ttddyy.dsproxy.listener.logging.SLF4JQueryLoggingListener` * <li> <b>count</b>: alias to `net.ttddyy.dsproxy.listener.DataSourceQueryCountListener` * <li> <b>x.y.z.MyQueryExecutionListener</b>: Fully qualified class name of `QueryExecutionListener` implementation * </ul> * * <i>format</i> parameter: * <ul> * <li> <b>json</b>: set logging output format as JSON * </ul> * * @author Tadaya Tsuyukubo * @since 1.3 */ public class ProxyDataSourceObjectFactory implements ObjectFactory { @Override public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception { if (obj == null || !(obj instanceof Reference)) { return null; } Reference reference = (Reference) obj; String dataSourceJndiName = getContentFromReference(reference, "dataSource"); String proxyDataSourceName = getContentFromReference(reference, "proxyName"); String listenerNames = getContentFromReference(reference, "listeners"); String logLevel = getContentFromReference(reference, "logLevel"); String loggerName = getContentFromReference(reference, "loggerName"); String format = getContentFromReference(reference, "format"); String queryTransformer = getContentFromReference(reference, "queryTransformer"); String parameterTransformer = getContentFromReference(reference, "parameterTransformer"); // retrieve datasource from JNDI Object dataSourceResource = new InitialContext().lookup(dataSourceJndiName); if (dataSourceResource == null) { throw new Exception(String.format("%s is not available.", dataSourceJndiName)); } else if (!(dataSourceResource instanceof DataSource)) { throw new Exception(String.format("%s is not DataSource: %s", dataSourceJndiName, dataSourceResource)); } DataSource dataSource = (DataSource) dataSourceResource; // builder ProxyDataSourceBuilder builder = ProxyDataSourceBuilder.create(dataSource); if (proxyDataSourceName != null) { builder.name(proxyDataSourceName); } if (listenerNames != null) { for (String listenerName : getListenerNames(listenerNames)) { if ("commons".equalsIgnoreCase(listenerName)) { boolean hasLogLevel = logLevel != null; boolean hasLoggerName = loggerName != null; if (hasLogLevel && hasLoggerName) { builder.logQueryByCommons(CommonsLogLevel.valueOf(logLevel.toUpperCase()), loggerName); } else if (hasLogLevel) { builder.logQueryByCommons(CommonsLogLevel.valueOf(logLevel.toUpperCase())); } else if (hasLoggerName) { builder.logQueryByCommons(loggerName); } else { builder.logQueryByCommons(); } } else if ("slf4j".equalsIgnoreCase(listenerName)) { boolean hasLogLevel = logLevel != null; boolean hasLogName = loggerName != null; if (hasLogLevel && hasLogName) { builder.logQueryBySlf4j(SLF4JLogLevel.valueOf(logLevel.toUpperCase()), loggerName); } else if (hasLogLevel) { builder.logQueryBySlf4j(SLF4JLogLevel.valueOf(logLevel.toUpperCase())); } else if (hasLogName) { builder.logQueryBySlf4j(loggerName); } else { builder.logQueryBySlf4j(); } } else if ("sysout".equalsIgnoreCase(listenerName)) { builder.logQueryToSysOut(); } else if ("count".equalsIgnoreCase(listenerName)) { builder.countQuery(); } else { QueryExecutionListener listener = createNewInstance(QueryExecutionListener.class, listenerName); builder.listener(listener); } } if (format != null && "json".equals(format.toLowerCase())) { builder.asJson(); } } if (queryTransformer != null) { QueryTransformer transformer = createNewInstance(QueryTransformer.class, queryTransformer); builder.queryTransformer(transformer); } if (parameterTransformer != null) { ParameterTransformer transformer = createNewInstance(ParameterTransformer.class, parameterTransformer); builder.parameterTransformer(transformer); } return builder.build(); } @SuppressWarnings("unchecked") protected <T> T createNewInstance(Class<T> clazz, String className) throws Exception { try { return (T) Class.forName(className).newInstance(); } catch (Exception e) { String msg = String.format("Failed to create %s - %s: %s", clazz.getSimpleName(), e.getClass().getName(), e.getMessage()); throw new Exception(msg); } } protected String getContentFromReference(Reference reference, String key) { RefAddr refAddr = reference.get(key); if (refAddr == null) { return null; } return refAddr.getContent().toString(); } protected String[] getListenerNames(String listenerNames) { Set<String> listenerNameSet = new HashSet<String>(); for (String listenerName : listenerNames.split(",")) { listenerNameSet.add(trim(listenerName)); } return listenerNameSet.toArray(new String[listenerNameSet.size()]); } protected String trim(String s) { int length = s.length(); StringBuilder sb = new StringBuilder(length); for (int i = 0; i < length; i++) { char c = s.charAt(i); if (!Character.isWhitespace(c)) { sb.append(c); } } return sb.toString(); } }