Save This Page
Home » jboss-5.0.0.CR1-src » org.jboss.resource.adapter » jdbc » local » [javadoc | source]
    1   /*
    2    * JBoss, Home of Professional Open Source.
    3    * Copyright 2006, Red Hat Middleware LLC, and individual contributors
    4    * as indicated by the @author tags. See the copyright.txt file in the
    5    * distribution for a full listing of individual contributors.
    6    *
    7    * This is free software; you can redistribute it and/or modify it
    8    * under the terms of the GNU Lesser General Public License as
    9    * published by the Free Software Foundation; either version 2.1 of
   10    * the License, or (at your option) any later version.
   11    *
   12    * This software is distributed in the hope that it will be useful,
   13    * but WITHOUT ANY WARRANTY; without even the implied warranty of
   14    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
   15    * Lesser General Public License for more details.
   16    *
   17    * You should have received a copy of the GNU Lesser General Public
   18    * License along with this software; if not, write to the Free
   19    * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
   20    * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
   21    */
   22   package org.jboss.resource.adapter.jdbc.local;
   23   
   24   import org.jboss.resource.adapter.jdbc.URLSelectorStrategy;
   25   import java.io.ByteArrayInputStream;
   26   import java.io.IOException;
   27   import java.io.InputStream;
   28   import java.sql.Connection;
   29   import java.sql.Driver;
   30   import java.sql.DriverManager;
   31   import java.util.ArrayList;
   32   import java.util.Collections;
   33   import java.util.Iterator;
   34   import java.util.Properties;
   35   import java.util.List;
   36   import java.util.Set;
   37   
   38   import javax.resource.ResourceException;
   39   import javax.resource.spi.ConnectionManager;
   40   import javax.resource.spi.ConnectionRequestInfo;
   41   import javax.resource.spi.ManagedConnection;
   42   import javax.security.auth.Subject;
   43   
   44   import org.jboss.resource.JBossResourceException;
   45   import org.jboss.resource.adapter.jdbc.BaseWrapperManagedConnectionFactory;
   46   import org.jboss.util.NestedRuntimeException;
   47   
   48   /**
   49    * LocalManagedConnectionFactory
   50    *
   51    * @author <a href="mailto:d_jencks@users.sourceforge.net">David Jencks</a>
   52    * @author <a href="mailto:adrian@jboss.com">Adrian Brock</a>
   53    * @version $Revision: 73443 $
   54    */
   55   public class LocalManagedConnectionFactory extends BaseWrapperManagedConnectionFactory
   56   {
   57      static final long serialVersionUID = 4698955390505160469L;
   58   
   59      private String driverClass;
   60   
   61      private transient Driver driver;
   62   
   63      private String connectionURL;
   64      
   65      private URLSelectorStrategy urlSelector;
   66   
   67      protected String connectionProperties;
   68   
   69      public LocalManagedConnectionFactory()
   70      {
   71   
   72      }
   73   
   74      @Override
   75      public Object createConnectionFactory(ConnectionManager cm) throws ResourceException
   76      {
   77         // check some invariants before they come back to haunt us
   78         if(driverClass == null)
   79            throw new JBossResourceException("driverClass is null");
   80         if(connectionURL == null)
   81            throw new JBossResourceException("connectionURL is null");
   82         
   83         return super.createConnectionFactory(cm);
   84      }
   85      
   86      /**
   87       * Get the value of ConnectionURL.
   88       * 
   89       * @return value of ConnectionURL.
   90       */
   91      public String getConnectionURL()
   92      {
   93         return connectionURL;
   94      }
   95   
   96      /**
   97       * Set the value of ConnectionURL.
   98       * 
   99       * @param connectionURL  Value to assign to ConnectionURL.
  100       */
  101      public void setConnectionURL(final String connectionURL) 
  102   	   //throws ResourceException
  103      {
  104         this.connectionURL = connectionURL;
  105         if(urlDelimiter!=null)
  106         {
  107            initUrlSelector();
  108         }
  109      }
  110   
  111      /**
  112       * Get the DriverClass value.
  113       * 
  114       * @return the DriverClass value.
  115       */
  116      public String getDriverClass()
  117      {
  118         return driverClass;
  119      }
  120   
  121      /**
  122       * Set the DriverClass value.
  123       * 
  124       * @param driverClass The new DriverClass value.
  125       */
  126      public synchronized void setDriverClass(final String driverClass)
  127      {
  128         this.driverClass = driverClass;
  129         driver = null;
  130      }
  131   
  132      /**
  133       * Get the value of connectionProperties.
  134       * 
  135       * @return value of connectionProperties.
  136       */
  137      public String getConnectionProperties()
  138      {
  139         return connectionProperties;
  140      }
  141   
  142      /**
  143       * Set the value of connectionProperties.
  144       * 
  145       * @param connectionProperties  Value to assign to connectionProperties.
  146       */
  147      public void setConnectionProperties(String connectionProperties)
  148      {
  149         this.connectionProperties = connectionProperties;
  150         connectionProps.clear();
  151         if (connectionProperties != null)
  152         {
  153            // Map any \ to \\
  154            connectionProperties = connectionProperties.replaceAll("\\\\", "\\\\\\\\");
  155   
  156            InputStream is = new ByteArrayInputStream(connectionProperties.getBytes());
  157            try
  158            {
  159               connectionProps.load(is);
  160            }
  161            catch (IOException ioe)
  162            {
  163               throw new NestedRuntimeException("Could not load connection properties", ioe);
  164            }
  165         }
  166      }
  167   
  168      public ManagedConnection createManagedConnection(Subject subject, ConnectionRequestInfo cri)
  169            throws javax.resource.ResourceException
  170      {
  171         Properties props = getConnectionProperties(subject, cri);
  172         // Some friendly drivers (Oracle, you guessed right) modify the props you supply.
  173         // Since we use our copy to identify compatibility in matchManagedConnection, we need
  174         // a pristine copy for our own use.  So give the friendly driver a copy.
  175         Properties copy = (Properties) props.clone();
  176         boolean trace = log.isTraceEnabled();
  177         if (trace)
  178         {
  179            // Make yet another copy to mask the password
  180            Properties logCopy = copy;
  181            if (copy.getProperty("password") != null)
  182            {
  183               logCopy = (Properties) props.clone();
  184               logCopy.setProperty("password", "--hidden--");
  185            }
  186            log.trace("Using properties: " + logCopy);
  187         }
  188         
  189         if(urlSelector!=null)
  190   	  {
  191       	  return getHALocalManagedConnection(props,copy);
  192         }
  193         else
  194   	  {
  195       	  return getLocalManagedConnection(props,copy);
  196         }
  197      }
  198   
  199      private LocalManagedConnection getLocalManagedConnection(Properties props,Properties copy) 
  200      		throws JBossResourceException
  201      {
  202          Connection con = null;
  203   	   try
  204   	   {
  205   		   String url = getConnectionURL();
  206   		   Driver d = getDriver(url); 
  207   		   con = d.connect(url, copy);
  208   		   if (con == null)
  209   			   throw new JBossResourceException("Wrong driver class for this connection URL");
  210   
  211   		   return new LocalManagedConnection(this, con, props, transactionIsolation, preparedStatementCacheSize);
  212   	   }
  213   	   catch (Throwable e)
  214   	   {
  215   	       if (con != null)
  216   	       {
  217   	          try
  218   	          {
  219   	             con.close();
  220   	          }
  221   	          catch (Throwable ignored)
  222   	          {
  223   	          }
  224   	       }
  225   		   throw new JBossResourceException("Could not create connection", e);
  226   	   }
  227      }
  228   
  229      private LocalManagedConnection getHALocalManagedConnection(Properties props,Properties copy)
  230      		throws JBossResourceException   
  231      {
  232   	   boolean trace = log.isTraceEnabled();
  233   	   
  234         // try to get a connection as many times as many urls we have in the list
  235   	  for(int i = 0; i < urlSelector.getCustomSortedUrls().size(); ++i)
  236         {
  237   		  String url = (String)urlSelector.getUrlObject();
  238       	  if(trace)
  239       	  {
  240       		  log.trace("Trying to create a connection to " + url);
  241       	  }
  242       	 Connection con = null;
  243            try
  244            {
  245           	 Driver d = getDriver(url); 
  246           	 con = d.connect(url, copy);
  247   	         if(con == null)
  248   	         {
  249   	        	 log.warn("Wrong driver class for this connection URL: " + url);
  250   				 urlSelector.failedUrlObject(url);
  251   	         }
  252   	         else
  253   	         {
  254   	             return new LocalManagedConnection(this, con, props, transactionIsolation, preparedStatementCacheSize);
  255   	         }
  256   	      }
  257   	      catch(Exception e)
  258   	      {
  259                if (con != null)
  260   	         {
  261   	            try
  262   	            {
  263   	               con.close();
  264   	            }
  265   	            catch (Throwable ignored)
  266   	            {
  267   	            }
  268   	          }
  269   	    	  log.warn("Failed to create connection for " + url + ": " + e.getMessage());
  270   			  urlSelector.failedUrlObject(url);
  271   	      }
  272         }
  273   
  274         // we have supposedly tried all the urls
  275   	  throw new JBossResourceException(
  276   	         "Could not create connection using any of the URLs: " + urlSelector.getAllUrlObjects());
  277      }
  278      
  279      public void setURLDelimiter(String urlDelimiter) 
  280      		//throws ResourceException
  281      {
  282         super.urlDelimiter = urlDelimiter;
  283         if(getConnectionURL() != null)
  284         {
  285            initUrlSelector();
  286         }
  287      }
  288      
  289      protected void initUrlSelector() 
  290   		//throws ResourceException
  291      {
  292         boolean trace = log.isTraceEnabled();
  293         
  294         List urlsList = new ArrayList();
  295         String urlsStr = getConnectionURL();
  296         String url;
  297         int urlStart = 0;
  298         int urlEnd = urlsStr.indexOf(urlDelimiter);
  299         while(urlEnd > 0)
  300         {
  301            url = urlsStr.substring(urlStart, urlEnd);
  302            urlsList.add(url);
  303            urlStart = ++urlEnd;
  304            urlEnd = urlsStr.indexOf(urlDelimiter, urlEnd);
  305            if (trace)
  306             log.trace("added HA connection url: " + url);
  307         }
  308   
  309         if(urlStart != urlsStr.length())
  310         {
  311            url = urlsStr.substring(urlStart, urlsStr.length());
  312            urlsList.add(url);
  313            if (trace)
  314               log.trace("added HA connection url: " + url);
  315         }
  316   	  if(getUrlSelectorStrategyClassName()==null)
  317   	  {
  318   		this.urlSelector = new URLSelector(urlsList);
  319   		log.debug("Default URLSelectorStrategy is being used : "+urlSelector);
  320   	  }
  321   	  else
  322   	  {
  323   		this.urlSelector = (URLSelectorStrategy)loadClass(getUrlSelectorStrategyClassName(),urlsList);
  324   		log.debug("Customized URLSelectorStrategy is being used : "+urlSelector);
  325   	  }
  326      }
  327      
  328      // Default Implementaion of the URLSelectorStrategy
  329      public static class URLSelector implements URLSelectorStrategy
  330      {
  331         private final List urls;
  332         private int urlIndex;
  333         private String url;
  334   
  335         public URLSelector(List urls)
  336         {
  337            if(urls == null || urls.size() == 0)
  338            {
  339               throw new IllegalStateException("Expected non-empty list of connection URLs but got: " + urls);
  340            }
  341            this.urls = Collections.unmodifiableList(urls);
  342         }
  343   
  344         public synchronized String getUrl()
  345         {
  346            if(url == null)
  347            {
  348               if(urlIndex == urls.size())
  349               {
  350                  urlIndex = 0;
  351               }
  352               url = (String)urls.get(urlIndex++);
  353            }
  354            return url;
  355         }
  356   
  357         public synchronized void failedUrl(String url)
  358         {
  359            if(url.equals(this.url))
  360            {
  361               this.url = null;
  362            }
  363         }
  364   
  365   	  /* URLSelectorStrategy Implementation goes here*/
  366   	  public List getCustomSortedUrls()
  367   	  {
  368   		 return urls;
  369   	  }
  370   	  public void failedUrlObject(Object urlObject)
  371   	  {
  372   		 failedUrl((String)urlObject);
  373   	  }
  374   	  public List getAllUrlObjects()
  375   	  {
  376   		 return urls;
  377         }
  378   	  public Object getUrlObject()
  379   	  {
  380   		 return getUrl();
  381   	  }
  382   
  383      }
  384   
  385      public ManagedConnection matchManagedConnections(final Set mcs, final Subject subject,
  386            final ConnectionRequestInfo cri) throws ResourceException
  387      {
  388         Properties newProps = getConnectionProperties(subject, cri);
  389   
  390         for (Iterator i = mcs.iterator(); i.hasNext();)
  391         {
  392            Object o = i.next();
  393   
  394            if (o instanceof LocalManagedConnection)
  395            {
  396               LocalManagedConnection mc = (LocalManagedConnection) o;
  397   
  398               //First check the properties
  399               if (mc.getProperties().equals(newProps))
  400               {
  401                  //Next check to see if we are validating on matchManagedConnections
  402                  if ((getValidateOnMatch() && mc.checkValid()) || !getValidateOnMatch())
  403                  {
  404   
  405                     return mc;
  406   
  407                  }
  408   
  409               }
  410            }
  411         }
  412   
  413         return null;
  414      }
  415   
  416      public int hashCode()
  417      {
  418         int result = 17;
  419         result = result * 37 + ((connectionURL == null) ? 0 : connectionURL.hashCode());
  420         result = result * 37 + ((driverClass == null) ? 0 : driverClass.hashCode());
  421         result = result * 37 + ((userName == null) ? 0 : userName.hashCode());
  422         result = result * 37 + ((password == null) ? 0 : password.hashCode());
  423         result = result * 37 + transactionIsolation;
  424         return result;
  425      }
  426   
  427      public boolean equals(Object other)
  428      {
  429         if (this == other)
  430            return true;
  431         if (getClass() != other.getClass())
  432            return false;
  433         LocalManagedConnectionFactory otherMcf = (LocalManagedConnectionFactory) other;
  434         return this.connectionURL.equals(otherMcf.connectionURL) && this.driverClass.equals(otherMcf.driverClass)
  435               && ((this.userName == null) ? otherMcf.userName == null : this.userName.equals(otherMcf.userName))
  436               && ((this.password == null) ? otherMcf.password == null : this.password.equals(otherMcf.password))
  437               && this.transactionIsolation == otherMcf.transactionIsolation;
  438   
  439      }
  440   
  441      /**
  442       * Check the driver for the given URL.  If it is not registered already
  443       * then register it.
  444       *
  445       * @param url   The JDBC URL which we need a driver for.
  446       */
  447      protected synchronized Driver getDriver(final String url) throws ResourceException
  448      {
  449         boolean trace = log.isTraceEnabled();
  450         
  451         // don't bother if it is loaded already
  452         if (driver != null)
  453         {
  454            return driver;
  455         }
  456         if (trace)
  457            log.trace("Checking driver for URL: " + url);
  458   
  459         if (driverClass == null)
  460         {
  461            throw new JBossResourceException("No Driver class specified (url = " + url + ")!");
  462         }
  463   
  464         // Check if the driver is already loaded, if not then try to load it
  465   
  466         if (isDriverLoadedForURL(url))
  467         {
  468            return driver;
  469         } // end of if ()
  470   
  471         try
  472         {
  473            //try to load the class... this should register with DriverManager.
  474            Class clazz = Class.forName(driverClass, true, Thread.currentThread().getContextClassLoader());
  475            if (isDriverLoadedForURL(url))
  476               //return immediately, some drivers (Cloudscape) do not let you create an instance.
  477               return driver;
  478   
  479            //We loaded the class, but either it didn't register
  480            //and is not spec compliant, or is the wrong class.
  481            driver = (Driver) clazz.newInstance();
  482            DriverManager.registerDriver(driver);
  483            if (isDriverLoadedForURL(url))
  484               return driver;
  485            //We can even instantiate one, it must be the wrong class for the URL.
  486         }
  487         catch (Exception e)
  488         {
  489            throw new JBossResourceException("Failed to register driver for: " + driverClass, e);
  490         }
  491   
  492         throw new JBossResourceException("Apparently wrong driver class specified for URL: class: " + driverClass
  493               + ", url: " + url);
  494      }
  495   
  496      private boolean isDriverLoadedForURL(String url)
  497      {
  498         boolean trace = log.isTraceEnabled();
  499         
  500         try
  501         {
  502            driver = DriverManager.getDriver(url);
  503            if (trace)
  504               log.trace("Driver already registered for url: " + url);
  505            return true;
  506         }
  507         catch (Exception e)
  508         {
  509            if (trace)
  510               log.trace("Driver not yet registered for url: " + url);
  511            return false;
  512         }
  513      }
  514   
  515      protected String internalGetConnectionURL()
  516      {
  517         return connectionURL;
  518      }
  519   }

Save This Page
Home » jboss-5.0.0.CR1-src » org.jboss.resource.adapter » jdbc » local » [javadoc | source]