Package com.p6spy.engine.spy

Source Code of com.p6spy.engine.spy.P6DataSource

/*
* #%L
* P6Spy
* %%
* Copyright (C) 2013 P6Spy
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
package com.p6spy.engine.spy;

import java.io.PrintWriter;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.sql.Wrapper;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.StringTokenizer;
import java.util.logging.Logger;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.naming.Reference;
import javax.naming.Referenceable;
import javax.naming.StringRefAddr;
import javax.sql.CommonDataSource;
import javax.sql.ConnectionPoolDataSource;
import javax.sql.DataSource;
import javax.sql.PooledConnection;
import javax.sql.XAConnection;
import javax.sql.XADataSource;

import com.p6spy.engine.common.P6LogQuery;

@SuppressWarnings("serial")
public class P6DataSource implements DataSource, ConnectionPoolDataSource, XADataSource, Referenceable, Serializable {

  protected CommonDataSource rds;
  protected String rdsName;

  static {
    // make sure that the core has been initialized
    P6Core.initialize();
  }

  /**
   * Default no-arg constructor for Serialization
   */
  public P6DataSource() {
  }

  public P6DataSource(DataSource source) {
    rds = source;
  }

  public String getRealDataSource() {
    return rdsName;
  }

  public void setRealDataSource(String inVar) {
    rdsName = inVar;
  }

  protected synchronized void bindDataSource() throws SQLException {
    // we'll check in the synchronized section again (to prevent unnecessary reinitialization)
    if (null != rds) {
      return;
    }
   
    final P6SpyLoadableOptions options = P6SpyOptions.getActiveInstance();
   
    // can be set when object is bound to JDNI, or
    // can be loaded from spy.properties
    if (rdsName == null) {
      rdsName = options.getRealDataSource();
    }
    if (rdsName == null) {
      throw new SQLException("P6DataSource: no value for Real Data Source Name, cannot perform jndi lookup");
    }

    // lookup the real data source
    Hashtable env = null;
    String factory;

    if ((factory = options.getJNDIContextFactory()) != null) {
      env = new Hashtable();
      env.put(Context.INITIAL_CONTEXT_FACTORY, factory);
      String url = options.getJNDIContextProviderURL();
      if (url != null) {
        env.put(Context.PROVIDER_URL, url);
      }
      String custom = options.getJNDIContextCustom();
      if (custom != null) {
        StringTokenizer st = new StringTokenizer(custom, ",", false);
        while (st.hasMoreElements()) {
          String pair = st.nextToken();
          StringTokenizer pst = new StringTokenizer(pair, ";", false);
          if (pst.hasMoreElements()) {
            String name = pst.nextToken();
            if (pst.hasMoreElements()) {
              String value = pst.nextToken();
              env.put(name, value);
            }
          }
        }
      }
    }
    InitialContext ctx;
      try {
        if (env != null) {
          ctx = new InitialContext(env);
        } else {
          ctx = new InitialContext();
        }
        rds = (CommonDataSource) ctx.lookup(rdsName);
      } catch (NamingException e) {
        throw new SQLException("P6DataSource: naming exception during jndi lookup of Real Data Source Name of '" + rdsName + "'. "
            + e.getMessage(), e);
      }

    // Set any properties that the spy.properties file contains
    // that are supported by set methods in this class

    String dsProps = options.getRealDataSourceProperties();

    if (dsProps != null) {
      Hashtable props = null;

      StringTokenizer st = new StringTokenizer(dsProps, ",", false);
      while (st.hasMoreElements()) {
        String pair = st.nextToken();
        StringTokenizer pst = new StringTokenizer(pair, ";", false);
        if (pst.hasMoreElements()) {
          String name = pst.nextToken();
          if (pst.hasMoreElements()) {
            String value = pst.nextToken();
            if (props == null) {
              props = new Hashtable();
            }
            props.put(name, value);
          }
        }
      }
      Hashtable matchedProps = new Hashtable();
      if (props != null) {
        Class<?> klass = rds.getClass();

        // find the setter methods in the class, and
        // see if the datasource properties collected
        // from the spy.properties file contains any matching
        // name
        Method[] methods = klass.getMethods();
        for (int i = 0; methods != null && i < methods.length; i++) {
          Method method = methods[i];
          String methodName = method.getName();
          // see if the method is a setXXX
          if (methodName.startsWith("set")) {
            String propertyname = methodName.substring(3).toLowerCase();
            // found a setXXX method, so see if there is an XXX
            // property in the list read in from spy.properties.
            Enumeration keys = props.keys();
            while (keys.hasMoreElements()) {
              String key = (String) keys.nextElement();
              // all checks are all lower case
              if (key.toLowerCase().equals(propertyname)) {
                try {
                  // this is a parameter for the current method,
                  // so find out which supported type the method
                  // expects
                  String value = (String) props.get(key);
                  Class<?>[] types = method.getParameterTypes();
                  if (types[0].getName().equals(value.getClass().getName())) {
                    // the method expects a string
                    String[] args = new String[1];
                    args[0] = value;
                    P6LogQuery.debug("calling " + methodName + " on DataSource " + rdsName + " with " + value);
                    method.invoke(rds, args);
                    matchedProps.put(key, value);
                  } else if (types[0].isPrimitive() && "int".equals(types[0].getName())) {
                    // the method expects an int, so we pass an Integer
                    Integer[] args = new Integer[1];
                    args[0] = Integer.valueOf(value);
                    P6LogQuery.debug("calling " + methodName + " on DataSource " + rdsName + " with " + value);
                    method.invoke(rds, args);
                    matchedProps.put(key, value);
                  } else {
                    P6LogQuery.debug("method " + methodName + " on DataSource " + rdsName + " matches property "
                        + propertyname + " but expects unsupported type " + types[0].getName());
                    matchedProps.put(key, value);
                  }
                } catch (java.lang.IllegalAccessException e) {
                  throw new SQLException("spy.properties file includes" + " datasource property " + key + " for datasource "
                      + rdsName + " but access is denied to method " + methodName, e);
                } catch (java.lang.reflect.InvocationTargetException e) {
                  throw new SQLException("spy.properties file includes" + " datasource property " + key + " for datasource "
                      + rdsName + " but call method " + methodName + " fails", e);
                }
              }
            }
          }
        }

        Enumeration keys = props.keys();
        while (keys.hasMoreElements()) {

          String key = (String) keys.nextElement();

          if (!matchedProps.containsKey(key)) {
            P6LogQuery.debug("spy.properties file includes" + " datasource property " + key + " for datasource " + rdsName
                + " but class " + klass.getName() + " has no method" + " by that name");
          }
        }
      }
    }

    if (rds == null) {
      throw new SQLException("P6DataSource: jndi lookup for Real Data Source Name of '" + rdsName + "' failed, cannot bind named data source.");
    }
  }

  /**
   * Required method to support this class as a <CODE>Referenceable</CODE>.
   */
  @Override
  public Reference getReference() throws NamingException {
    final Reference reference = new Reference(getClass().getName(), P6DataSourceFactory.class.getName(), null);
    reference.add(new StringRefAddr("dataSourceName", getRealDataSource()));
    return reference;
  }

  @Override
  public int getLoginTimeout() throws SQLException {
    if (rds == null) {
      bindDataSource();
    }
    return rds.getLoginTimeout();
  }

  @Override
  public void setLoginTimeout(int inVar) throws SQLException {
    if (rds == null) {
      bindDataSource();
    }
    rds.setLoginTimeout(inVar);
  }

  @Override
  public PrintWriter getLogWriter() throws SQLException {
    if (rds == null) {
      bindDataSource();
    }
    return rds.getLogWriter();
  }

  @Override
  public void setLogWriter(PrintWriter inVar) throws SQLException {
    rds.setLogWriter(inVar);
  }

  @Override
  public Connection getConnection() throws SQLException {
    if (rds == null) {
      bindDataSource();
    }
    return P6Core.wrapConnection(((DataSource) rds).getConnection());
  }

  @Override
  public Connection getConnection(String username, String password) throws SQLException {
    if (rds == null) {
      bindDataSource();
    }
    return P6Core.wrapConnection(((DataSource) rds).getConnection(username, password));
  }

  /**
   * @param iface
   * @return
   * @throws SQLException
   * @see java.sql.Wrapper#isWrapperFor(java.lang.Class)
   */
  @Override
  public boolean isWrapperFor(Class<?> iface) throws SQLException {
    return ((Wrapper) rds).isWrapperFor(iface);
  }

  /**
   * @param <T>
   * @param iface
   * @return
   * @throws SQLException
   * @see java.sql.Wrapper#unwrap(java.lang.Class)
   */
  @Override
  public <T> T unwrap(Class<T> iface) throws SQLException {
    return ((DataSource) rds).unwrap(iface);
  }

  // since 1.7
  public Logger getParentLogger() throws SQLFeatureNotSupportedException {
    return rds.getParentLogger();
  }
 
  @Override
  public PooledConnection getPooledConnection() throws SQLException {
    return new P6XAConnection(castRealDS(ConnectionPoolDataSource.class).getPooledConnection());
  }
 
  @Override
  public PooledConnection getPooledConnection(String user, String password) throws SQLException {
    return new P6XAConnection(castRealDS(ConnectionPoolDataSource.class).getPooledConnection(user, password));
  }

  @Override
  public XAConnection getXAConnection() throws SQLException {
    return new P6XAConnection(castRealDS(XADataSource.class).getXAConnection());
  }

  @Override
  public XAConnection getXAConnection(String user, String password) throws SQLException {
    return new P6XAConnection(castRealDS(XADataSource.class).getXAConnection(user, password));
  }
 
  @SuppressWarnings("unchecked")
  <T> T castRealDS(Class<T> iface) throws SQLException {
    if (rds == null) {
      bindDataSource();
    }
   
    if (iface.isInstance(rds)) {
      return ((T) rds);
    } else if (isWrapperFor(iface)){
      return unwrap(iface);
    } else {
      throw new IllegalStateException("realdatasource type not supported: " + rds);
    }
  }

}
TOP

Related Classes of com.p6spy.engine.spy.P6DataSource

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.