Package org.jboss.resource.adapter.jdbc.local

Source Code of org.jboss.resource.adapter.jdbc.local.LocalManagedConnectionFactory

/*
* JBoss, Home of Professional Open Source.
* Copyright 2006, Red Hat Middleware LLC, and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.resource.adapter.jdbc.local;

import java.beans.PropertyEditor;
import java.beans.PropertyEditorManager;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.Set;

import javax.resource.ResourceException;
import javax.resource.spi.ConnectionManager;
import javax.resource.spi.ConnectionRequestInfo;
import javax.resource.spi.ManagedConnection;
import javax.security.auth.Subject;
import javax.sql.DataSource;

import org.jboss.resource.JBossResourceException;
import org.jboss.resource.adapter.jdbc.BaseWrapperManagedConnectionFactory;
import org.jboss.resource.adapter.jdbc.URLSelectorStrategy;
import org.jboss.util.NestedRuntimeException;

/**
* LocalManagedConnectionFactory
*
* @author <a href="mailto:d_jencks@users.sourceforge.net">David Jencks</a>
* @author <a href="mailto:adrian@jboss.com">Adrian Brock</a>
* @version $Revision: 109982 $
*/
public class LocalManagedConnectionFactory extends BaseWrapperManagedConnectionFactory
{
   static final long serialVersionUID = 4698955390505160469L;

   private String driverClass;

   private transient Driver driver;
  
   private transient DataSource dataSource;
  
   private String connectionURL;
  
   private URLSelectorStrategy urlSelector;

   protected String connectionProperties;
  
   private boolean useDataSource;
  
   public LocalManagedConnectionFactory()
   {

   }

   @Override
   public Object createConnectionFactory(ConnectionManager cm) throws ResourceException
   {
      // check some invariants before they come back to haunt us
      if(driverClass == null)
         throw new JBossResourceException("driverClass is null");
      if(connectionURL == null && !getUseDataSource())
         throw new JBossResourceException("connectionURL is null");
     
      return super.createConnectionFactory(cm);
   }
  
   /**
    * Get the value of ConnectionURL.
    *
    * @return value of ConnectionURL.
    */
   public String getConnectionURL()
   {
      return connectionURL;
   }

   /**
    * Set the value of ConnectionURL.
    *
    * @param connectionURL  Value to assign to ConnectionURL.
    */
   public void setConnectionURL(final String connectionURL)
     //throws ResourceException
   {
      this.connectionURL = connectionURL;
      if(urlDelimiter!=null)
      {
         initUrlSelector();
      }
   }

   /**
    * Get the DriverClass value.
    *
    * @return the DriverClass value.
    */
   public String getDriverClass()
   {
      return driverClass;
   }

   /**
    * Set the DriverClass value.
    *
    * @param driverClass The new DriverClass value.
    */
   public synchronized void setDriverClass(final String driverClass)
   {
      this.driverClass = driverClass;
      driver = null;
   }

   /**
    * Get the value of connectionProperties.
    *
    * @return value of connectionProperties.
    */
   public String getConnectionProperties()
   {
      return connectionProperties;
   }

   /**
    * Set the value of connectionProperties.
    *
    * @param connectionProperties  Value to assign to connectionProperties.
    */
   public void setConnectionProperties(String connectionProperties)
   {
      this.connectionProperties = connectionProperties;
      connectionProps.clear();
      if (connectionProperties != null)
      {
         // Map any \ to \\
         connectionProperties = connectionProperties.replaceAll("\\\\", "\\\\\\\\");

         InputStream is = new ByteArrayInputStream(connectionProperties.getBytes());
         try
         {
            connectionProps.load(is);
         }
         catch (IOException ioe)
         {
            throw new NestedRuntimeException("Could not load connection properties", ioe);
         }
      }
   }

  
   public boolean getUseDataSource()
   {
     return useDataSource;
   }

   public void setUseDataSource(boolean useDataSource)
   {
     this.useDataSource = useDataSource;
   }

   public ManagedConnection createManagedConnection(Subject subject, ConnectionRequestInfo cri)
         throws javax.resource.ResourceException
   {
      Properties props = getConnectionProperties(subject, cri);
      // Some friendly drivers (Oracle, you guessed right) modify the props you supply.
      // Since we use our copy to identify compatibility in matchManagedConnection, we need
      // a pristine copy for our own use.  So give the friendly driver a copy.
      Properties copy = (Properties) props.clone();
      boolean trace = log.isTraceEnabled();
      if (trace)
      {
         // Make yet another copy to mask the password
         Properties logCopy = copy;
         if (copy.getProperty("password") != null)
         {
            logCopy = (Properties) props.clone();
            logCopy.setProperty("password", "--hidden--");
         }
         log.trace("Using properties: " + logCopy);
      }
     
      if(urlSelector!=null)
    {
        return getHALocalManagedConnection(props,copy);
      }
      else
    {
        return getLocalManagedConnection(props,copy);
      }
   }

   private LocalManagedConnection getLocalManagedConnection(Properties props,Properties copy)
       throws JBossResourceException
   {
       Connection con = null;
     try
     {
       if(!useDataSource)
       {
         String url = getConnectionURL();
         Driver d = getDriver(url);
         con = d.connect(url, copy);
         if (con == null)
           throw new JBossResourceException("Wrong driver class for this connection URL");        
       }
       else
       {
         final String user = props.getProperty("user");
         final String password = props.getProperty("password");
     
         con = (user != null)
           ? getDataSource().getConnection(user, password)
           : getDataSource().getConnection();

         if (con == null)
             throw new JBossResourceException("Could not create connection from data source " + getDriverClass());        
  
       }
      
       return new LocalManagedConnection(this, con, props, transactionIsolation, preparedStatementCacheSize);
     }
     catch (Throwable e)
     {
         if (con != null)
         {
            try
            {
               con.close();
            }
            catch (Throwable ignored)
            {
            }
         }
       throw new JBossResourceException("Could not create connection", e);
     }
   }

   private LocalManagedConnection getHALocalManagedConnection(Properties props,Properties copy)
       throws JBossResourceException  
   {
     boolean trace = log.isTraceEnabled();
    
      // try to get a connection as many times as many urls we have in the list
    for(int i = 0; i < urlSelector.getCustomSortedUrls().size(); ++i)
      {
      String url = (String)urlSelector.getUrlObject();
        if(trace)
        {
          log.trace("Trying to create a connection to " + url);
        }
       Connection con = null;
         try
         {
           Driver d = getDriver(url);
           con = d.connect(url, copy);
           if(con == null)
           {
             log.warn("Wrong driver class for this connection URL: " + url);
         urlSelector.failedUrlObject(url);
           }
           else
           {
               return new LocalManagedConnection(this, con, props, transactionIsolation, preparedStatementCacheSize);
           }
        }
        catch(Exception e)
        {
             if (con != null)
           {
              try
              {
                 con.close();
              }
              catch (Throwable ignored)
              {
              }
            }
          log.warn("Failed to create connection for " + url + ": " + e.getMessage());
        urlSelector.failedUrlObject(url);
        }
      }

      // we have supposedly tried all the urls
    throw new JBossResourceException(
           "Could not create connection using any of the URLs: " + urlSelector.getAllUrlObjects());
   }
  
   public void setURLDelimiter(String urlDelimiter)
       //throws ResourceException
   {
      super.urlDelimiter = urlDelimiter;
      if(getConnectionURL() != null)
      {
         initUrlSelector();
      }
   }
  
   protected void initUrlSelector()
    //throws ResourceException
   {
      boolean trace = log.isTraceEnabled();
     
      List urlsList = new ArrayList();
      String urlsStr = getConnectionURL();
      String url;
      int urlStart = 0;
      int urlEnd = urlsStr.indexOf(urlDelimiter);
      while(urlEnd > 0)
      {
         url = urlsStr.substring(urlStart, urlEnd);
         urlsList.add(url);
         urlStart = ++urlEnd;
         urlEnd = urlsStr.indexOf(urlDelimiter, urlEnd);
         if (trace)
          log.trace("added HA connection url: " + url);
      }

      if(urlStart != urlsStr.length())
      {
         url = urlsStr.substring(urlStart, urlsStr.length());
         urlsList.add(url);
         if (trace)
            log.trace("added HA connection url: " + url);
      }
    if(getUrlSelectorStrategyClassName()==null)
    {
    this.urlSelector = new URLSelector(urlsList);
    log.debug("Default URLSelectorStrategy is being used : "+urlSelector);
    }
    else
    {
    this.urlSelector = (URLSelectorStrategy)loadClass(getUrlSelectorStrategyClassName(),urlsList);
    log.debug("Customized URLSelectorStrategy is being used : "+urlSelector);
    }
   }
  
   // Default Implementaion of the URLSelectorStrategy
   public static class URLSelector implements URLSelectorStrategy
   {
      private final List urls;
      private int urlIndex;
      private String url;

      public URLSelector(List urls)
      {
         if(urls == null || urls.size() == 0)
         {
            throw new IllegalStateException("Expected non-empty list of connection URLs but got: " + urls);
         }
         this.urls = Collections.unmodifiableList(urls);
      }

      public synchronized String getUrl()
      {
         if(url == null)
         {
            if(urlIndex == urls.size())
            {
               urlIndex = 0;
            }
            url = (String)urls.get(urlIndex++);
         }
         return url;
      }

      public synchronized void failedUrl(String url)
      {
         if(url.equals(this.url))
         {
            this.url = null;
         }
      }

    /* URLSelectorStrategy Implementation goes here*/
    public List getCustomSortedUrls()
    {
     return urls;
    }
    public void failedUrlObject(Object urlObject)
    {
     failedUrl((String)urlObject);
    }
    public List getAllUrlObjects()
    {
     return urls;
      }
    public Object getUrlObject()
    {
     return getUrl();
    }

   }

   public ManagedConnection matchManagedConnections(final Set mcs, final Subject subject,
         final ConnectionRequestInfo cri) throws ResourceException
   {
      Properties newProps = getConnectionProperties(subject, cri);

      for (Iterator i = mcs.iterator(); i.hasNext();)
      {
         Object o = i.next();

         if (o instanceof LocalManagedConnection)
         {
            LocalManagedConnection mc = (LocalManagedConnection) o;

            //First check the properties
            if (mc.getProperties().equals(newProps))
            {
               //Next check to see if we are validating on matchManagedConnections
               if ((getValidateOnMatch() && mc.checkValid()) || !getValidateOnMatch())
               {

                  return mc;

               }

            }
         }
      }

      return null;
   }

   public int hashCode()
   {
      int result = 17;
   
      result = result * 37 + ((connectionURL == null) ? 0 : connectionURL.hashCode());
      result = result * 37 + ((driverClass == null) ? 0 : driverClass.hashCode());
      result = result * 37 + ((userName == null) ? 0 : userName.hashCode());
      result = result * 37 + ((password == null) ? 0 : password.hashCode());
      result = result * 37 + transactionIsolation;
      return result;
   }

   public boolean equals(Object other)
   {
      if (this == other)
         return true;
      if (getClass() != other.getClass())
         return false;
      LocalManagedConnectionFactory otherMcf = (LocalManagedConnectionFactory) other;
     
      if(!useDataSource)
      {
          return this.connectionURL.equals(otherMcf.connectionURL) && this.driverClass.equals(otherMcf.driverClass)
          && ((this.userName == null) ? otherMcf.userName == null : this.userName.equals(otherMcf.userName))
          && ((this.password == null) ? otherMcf.password == null : this.password.equals(otherMcf.password))
          && this.transactionIsolation == otherMcf.transactionIsolation;
       
      }
      else
      {
          return this.driverClass.equals(otherMcf.driverClass) && this.connectionProps.equals(otherMcf.connectionProps)
          && ((this.userName == null) ? otherMcf.userName == null : this.userName.equals(otherMcf.userName))
          && ((this.password == null) ? otherMcf.password == null : this.password.equals(otherMcf.password))
          && this.transactionIsolation == otherMcf.transactionIsolation;
       
      }
   }

   /**
    * Check the driver for the given URL.  If it is not registered already
    * then register it.
    *
    * @param url   The JDBC URL which we need a driver for.
    */
   protected synchronized Driver getDriver(final String url) throws ResourceException
   {
      boolean trace = log.isTraceEnabled();
     
      // don't bother if it is loaded already
      if (driver != null)
      {
         return driver;
      }
      if (trace)
         log.trace("Checking driver for URL: " + url);

      if (driverClass == null)
      {
         throw new JBossResourceException("No Driver class specified (url = " + url + ")!");
      }

      // Check if the driver is already loaded, if not then try to load it

      if (isDriverLoadedForURL(url))
      {
         return driver;
      } // end of if ()

      try
      {
         //try to load the class... this should register with DriverManager.
         Class clazz = Class.forName(driverClass, true, Thread.currentThread().getContextClassLoader());
         if (isDriverLoadedForURL(url))
            //return immediately, some drivers (Cloudscape) do not let you create an instance.
            return driver;

         //We loaded the class, but either it didn't register
         //and is not spec compliant, or is the wrong class.
         driver = (Driver) clazz.newInstance();
         DriverManager.registerDriver(driver);
         if (isDriverLoadedForURL(url))
            return driver;
         //We can even instantiate one, it must be the wrong class for the URL.
      }
      catch (Exception e)
      {
         throw new JBossResourceException("Failed to register driver for: " + driverClass, e);
      }

      throw new JBossResourceException("Apparently wrong driver class specified for URL: class: " + driverClass
            + ", url: " + url);
   }

   private boolean isDriverLoadedForURL(String url)
   {
      boolean trace = log.isTraceEnabled();
     
      try
      {
         driver = DriverManager.getDriver(url);
         if (trace)
            log.trace("Driver already registered for url: " + url);
         return true;
      }
      catch (Exception e)
      {
         if (trace)
            log.trace("Driver not yet registered for url: " + url);
         return false;
      }
   }

   protected String internalGetConnectionURL()
   {
      return connectionURL;
   }

   private synchronized DataSource getDataSource() throws ResourceException {
   
     if (dataSource == null)
        {
           if (driverClass == null)
              throw new JBossResourceException("No DataSourceClass supplied!");
          
           try
           {
              Class<?> clazz = Thread.currentThread().getContextClassLoader().loadClass(driverClass);
              dataSource = (DataSource) clazz.newInstance();
              Class<?>[] NOCLASSES = new Class[] {};
             
              for (Iterator i = this.connectionProps.keySet().iterator(); i.hasNext();)
              {
                 String name = (String) i.next();
                 String value = this.connectionProps.getProperty(name);     
                 char firstCharName = Character.toUpperCase(name.charAt(0));
                  if (name.length() > 1)
                       name = firstCharName+name.substring(1);
                  else
                     name = ""+firstCharName;                                                                                                  
                 //This is a bad solution.  On the other hand the only known example
                 // of a setter with no getter is for Oracle with password.
                 //Anyway, each xadatasource implementation should get its
                 //own subclass of this that explicitly sets the
                 //properties individually.
                 Class type = null;
                 try
                 {
                    Method getter = clazz.getMethod("get" + name, NOCLASSES);
                    type = getter.getReturnType();
                 }
                 catch (NoSuchMethodException e)
                 {
                    try
                    {
                       Method isMethod = clazz.getMethod("is" + name, NOCLASSES);
                       type = isMethod.getReturnType();
                    }
                    catch(NoSuchMethodException nsme)
                    {
                      log.warn("Property with name " + name + " could not be found for datasource class" + getDriverClass() + ". This property will be ignored.");
                      continue;
                    }
                 }

                 Method setter = clazz.getMethod("set" + name, new Class[] { type });
                 PropertyEditor editor = PropertyEditorManager.findEditor(type);
                 if (editor == null)
                    throw new JBossResourceException("No property editor found for type: " + type);
                 editor.setAsText(value);
                 setter.invoke(dataSource, new Object[] { editor.getValue() });
              }
           }
           catch (ClassNotFoundException cnfe)
           {
              throw new JBossResourceException("Class not found for DataSource " + getDriverClass(), cnfe);
           }
           catch (InstantiationException ie)
           {
              throw new JBossResourceException("Could not create an DataSource: ", ie);
           }
           catch (IllegalAccessException iae)
           {
              throw new JBossResourceException("Could not set a property: ", iae);
           }
           catch (IllegalArgumentException iae)
           {
              throw new JBossResourceException("Could not set a property: ", iae);
           }
           catch (InvocationTargetException ite)
           {
              throw new JBossResourceException("Could not invoke setter on DataSource: ", ite);
           }
           catch (NoSuchMethodException nsme)
           {
              throw new JBossResourceException("Could not find accessor on DataSource: ", nsme);
           }
        }
        return dataSource;

  }


  

}
TOP

Related Classes of org.jboss.resource.adapter.jdbc.local.LocalManagedConnectionFactory

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.