Package com.atomikos.jdbc

Source Code of com.atomikos.jdbc.SimpleDataSourceBean

/**
* Copyright (C) 2000-2010 Atomikos <info@atomikos.com>
*
* This code ("Atomikos TransactionsEssentials"), by itself,
* is being distributed under the
* Apache License, Version 2.0 ("License"), a copy of which may be found at
* http://www.atomikos.com/licenses/apache-license-2.0.txt .
* You may not use this file except in compliance with the License.
*
* While the License grants certain patent license rights,
* those patent license rights only extend to the use of
* Atomikos TransactionsEssentials by itself.
*
* This code (Atomikos TransactionsEssentials) contains certain interfaces
* in package (namespace) com.atomikos.icatch
* (including com.atomikos.icatch.Participant) which, if implemented, may
* infringe one or more patents held by Atomikos.
* It should be appreciated that you may NOT implement such interfaces;
* licensing to implement these interfaces must be obtained separately from Atomikos.
*
* 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.
*/

package com.atomikos.jdbc;

import java.io.PrintWriter;
import java.io.Serializable;
import java.lang.reflect.UndeclaredThrowableException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Enumeration;
import java.util.Properties;
import java.util.StringTokenizer;

import javax.naming.NamingException;
import javax.naming.Reference;
import javax.naming.Referenceable;
import javax.sql.ConnectionPoolDataSource;
import javax.sql.PooledConnection;
import javax.sql.XAConnection;
import javax.sql.XADataSource;

import com.atomikos.beans.BeanInspector;
import com.atomikos.beans.Property;
import com.atomikos.beans.PropertyException;
import com.atomikos.datasource.TransactionalResource;
import com.atomikos.datasource.xa.DefaultXidFactory;
import com.atomikos.datasource.xa.XidFactory;
import com.atomikos.icatch.HeuristicMessage;
import com.atomikos.icatch.system.Configuration;
import com.atomikos.logging.Logger;
import com.atomikos.logging.LoggerFactory;
import com.atomikos.util.ClassLoadingHelper;
import com.atomikos.util.SerializableObjectFactory;

/**
*
*
* An Atomikos DataSource implementation.
*
* @deprecated As of release 3.3, the {@link AtomikosDataSourceBean} should be used instead.
*
*/

public class SimpleDataSourceBean implements HeuristicDataSource,
        ConnectionPoolDataSource, Serializable, Referenceable
{
  private static final Logger LOGGER = LoggerFactory.createLogger(SimpleDataSourceBean.class);

  private static final long serialVersionUID = 6413560960979946477L;

  private transient JtaDataSourceImp ds_;
    // the data source to delegate to

    private transient XADataSource xads_;
    // the hook to the JDBC database, needed to
    // reconstruct the transient datasource
    // NOTE: this is transient to make sure that
    // serialization works even in the presence
    // of non-compliant XADataSource classes

    private String resourceName_;
    // the unique name for the resource associated with us

    private String xidFactory_;
    // the name of the XID factory, needed to reconstruct ds_

    private int poolSize_;
    // the pool size for the ds_

    private int connectionTimeout_;
    // needed for the pool

    private boolean exclusive_;
    // true if not reusable before 2PC

    private String validatingQuery_;
    // an optional query for validating all settings

    private String xaProperties_;
    // the specific properties for XADataSource,
    // as a semi-colon-separated list

    private String xaDataSourceClassName_;
    // the name of the XADataSource class to use
   
    private boolean testOnBorrow_;
    //should connections be tested upon get or not?

    public SimpleDataSourceBean ()
    {
        ds_ = null;
        xads_ = null;
        resourceName_ = "someUniqueName";
        xidFactory_ = "Default";
        poolSize_ = 1;
        connectionTimeout_ = 30;
        exclusive_ = true;
        validatingQuery_ = "";
        xaProperties_ = "";
        xaDataSourceClassName_ = "";
        testOnBorrow_ = false;
    }

    private Properties parseProperties ()
    {
        Properties ret = new Properties ();
        StringTokenizer t = new StringTokenizer ( xaProperties_, ";" );
        if ( xaProperties_.indexOf ( "," ) >= 0 ) {
            //case 20167: generate warning
            LOGGER.logWarning ( "xaDataSourceProperties: found comma(s) - please make sure to use ';' to separate properties: " + xaProperties_ );
        }
        else if ( t.countTokens() <= 1 ) {
            //case 20167: generate warning
            LOGGER.logWarning ( "xaDataSourceProperties: only one property found - please check format: " + xaProperties_ );
        }
        while ( t.hasMoreTokens () ) {
            String next = t.nextToken ();
            int index = next.indexOf ( "=" );
            if ( index < 0 )
                throw new RuntimeException ( "Invalid xaDataSourceProperties format" );
            String name = next.substring ( 0, index );
            String val = next.substring ( index + 1 );
            ret.setProperty ( name, val );
        }
        return ret;
    }

    private synchronized void checkSetup ( boolean validation )
            throws SQLException
    {
        // try if there has been a previous bean setup; return the DS if so
        ds_ = JtaDataSourceImp.getInstance ( getUniqueResourceName () );
        // return if found, but ONLY if validation is NOT true
        // since validation requires asserting XA settings and creation
        if ( ds_ != null && !validation )
            return;

        if ( xads_ == null && ( getXaDataSourceClassName () == null || getXaDataSourceClassName ().length() == 0 ) )
            throw new SQLException (
                    "SimpleDataSourceBean: xaDataSourceClassName not set." );
        if ( xidFactory_ == null )
            throw new SQLException ( "SimpleDataSourceBean: xidFormat not set." );

        if ( xads_ == null ) {
            //check added for case 20112
          try {
            Class xadsClass = ClassLoadingHelper.loadClass ( getXaDataSourceClassName() );
              xads_ = (XADataSource) xadsClass.newInstance ();
              BeanInspector inspector = new BeanInspector ( xads_ );
              Properties p = parseProperties ();
              Enumeration names = p.propertyNames ();
              while ( names.hasMoreElements () ) {
                  String name = (String) names.nextElement ();
                  String val = p.getProperty ( name );
                  inspector.setPropertyValue ( name, val );
              }
 
          } catch ( Exception e ) {
              LOGGER.logWarning (
                      "SimpleDataSourceBean: could not configure XADataSource of class "
                              + getXaDataSourceClassName (), e );
              throw new SQLException ( "Could not configure XADataSource: "
                      + e.getMessage () + " " + e.getClass ().getName () );
          }
        }
        XidFactory xidFactory = null;

        xidFactory = new DefaultXidFactory ();

        XAConnectionFactory factory = new XAConnectionFactory ( resourceName_,
                "", "", xads_, xidFactory );
        factory.setExclusive ( exclusive_ );

        ds_ = new JtaDataSourceImp ( factory, poolSize_, connectionTimeout_,
                validation, !validation, validatingQuery_ , testOnBorrow_ );

        // MOVED TO JTADATASOURCEIMP
        // if ( ! validation )
        // Configuration.addResource ( ds_.getTransactionalResource() );

        // the application does not know the Jta datasource and hence can not
        // shut it down. therefore, add a shutdown hook to do this job
        DataSourceShutdownHook hook = new DataSourceShutdownHook ( ds_ );
        Configuration.addShutdownHook ( hook );
       
       
        StringBuffer sb = new StringBuffer();
        sb.append("SimpleDataSourceBean configured with [");
        sb.append("resourceName=").append(resourceName_).append(", ");
        sb.append("xidFactory=").append(xidFactory_).append(", ");
        sb.append("poolSize=").append(poolSize_).append(", ");
        sb.append("connectionTimeout=").append(connectionTimeout_).append(", ");
        sb.append("exclusive=").append(exclusive_).append(", ");
        sb.append("validatingQuery=").append(validatingQuery_).append(", ");
        sb.append("xaProperties=").append(xaProperties_).append(", ");
        sb.append("xaDataSourceClassName=").append(xaDataSourceClassName_).append(", ");
        sb.append("testOnBorrow=").append(testOnBorrow_);
        sb.append("]");
       
        if ( LOGGER.isDebugEnabled() ) LOGGER.logDebug(sb.toString());
       
        LOGGER.logWarning ( "WARNING: class " + getClass().getName() + " is deprecated!" );
       
    }

    private synchronized void checkSetup () throws SQLException
    {
        checkSetup ( false );
    }
   
    /**
     * Init method to setup the bean for recovery
     * and other init stuff.
     * @throws SQLException
     *
     */
    public void init() throws SQLException
    {
        checkSetup ( false );
    }


    /**
     * Set the identifying name for this data source (required). Used by the
     * transaction logging mechanism. NOTE: the value should not exceed
     * 45 bytes in length.
     *
     * @param resourceName
     */
    public void setUniqueResourceName ( String resourceName )
    {
        resourceName_ = resourceName;
    }

    /**
     * Get the unique resource name for this instance.
     *
     * @return String The name.
     */

    public String getUniqueResourceName ()
    {
        return resourceName_;
    }

    /**
     * Set the size of the internal connection pool (optional). Note: this class
     * also implements ConnectionPoolDataSource, meaning that it can be used for
     * third-party connection pools. In that case, the internal connection pool
     * size can still be configured to have pooling at two levels.
     *
     * @param poolSize
     *            The size of the pool.
     */

    public void setConnectionPoolSize ( int poolSize )
    {
        poolSize_ = poolSize;
    }

    /**
     * Get the size of the connection pool.
     *
     * @return int The size.
     */
   
    public int getConnectionPoolSize ()
    {
        return poolSize_;
    }
   
    /**
     * Set whether connections should be tested when gotten (optional). Default is false.
     *
     * @param value True if connections should be tested when gotten.
     */
   
    public void setTestOnBorrow ( boolean value )
    {
        testOnBorrow_ = value;
    }

    /**
     * Get whether connections should be tested when gotten.
     * @return
     */
   
    public boolean getTestOnBorrow()
    {
        return testOnBorrow_;
    }
   
    /**
     * Set the timeout after which connections should be checked for liveness
     * (optional).
     *
     * @param timeout
     *            The timeout in seconds.
     */

    public void setConnectionTimeout ( int timeout )
    {
        connectionTimeout_ = timeout;
    }

    /**
     * Get the timeout after which connections are checked for liveness.
     *
     * @return int The timeout.
     */
    public int getConnectionTimeout ()
    {
        return connectionTimeout_;
    }

    /**
     * Set the sharing preferences (optional).
     *
     * @param mode
     *            The mode. If true, then connections are not shared when they
     *            are in a transaction. This is the safest setting and allows to
     *            avoid problems with databases that don't implement XA
     *            correctly (such as Oracle). Setting this to true will slightly
     *            affect performance of connection pooling in a negative way.
     *            Default is true.
     */

    public void setExclusiveConnectionMode ( boolean mode )
    {
        exclusive_ = mode;
    }

    /**
     * Get the sharing preference.
     *
     * @return boolean true if exclusive, false if not.
     */

    public boolean getExclusiveConnectionMode ()
    {
        return exclusive_;
    }

    /**
     * Get the transactional resource.
     *
     * @return TransactionalResource The resource as it is used by the
     *         transaction service during recovery.
     */

    protected TransactionalResource getTransactionalResource ()
    {
        try {
            checkSetup ();
        } catch ( SQLException err ) {
            err.printStackTrace ();
            throw new RuntimeException ( err.getMessage () );
        }
        return ds_.getTransactionalResource ();
    }

    /**
     * Set the validating query for this datasource (optional). This optional
     * property allows you to give a test query to see if the configuration
     * works.
     *
     * @param query
     *            The SQL query that should work if the connectivity is made.
     */

    public void setValidatingQuery ( String query )
    {
        validatingQuery_ = query;
    }

    /**
     * Get the validating query.
     *
     * @return String The query.
     */
    public String getValidatingQuery ()
    {
        return validatingQuery_;
    }

    /**
     * Set the fully qualified name of the XADataSource class to use (required).
     *
     * @param name
     *            The vendor-specific XADataSource class to use. Ignored if the XADataSource instance is set directly.
     */

    public void setXaDataSourceClassName ( String name )
    {
        xaDataSourceClassName_ = name;
    }

    // /**
    // * Check if the setup is valid.
    // *
    // * @return boolean False if the connectivity fails,
    // * true if the validating query could be executed,
    // * or if no validating query was specified.
    // */
    //   
    // public boolean isValidatingQueryOK()
    // {
    // boolean ret = false;
    // try
    // {
    // validate();
    // ret = true;
    // }
    // catch (SQLException e)
    // {
    //           
    // }
    // return ret ;
    // }
    //   
    /**
     * Get the full name of the vendor-specific XADataSource class.
     *
     * @return String The fully qualified name.
     */

    public String getXaDataSourceClassName ()
    {
        String ret = xaDataSourceClassName_;
        if ( ret == null && xads_ != null ) {
          //if xads is set directly -> use the actual classname
          //since xaDataSourceClassName_ may be null!
          ret = xads_.getClass().getName();
        }
         return ret;
    }

    /**
     * Set the XADataSource-specific properties as a semicolon-separated list of
     * string values (required unless the XADataSource instance is set directly).
     *
     * @param properties
     *            The properties expressed as a semi-colon separated list. For
     *            example: port=8000;user=demo;password=sa
     * Ignored if the XADataSource instance is set directly.
     */

    public void setXaDataSourceProperties ( String properties )
    {
        xaProperties_ = properties;
    }

    /**
     * Get the XADataSource properties as one large string.
     *
     * @return String The poperty list as set previously by setXaDataSourceProperties.
     */

    public String getXaDataSourceProperties ()
    {
          StringBuffer ret = new StringBuffer();
          if ( xaProperties_ != null ) ret.append ( xaProperties_ );
          if ( ret.length() == 0 && xads_ != null ) {      
                try {
                BeanInspector inspector = new BeanInspector ( xads_ );
                Property[] props = inspector.getProperties();
                for ( int i = 0 ; i < props.length ; i++ ) {
                  String name = props[i].getName();
                  String value = inspector.getPropertyValue ( name );
                  ret.append ( name ); ret.append( "=" ); ret.append ( value );
                  if ( i < props.length - 1 ) ret.append ( ";" );
                }
                }
                catch ( PropertyException e ) {
                    LOGGER.logWarning ( "Error in getXaDataSourceProperties" , e );
                    throw new UndeclaredThrowableException ( e );
                }
          }
        return ret.toString();
    }
   
    /**
     * Sets the (preconfigured) XADataSource instance.
     *
     * @param xads The instance.
     */
    public void setXaDataSource ( XADataSource xads )
    {
        this.xads_ = xads;
    }
   
    /**
     * Gets the configured XADataSource instance (if set).
     * @return The XADataSource - or null if not set.
     */
    public XADataSource getXaDataSource()
    {
        return xads_;
    }

    /**
     * Perform validation based on the validating query. This method does
     * nothing if no query was specified.
     *
     * @throws SQLException
     *             If validation fails.
     */
    public void validate () throws SQLException
    {
        checkSetup ( true );
        String query = getValidatingQuery ();
        if ( query == null || query.equals ( "" ) )
            return;

        Connection c = null;
        Statement s = null;
        try {
            // don't use our own getConnection since it will
            // call checkSetup without validation flag!
            c = ds_.getConnection ();

            try {
                s = c.createStatement ();
                ResultSet rs = s.executeQuery ( query );
                s.close ();
            } finally {
                if ( s != null )
                    s.close ();
                // this will also close the resultsets if any
            }
        } catch ( SQLException e ) {
            LOGGER.logWarning (
                    "Error in validating query for resource "
                            + getUniqueResourceName (), e );
        } finally {
            if ( c != null )
                c.close ();
        }
    }

    //
    //
    // IMPLEMENTATION OF HEURISTICDATASOURCE
    //
    //

    /**
     * @see com.atomikos.jdbc.HeuristicDataSource
     */
    public Connection getConnection () throws SQLException
    {
        checkSetup ();
        return ds_.getConnection ();
    }

    /**
     * @see com.atomikos.jdbc.HeuristicDataSource
     */

    public Connection getConnection ( String user , String pw )
            throws SQLException
    {
        checkSetup ();
        return ds_.getConnection ( user, pw );
    }

    /**
     * @see com.atomikos.jdbc.HeuristicDataSource
     */

    public Connection getConnection ( HeuristicMessage msg )
            throws SQLException
    {
        checkSetup ();
        return ds_.getConnection ( msg );
    }

    /**
     * @see com.atomikos.jdbc.HeuristicDataSource
     */

    public Connection getConnection ( String user , String pw ,
            HeuristicMessage msg ) throws SQLException
    {
        checkSetup ();
        return ds_.getConnection ( user, pw, msg );
    }

    /**
     * @see com.atomikos.jdbc.HeuristicDataSource
     */

    public Connection getConnection ( String msg ) throws SQLException
    {
        checkSetup ();
        return ds_.getConnection ( msg );
    }

    /**
     * @see com.atomikos.jdbc.HeuristicDataSource
     */

    public Connection getConnection ( String user , String passwd , String msg )
            throws SQLException
    {
        checkSetup ();
        return ds_.getConnection ( user, passwd, msg );
    }

    /**
     * @see com.atomikos.jdbc.HeuristicDataSource
     */

    public int getLoginTimeout () throws SQLException
    {
        checkSetup ();
        return ds_.getLoginTimeout ();
    }

    /**
     * @see com.atomikos.jdbc.HeuristicDataSource
     */

    public PrintWriter getLogWriter () throws SQLException
    {
        checkSetup ();
        return ds_.getLogWriter ();
    }

    /**
     * @see com.atomikos.jdbc.HeuristicDataSource
     */

    public void setLoginTimeout ( int seconds ) throws SQLException
    {
        checkSetup ();
        ds_.setLoginTimeout ( seconds );
    }

    /**
     * @see com.atomikos.jdbc.HeuristicDataSource
     */

    public void setLogWriter ( PrintWriter out ) throws SQLException
    {
        checkSetup ();
        ds_.setLogWriter ( out );
    }

    /**
     * @see com.atomikos.jdbc.HeuristicDataSource
     */

    public void close () throws SQLException
    {
          //DON'T setup: see issue 10098
        //checkSetup ();
     
        if ( ds_ != null  ) {
          //issue 10098: don't call setup -> added null check
          ds_.close ();
        }
    }

    //
    //
    // IMPLEMENTATION OF REFERENCEABLE
    //
    //

    /**
     * @see javax.naming.Referenceable
     */
    public Reference getReference () throws NamingException
    {
        return SerializableObjectFactory.createReference ( this );
    }

    /**
     * @see javax.sql.ConnectionPoolDataSource#getPooledConnection()
     */

    public PooledConnection getPooledConnection () throws SQLException
    {
        checkSetup ();
        PooledConnection ret = null;
        XAConnection xaconn = xads_.getXAConnection ();
        ret = new ExternalXAPooledConnectionImp ( xaconn,
                getTransactionalResource (), getLogWriter () );
        return ret;
    }

    /**
     * @see javax.sql.ConnectionPoolDataSource#getPooledConnection(java.lang.String,
     *      java.lang.String)
     */

    public PooledConnection getPooledConnection ( String user , String pw )
            throws SQLException
    {
        PooledConnection ret = null;
        checkSetup ();
        XAConnection xaconn = xads_.getXAConnection ( user, pw );
        ret = new ExternalXAPooledConnectionImp ( xaconn,
                getTransactionalResource (), getLogWriter () );
        return ret;
    }

}
TOP

Related Classes of com.atomikos.jdbc.SimpleDataSourceBean

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.