com.sun.gjc.spi.ManagedConnectionFactoryImpl Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of payara-embedded-all Show documentation
Show all versions of payara-embedded-all Show documentation
Payara-Embedded-All Distribution of the Payara Project
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 1997-2016 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can
* obtain a copy of the License at
* https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
// Portions Copyright [2017] [Payara Foundation and/or its affiliates]
package com.sun.gjc.spi;
import com.sun.appserv.connectors.internal.spi.MCFLifecycleListener;
import com.sun.enterprise.util.i18n.StringManager;
import com.sun.gjc.common.DataSourceObjectBuilder;
import com.sun.gjc.common.DataSourceSpec;
import com.sun.gjc.monitoring.JdbcStatsProvider;
import com.sun.gjc.util.SQLTraceDelegator;
import com.sun.gjc.util.SQLTraceLogger;
import com.sun.gjc.util.SecurityUtils;
import com.sun.logging.LogDomains;
import fish.payara.jdbc.SlowSQLLogger;
import org.glassfish.api.jdbc.ConnectionValidation;
import org.glassfish.api.jdbc.SQLTraceListener;
import org.glassfish.external.probe.provider.PluginPoint;
import org.glassfish.external.probe.provider.StatsProviderManager;
import org.glassfish.resourcebase.resources.api.PoolInfo;
import javax.resource.ResourceException;
import javax.resource.spi.ConfigProperty;
import javax.resource.spi.ConnectionRequestInfo;
import javax.resource.spi.ResourceAdapterAssociation;
import javax.resource.spi.ResourceAllocationException;
import javax.resource.spi.security.PasswordCredential;
import javax.sql.PooledConnection;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.sql.Connection;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* ManagedConnectionFactory
implementation for Generic JDBC Connector.
* This class is extended by the DataSource specific ManagedConnection
factories
* and the ManagedConnectionFactory
for the DriverManager
.
*
* @author Evani Sai Surya Kiran, Aditya Gore
* @version 1.0, 02/08/03
*/
public abstract class ManagedConnectionFactoryImpl implements javax.resource.spi.ManagedConnectionFactory,
javax.resource.spi.ValidatingManagedConnectionFactory,
MCFLifecycleListener, ResourceAdapterAssociation,
java.io.Serializable, Externalizable {
protected DataSourceSpec spec = new DataSourceSpec();
protected transient DataSourceObjectBuilder dsObjBuilder;
protected java.io.PrintWriter logWriter = null;
protected transient javax.resource.spi.ResourceAdapter ra = null;
private static Logger _logger;
protected boolean statementWrapping;
private JdbcObjectsFactory jdbcObjectsFactory = JdbcObjectsFactory.getInstance();
protected SQLTraceDelegator sqlTraceDelegator;
static {
_logger = LogDomains.getLogger(ManagedConnectionFactoryImpl.class, LogDomains.RSR_LOGGER);
}
protected javax.resource.spi.LazyEnlistableConnectionManager cm_;
protected boolean isLazyCm_;
private int statementCacheSize = 0;
private String statementCacheType = null;
private long statementLeakTimeout = 0;
private boolean statementLeakReclaim = false;
//Jdbc Stats provider that is created
private JdbcStatsProvider jdbcStatsProvider = null;
protected static final StringManager localStrings =
StringManager.getManager(DataSourceObjectBuilder.class);
/**
* Creates a Connection Factory instance. The ConnectionManager
implementation
* of the resource adapter is used here.
*
* @return Generic JDBC Connector implementation of javax.sql.DataSource
*/
@Override
public Object createConnectionFactory() {
logFine("In createConnectionFactory()");
return jdbcObjectsFactory.getDataSourceInstance(this, null);
}
/**
* Creates a Connection Factory instance. The ConnectionManager
implementation
* of the application server is used here.
*
* @param cxManager ConnectionManager
passed by the application server
* @return Generic JDBC Connector implementation of javax.sql.DataSource
*/
@Override
public Object createConnectionFactory(javax.resource.spi.ConnectionManager cxManager) {
logFine("In createConnectionFactory(javax.resource.spi.ConnectionManager cxManager)");
javax.sql.DataSource cf = jdbcObjectsFactory.getDataSourceInstance(this, cxManager);
if (cxManager instanceof javax.resource.spi.LazyEnlistableConnectionManager) {
cm_ = (javax.resource.spi.LazyEnlistableConnectionManager) cxManager;
isLazyCm_ = true;
}
return cf;
}
/**
* Creates a new physical connection to the underlying EIS resource
* manager.
*
* @param subject Subject
instance passed by the application server
* @param cxRequestInfo ConnectionRequestInfo
which may be created
* as a result of the invocation getConnection(user, password)
* on the DataSource
object
* @return ManagedConnection
object created
* @throws ResourceException if there is an error in instantiating the
* DataSource
object used for the
* creation of the ManagedConnection
object
* @throws SecurityException if there ino PasswordCredential
object
* satisfying this request
* @throws ResourceException if there is an error in allocating the
* physical connection
*/
@Override
public abstract javax.resource.spi.ManagedConnection createManagedConnection
(javax.security.auth.Subject subject, ConnectionRequestInfo cxRequestInfo) throws ResourceException;
/**
* Check if this ManagedConnectionFactoryImpl
is equal to
* another ManagedConnectionFactoryImpl
.
*
* @param other ManagedConnectionFactoryImpl
object for checking equality with
* @return true if the property sets of both the
* ManagedConnectionFactoryImpl
objects are the same
* false otherwise
*/
@Override
public abstract boolean equals(Object other);
/**
* Get the log writer for this ManagedConnectionFactoryImpl
instance.
*
* @return PrintWriter
associated with this ManagedConnectionFactoryImpl
instance
* @see setLogWriter
*/
@Override
public java.io.PrintWriter getLogWriter() {
return logWriter;
}
/**
* Get the ResourceAdapterImpl
for this ManagedConnectionFactoryImpl
instance.
*
* @return ResourceAdapterImpl
associated with this ManagedConnectionFactoryImpl
instance
* @see setResourceAdapter
*/
@Override
public javax.resource.spi.ResourceAdapter getResourceAdapter() {
logFine("In getResourceAdapter");
return ra;
}
/**
* Returns the hash code for this ManagedConnectionFactoryImpl
.
*
* @return hash code for this ManagedConnectionFactoryImpl
*/
@Override
public int hashCode() {
logFine("In hashCode");
return spec.hashCode();
}
/**
* Returns a matched ManagedConnection
from the candidate
* set of ManagedConnection
objects.
*
* @param connectionSet Set
of ManagedConnection
* objects passed by the application server
* @param subject passed by the application server
* for retrieving information required for matching
* @param cxRequestInfo ConnectionRequestInfo
passed by the application server
* for retrieving information required for matching
* @return ManagedConnection
that is the best match satisfying this request
* @throws ResourceException if there is an error accessing the Subject
* parameter or the Set
of ManagedConnection
* objects passed by the application server
*/
@Override
public javax.resource.spi.ManagedConnection matchManagedConnections(
java.util.Set connectionSet, javax.security.auth.Subject subject, ConnectionRequestInfo cxRequestInfo)
throws ResourceException {
logFine("In matchManagedConnections");
if (connectionSet == null) {
return null;
}
PasswordCredential pc = SecurityUtils.getPasswordCredential(this, subject, cxRequestInfo);
java.util.Iterator iter = connectionSet.iterator();
ManagedConnectionImpl mc = null;
while (iter.hasNext()) {
try {
mc = (ManagedConnectionImpl) iter.next();
} catch (java.util.NoSuchElementException nsee) {
_logger.log(Level.SEVERE, "jdbc.exc_iter");
throw new ResourceException(nsee.getMessage());
}
if (pc == null && this.equals(mc.getManagedConnectionFactory())) {
return mc;
} else if (SecurityUtils.isPasswordCredentialEqual(pc, mc.getPasswordCredential())) {
return mc;
}
}
return null;
}
/**
* This method returns a set of invalid ManagedConnection
* objects chosen from a specified set of ManagedConnection
* objects.
*
* @param connectionSet a set of ManagedConnection
objects
* that need to be validated.
* @return a set of invalid ManagedConnection
objects.
* @throws ResourceException generic exception.
*/
@Override
public Set getInvalidConnections(Set connectionSet) throws ResourceException {
Iterator iter = connectionSet.iterator();
Set invalidConnections = new HashSet();
while (iter.hasNext()) {
ManagedConnectionImpl mc = (ManagedConnectionImpl) iter.next();
try {
isValid(mc);
} catch (ResourceException re) {
invalidConnections.add(mc);
mc.connectionErrorOccurred(re, null);
if (_logger.isLoggable(Level.FINE)) {
_logger.log(Level.FINE, "jdbc.invalid_connection", re);
}
}
}
return invalidConnections;
}
//GJCINT
/**
* Checks if a ManagedConnection
is to be validated or not
* and validates it or returns.
*
* @param mc ManagedConnection
to be validated
* @throws ResourceException if the connection is not valid or
* if validation method is not proper
*/
void isValid(ManagedConnectionImpl mc) throws ResourceException {
if (mc == null || mc.isTransactionInProgress()) {
return;
}
String conVal = spec.getDetail(DataSourceSpec.CONNECTIONVALIDATIONREQUIRED);
boolean connectionValidationRequired =
(conVal == null) ? false : Boolean.valueOf(conVal.toLowerCase(Locale.getDefault()));
if (!connectionValidationRequired) {
return;
}
String validationMethod = spec.getDetail(DataSourceSpec.VALIDATIONMETHOD).toLowerCase(Locale.getDefault());
mc.checkIfValid();
/**
* The above call checks if the actual physical connection
* is usable or not.
*/
java.sql.Connection con = mc.getActualConnection();
if(validationMethod.equals("custom-validation")) {
isValidByCustomValidation(con, spec.getDetail(DataSourceSpec.VALIDATIONCLASSNAME));
} else if (validationMethod.equals("auto-commit")) {
isValidByAutoCommit(con);
} else if (validationMethod.equals("meta-data")) {
isValidByMetaData(con);
} else if (validationMethod.equals("table")) {
isValidByTableQuery(con, spec.getDetail(DataSourceSpec.VALIDATIONTABLENAME));
} else {
throw new ResourceException("The validation method is not proper");
}
}
/**
* Checks if a java.sql.Connection
is valid or not
* by doing a custom validation using the validation class name specified.
*
* @param con java.sql.Connection
to be validated
* @throws ResourceException if the connection is not valid
*/
protected void isValidByCustomValidation(java.sql.Connection con,
String validationClassName) throws ResourceException {
boolean isValid = false;
if (con == null) {
throw new ResourceException("The connection is not valid as "
+ "the connection is null");
}
// The timeout defaults to -1, which isn't actually a valid setting for the timeout
int statementTimeout = Integer.valueOf(getStatementTimeout());
if (statementTimeout == -1) {
statementTimeout = 0;
}
try {
Class validationClass = Thread.currentThread().getContextClassLoader().loadClass(validationClassName);
ConnectionValidation valClass = (ConnectionValidation) validationClass.newInstance();
isValid = valClass.isConnectionValid(con, statementTimeout);
} catch (Exception e) {
_logger.log(Level.INFO, "jdbc.exc_custom_validation", validationClassName);
throw new ResourceException(e);
}
if (!isValid) {
_logger.log(Level.INFO, "jdbc.exc_custom_validation", validationClassName);
throw new ResourceException("Custom validation detected invalid connection");
}
}
/**
* Checks if a java.sql.Connection
is valid or not
* by checking its auto commit property.
*
* @param con java.sql.Connection
to be validated
* @throws ResourceException if the connection is not valid
*/
protected void isValidByAutoCommit(java.sql.Connection con) throws ResourceException {
if (con == null) {
throw new ResourceException("The connection is not valid as "
+ "the connection is null");
}
try {
// Notice that using something like
// dbCon.setAutoCommit(dbCon.getAutoCommit()) will cause problems with
// some drivers like sybase
// We do not validate connections that are already enlisted
//in a transaction
// We cycle autocommit to true and false to by-pass drivers that
// might cache the call to set autocomitt
// Also notice that some XA data sources will throw and exception if
// you try to call setAutoCommit, for them this method is not recommended
boolean ac = con.getAutoCommit();
if (ac) {
con.setAutoCommit(false);
} else {
con.rollback(); // prevents uncompleted transaction exceptions
con.setAutoCommit(true);
}
con.setAutoCommit(ac);
} catch (Exception sqle) {
_logger.log(Level.INFO, "jdbc.exc_autocommit_validation");
throw new ResourceException(sqle);
}
}
/**
* Checks if a java.sql.Connection
is valid or not
* by checking its meta data.
*
* @param con java.sql.Connection
to be validated
* @throws ResourceException if the connection is not valid
*/
protected void isValidByMetaData(java.sql.Connection con) throws ResourceException {
if (con == null) {
throw new ResourceException("The connection is not valid as "
+ "the connection is null");
}
try {
con.getMetaData();
} catch (Exception sqle) {
_logger.log(Level.INFO, "jdbc.exc_metadata_validation");
throw new ResourceException(sqle);
}
}
/**
* Checks if a java.sql.Connection
is valid or not
* by querying a table.
*
* @param con java.sql.Connection
to be validated
* @param tableName table which should be queried
* @throws ResourceException if the connection is not valid
*/
protected void isValidByTableQuery(java.sql.Connection con,
String tableName) throws ResourceException {
if (con == null) {
throw new ResourceException("The connection is not valid as "
+ "the connection is null");
}
java.sql.PreparedStatement stmt = null;
java.sql.ResultSet rs = null;
final String statement = "SELECT COUNT(*) FROM " + tableName;
int statementTimeout = Integer.valueOf(getStatementTimeout());
// The timeout defaults to -1, which isn't actually a valid setting for the timeout
if (statementTimeout == -1) {
statementTimeout = 0;
}
try {
stmt = con.prepareStatement(statement);
stmt.setQueryTimeout(statementTimeout);
rs = stmt.executeQuery();
} catch (Exception sqle) {
_logger.log(Level.INFO, "jdbc.exc_table_validation", tableName);
throw new ResourceException(sqle);
} finally {
try {
if (rs != null) {
rs.close();
}
} catch (Exception e1) {
}
try {
if (stmt != null) {
stmt.close();
}
} catch (Exception e2) {
}
}
}
/**
* Sets the isolation level specified in the ConnectionRequestInfo
* for the ManagedConnection
passed.
*
* @param mc ManagedConnection
* @throws ResourceException if the isolation property is invalid
* or if the isolation cannot be set over the connection
*/
protected void setIsolation(ManagedConnectionImpl mc) throws ResourceException {
java.sql.Connection con = mc.getActualConnection();
if (con == null) {
return;
}
String tranIsolation = spec.getDetail(DataSourceSpec.TRANSACTIONISOLATION);
if (tranIsolation != null && !tranIsolation.equals("")) {
int tranIsolationInt = getTransactionIsolationInt(tranIsolation);
try {
con.setTransactionIsolation(tranIsolationInt);
mc.setLastTransactionIsolationLevel(tranIsolationInt);
} catch (java.sql.SQLException sqle) {
_logger.log(Level.SEVERE, "jdbc.exc_tx_iso", sqle);
throw new ResourceException("The transaction isolation could "
+ "not be set: " + sqle.getMessage());
}
}
}
/**
* Resets the isolation level for the ManagedConnection
passed.
* If the transaction level is to be guaranteed to be the same as the one
* present when this ManagedConnection
was created, as specified
* by the ConnectionRequestInfo
passed, it sets the transaction
* isolation level from the ConnectionRequestInfo
passed. Else,
* it sets it to the transaction isolation passed.
*
* @param mc ManagedConnection
* @param tranIsol int
* @throws ResourceException if the isolation property is invalid
* or if the isolation cannot be set over the connection
*/
void resetIsolation(ManagedConnectionImpl mc, int tranIsol) throws ResourceException {
java.sql.Connection con = mc.getActualConnection();
if (con == null) {
return;
}
String tranIsolation = spec.getDetail(DataSourceSpec.TRANSACTIONISOLATION);
if (tranIsolation != null && !tranIsolation.equals("")) {
String guaranteeIsolationLevel = spec.getDetail(DataSourceSpec.GUARANTEEISOLATIONLEVEL);
if (guaranteeIsolationLevel != null && !guaranteeIsolationLevel.equals("")) {
boolean guarantee = Boolean.valueOf(guaranteeIsolationLevel.toLowerCase(Locale.getDefault()));
if (guarantee) {
int tranIsolationInt = getTransactionIsolationInt(tranIsolation);
try {
if (tranIsolationInt != con.getTransactionIsolation()) {
con.setTransactionIsolation(tranIsolationInt);
}
} catch (java.sql.SQLException sqle) {
_logger.log(Level.SEVERE, "jdbc.exc_tx_iso", sqle);
throw new ResourceException("The isolation level could not be set: "
+ sqle.getMessage());
}
} else {
try {
if (tranIsol != con.getTransactionIsolation()) {
con.setTransactionIsolation(tranIsol);
}
} catch (java.sql.SQLException sqle) {
_logger.log(Level.SEVERE, "jdbc.exc_tx_iso", sqle);
throw new ResourceException("The isolation level could not be set: "
+ sqle.getMessage());
}
}
}
}
}
private void detectSqlTraceListeners() {
//Check for sql-trace-listeners attribute.
String sqlTraceListeners = getSqlTraceListeners();
String delimiter = ",";
if(sqlTraceListeners != null && !sqlTraceListeners.equals("null")) {
if (sqlTraceDelegator == null) {
sqlTraceDelegator = new SQLTraceDelegator(getPoolName(), getApplicationName(), getModuleName());
}
StringTokenizer st = new StringTokenizer(sqlTraceListeners, delimiter);
while (st.hasMoreTokens()) {
String sqlTraceListener = st.nextToken().trim();
if(!sqlTraceListener.equals("")) {
Class listenerClass = null;
SQLTraceListener listener = null;
Constructor[] constructors = null;
Class[] parameterTypes = null;
Object[] initargs = null;
//Load the listener class
try {
listenerClass = Thread.currentThread().getContextClassLoader().loadClass(sqlTraceListener);
} catch (ClassNotFoundException ex) {
try {
listenerClass = this.getClass().getClassLoader().loadClass(sqlTraceListener);
}catch (ClassNotFoundException ex2) {
_logger.log(Level.SEVERE, "jdbc.sql_trace_listener_cnfe", sqlTraceListener);
}
}
Class intf[] = listenerClass.getInterfaces();
for (Class interfaceName : intf) {
if (interfaceName.getName().equals("org.glassfish.api.jdbc.SQLTraceListener")) {
try {
constructors = listenerClass.getConstructors();
for (Constructor constructor : constructors) {
parameterTypes = constructor.getParameterTypes();
//For now only the no argument constructors are allowed.
//TODO should this be documented?
if (parameterTypes != null && parameterTypes.length == 0) {
listener = (SQLTraceListener) constructor.newInstance(initargs);
}
}
} catch (InstantiationException ex) {
_logger.log(Level.SEVERE, "jdbc.sql_trace_listener_exception", ex.getMessage());
} catch (IllegalAccessException ex) {
_logger.log(Level.SEVERE, "jdbc.sql_trace_listener_exception", ex.getMessage());
} catch (IllegalArgumentException ex) {
_logger.log(Level.SEVERE, "jdbc.sql_trace_listener_exception", ex.getMessage());
} catch (InvocationTargetException ex) {
_logger.log(Level.SEVERE, "jdbc.sql_trace_listener_exception", ex.getMessage());
} catch (SecurityException ex) {
_logger.log(Level.SEVERE, "jdbc.sql_trace_listener_exception", ex.getMessage());
}
sqlTraceDelegator.registerSQLTraceListener(listener);
}
}
}
}
}
}
/**
* Gets the integer equivalent of the string specifying
* the transaction isolation.
*
* @param tranIsolation string specifying the isolation level
* @return tranIsolationInt the java.sql.Connection
constant
* for the string specifying the isolation.
*/
private int getTransactionIsolationInt(String tranIsolation) throws ResourceException {
if (tranIsolation.equalsIgnoreCase("read-uncommitted")) {
return java.sql.Connection.TRANSACTION_READ_UNCOMMITTED;
} else if (tranIsolation.equalsIgnoreCase("read-committed")) {
return java.sql.Connection.TRANSACTION_READ_COMMITTED;
} else if (tranIsolation.equalsIgnoreCase("repeatable-read")) {
return java.sql.Connection.TRANSACTION_REPEATABLE_READ;
} else if (tranIsolation.equalsIgnoreCase("serializable")) {
return java.sql.Connection.TRANSACTION_SERIALIZABLE;
} else {
throw new ResourceException("Invalid transaction isolation; the transaction "
+ "isolation level can be empty or any of the following: "
+ "read-uncommitted, read-committed, repeatable-read, serializable");
}
}
/**
* Common operation performed by all the child MCFs before returning a created mc
*/
protected void validateAndSetIsolation(ManagedConnectionImpl mc) throws ResourceException {
try {
isValid(mc);
setIsolation(mc);
} catch (ResourceException e) {
if (mc != null) {
try {
mc.destroy();
} catch (ResourceException e1) {
_logger.log(Level.WARNING, "jdbc.exc_destroy", e1);
}
}
String msg = localStrings.getString("jdbc.exc_destroy", e.getMessage());
ResourceAllocationException rae = new ResourceAllocationException(
msg, e);
throw rae;
}
}
private void detectStatementCachingSupport() {
String cacheSize = getStatementCacheSize();
if(cacheSize != null){
try{
statementCacheSize = Integer.parseInt(cacheSize);
//TODO-SC FINE log-level with Pool Name (if possible)
if(_logger.isLoggable(Level.FINE)) {
_logger.log(Level.FINE, "StatementCaching Size : " + statementCacheSize);
}
}catch(NumberFormatException nfe){
if(_logger.isLoggable(Level.FINE)) {
_logger.fine("Exception while setting StatementCacheSize : " +
nfe.getMessage());
}
//ignore
}
}
}
/**
* Set the log writer for this ManagedConnectionFactoryImpl
instance.
*
* @param out PrintWriter
passed by the application server
* @see getLogWriter
*/
@Override
public void setLogWriter(java.io.PrintWriter out) {
logWriter = out;
}
/**
* Set the associated ResourceAdapterImpl
JavaBean.
*
* @param ra ResourceAdapterImpl
associated with this
* ManagedConnectionFactoryImpl
instance
* @see getResourceAdapter
*/
@Override
public void setResourceAdapter(javax.resource.spi.ResourceAdapter ra) {
this.ra = ra;
}
/**
* Sets the user name
*
* @param user String
*/
@ConfigProperty(type = String.class, defaultValue = "APP")
public void setUser(String user) {
spec.setDetail(DataSourceSpec.USERNAME, user);
}
/**
* Gets the user name
*
* @return user
*/
public String getUser() {
return spec.getDetail(DataSourceSpec.USERNAME);
}
/**
* Sets the password
*
* @param passwd String
*/
@ConfigProperty(type = String.class, defaultValue = "APP")
public void setPassword(String passwd) {
spec.setDetail(DataSourceSpec.PASSWORD, passwd);
}
/**
* Gets the password
*
* @return passwd
*/
public String getPassword() {
return spec.getDetail(DataSourceSpec.PASSWORD);
}
/**
* Sets the class name of the data source
*
* @param className String
*/
@ConfigProperty(type = String.class, defaultValue = "org.apache.derby.jdbc.ClientConnectionPoolDataSource")
public void setClassName(String className) {
spec.setDetail(DataSourceSpec.CLASSNAME, className);
}
/**
* Gets the class name of the data source
*
* @return className
*/
public String getClassName() {
return spec.getDetail(DataSourceSpec.CLASSNAME);
}
/**
* Sets if connection validation is required or not
*
* @param conVldReq String
*/
@ConfigProperty(type = String.class, defaultValue = "false")
public void setConnectionValidationRequired(String conVldReq) {
spec.setDetail(DataSourceSpec.CONNECTIONVALIDATIONREQUIRED, conVldReq);
}
/**
* Returns if connection validation is required or not
*
* @return connection validation requirement
*/
public String getConnectionValidationRequired() {
return spec.getDetail(DataSourceSpec.CONNECTIONVALIDATIONREQUIRED);
}
/**
* Sets the validation method required
*
* @param validationMethod String
*/
@ConfigProperty(type = String.class, defaultValue = "")
public void setValidationMethod(String validationMethod) {
spec.setDetail(DataSourceSpec.VALIDATIONMETHOD, validationMethod);
}
/**
* Returns the connection validation method type
*
* @return validation method
*/
public String getValidationMethod() {
return spec.getDetail(DataSourceSpec.VALIDATIONMETHOD);
}
/**
* Sets the table checked for during validation
*
* @param table String
*/
@ConfigProperty(type = String.class, defaultValue = "")
public void setValidationTableName(String table) {
spec.setDetail(DataSourceSpec.VALIDATIONTABLENAME, table);
}
/**
* Returns the table checked for during validation
*
* @return table
*/
public String getValidationTableName() {
return spec.getDetail(DataSourceSpec.VALIDATIONTABLENAME);
}
/**
* Sets the validation class name checked for during validation
*
* @param className String
*/
public void setValidationClassName(String className) {
try {
Class validationClass = Thread.currentThread().getContextClassLoader().loadClass(className);
boolean isAssignable = ConnectionValidation.class.isAssignableFrom(validationClass);
if (isAssignable) {
spec.setDetail(DataSourceSpec.VALIDATIONCLASSNAME, className);
} else {
//Validation Failed
_logger.log(Level.SEVERE, "jdbc.set_custom_validation_class_name_failure", className);
throw new ResourceException("The Custom validation class name is" +
"not valid as it does not implement " +
ConnectionValidation.class.getName());
}
} catch (ResourceException ex) {
_logger.log(Level.SEVERE, "jdbc.set_custom_validation_class_name_failure",
ex.getMessage());
} catch (ClassNotFoundException ex) {
_logger.log(Level.SEVERE, "jdbc.set_custom_validation_class_name_failure",
ex.getMessage());
}
}
/**
* Returns the validation class name checked for during validation
*
* @return table
*/
public String getValidationClassName() {
return spec.getDetail(DataSourceSpec.VALIDATIONCLASSNAME);
}
/**
* Sets the transaction isolation level
*
* @param trnIsolation String
*/
@ConfigProperty(type = String.class, defaultValue = "")
public void setTransactionIsolation(String trnIsolation) {
spec.setDetail(DataSourceSpec.TRANSACTIONISOLATION, trnIsolation);
}
/**
* Returns the transaction isolation level
*
* @return transaction isolation level
*/
public String getTransactionIsolation() {
return spec.getDetail(DataSourceSpec.TRANSACTIONISOLATION);
}
/**
* Sets if the transaction isolation level is to be guaranteed
*
* @param guaranteeIsolation String
*/
@ConfigProperty(type = String.class, defaultValue = "")
public void setGuaranteeIsolationLevel(String guaranteeIsolation) {
spec.setDetail(DataSourceSpec.GUARANTEEISOLATIONLEVEL, guaranteeIsolation);
}
/**
* Returns the transaction isolation level
*
* @return isolation level guarantee
*/
public String getGuaranteeIsolationLevel() {
return spec.getDetail(DataSourceSpec.GUARANTEEISOLATIONLEVEL);
}
protected boolean isEqual(PasswordCredential pc, String user,
String password) {
//if equal get direct connection else
//get connection with user and password.
String thisUser = (pc == null) ? null : pc.getUserName();
char[] passwordArray = (pc == null) ? null : pc.getPassword();
char[] tmpPasswordArray = (password == null) ? null : password.toCharArray();
return (isStringEqual(thisUser, user) &&
Arrays.equals(passwordArray, tmpPasswordArray));
}
private boolean isStringEqual(String str1, String str2) {
return str1 == null ? str2 == null : str1.equals(str2);
}
/**
* Sets the server name.
*
* @param serverName String
* @see getServerName
*/
@ConfigProperty(type = String.class, defaultValue = "localhost")
public void setServerName(String serverName) {
spec.setDetail(DataSourceSpec.SERVERNAME, serverName);
}
/**
* Gets the server name.
*
* @return serverName
* @see setServerName
*/
public String getServerName() {
return spec.getDetail(DataSourceSpec.SERVERNAME);
}
/**
* Sets the port number.
*
* @param portNumber String
* @see getPortNumber
*/
@ConfigProperty(type = String.class, defaultValue = "1527")
public void setPortNumber(String portNumber) {
spec.setDetail(DataSourceSpec.PORTNUMBER, portNumber);
}
/**
* Gets the port number.
*
* @return portNumber
* @see setPortNumber
*/
public String getPortNumber() {
return spec.getDetail(DataSourceSpec.PORTNUMBER);
}
public void setJdbc30DataSource(String booleanValue) {
spec.setDetail(DataSourceSpec.JDBC30DATASOURCE, booleanValue);
}
public String getJdbc30DataSource() {
return spec.getDetail(DataSourceSpec.JDBC30DATASOURCE);
}
/**
* Sets the database name.
*
* @param databaseName String
* @see getDatabaseName
*/
@ConfigProperty(type = String.class, defaultValue = "testdb")
public void setDatabaseName(String databaseName) {
spec.setDetail(DataSourceSpec.DATABASENAME, databaseName);
}
/**
* Gets the database name.
*
* @return databaseName
* @see setDatabaseName
*/
public String getDatabaseName() {
return spec.getDetail(DataSourceSpec.DATABASENAME);
}
/**
* Sets the data source name.
*
* @param dsn String
* @see getDataSourceName
*/
@ConfigProperty(type = String.class, defaultValue = "")
public void setDataSourceName(String dsn) {
spec.setDetail(DataSourceSpec.DATASOURCENAME, dsn);
}
/**
* Gets the data source name.
*
* @return dsn
* @see setDataSourceName
*/
public String getDataSourceName() {
return spec.getDetail(DataSourceSpec.DATASOURCENAME);
}
/**
* Set Statement Wrapping value
*
* @param wrapping String
* @see getStatementWrapping
*/
public void setStatementWrapping(String wrapping) {
spec.setDetail(DataSourceSpec.STATEMENTWRAPPING, wrapping);
computeStatementWrappingStatus();
}
/**
* Gets the statement wrapping value
*
* @return String representing "true" or "false"
* @see setStatementWrapping
*/
public String getStatementWrapping() {
return spec.getDetail(DataSourceSpec.STATEMENTWRAPPING);
}
public void setStatementCacheSize(String value){
spec.setDetail(DataSourceSpec.STATEMENTCACHESIZE, value);
detectStatementCachingSupport();
}
public String getStatementCacheSize(){
return spec.getDetail(DataSourceSpec.STATEMENTCACHESIZE);
}
public void setStatementLeakTimeoutInSeconds(String value){
spec.setDetail(DataSourceSpec.STATEMENTLEAKTIMEOUTINSECONDS, value);
detectStatementLeakSupport();
}
public String getStatementLeakTimeoutInSeconds(){
return spec.getDetail(DataSourceSpec.STATEMENTLEAKTIMEOUTINSECONDS);
}
public void setStatementLeakReclaim(String value) {
spec.setDetail(DataSourceSpec.STATEMENTLEAKRECLAIM, value);
}
public String getStatementLeakReclaim() {
return spec.getDetail(DataSourceSpec.STATEMENTLEAKRECLAIM);
}
public void setPoolMonitoringSubTreeRoot(String value) {
spec.setDetail(DataSourceSpec.POOLMONITORINGSUBTREEROOT, value);
}
public String getPoolMonitoringSubTreeRoot() {
return spec.getDetail(DataSourceSpec.POOLMONITORINGSUBTREEROOT);
}
public String getApplicationName() {
return spec.getDetail(DataSourceSpec.APPLICATIONNAME);
}
public void setApplicationName(String value) {
spec.setDetail(DataSourceSpec.APPLICATIONNAME, value);
if (sqlTraceDelegator != null) {
sqlTraceDelegator.setAppName(value);
}
}
public String getModuleName() {
return spec.getDetail(DataSourceSpec.MODULENAME);
}
public void setModuleName(String value) {
spec.setDetail(DataSourceSpec.MODULENAME, value);
if (sqlTraceDelegator != null) {
sqlTraceDelegator.setModuleName(value);
}
}
public String getPoolName() {
return spec.getDetail(DataSourceSpec.POOLNAME);
}
public void setPoolName(String value) {
spec.setDetail(DataSourceSpec.POOLNAME, value);
if (sqlTraceDelegator != null) {
sqlTraceDelegator.setPoolName(value);
}
}
public String getStatementCacheType() {
return spec.getDetail(DataSourceSpec.STATEMENTCACHETYPE);
}
public void setStatementCacheType(String statementCacheType) {
spec.setDetail(DataSourceSpec.STATEMENTCACHETYPE, statementCacheType);
this.statementCacheType = getStatementCacheType();
if(this.statementCacheType == null || this.statementCacheType.trim().equals("")) {
if(_logger.isLoggable(Level.FINE)) {
_logger.fine(" Default StatementCaching Type : " +
localStrings.getString("jdbc.statement-cache.default.datastructure"));
}
} else {
if(_logger.isLoggable(Level.FINE)) {
_logger.fine("StatementCaching Type : " + this.statementCacheType);
}
}
}
public String getMaxCacheSize(){
return spec.getDetail(DataSourceSpec.MAXCACHESIZE);
}
public void setMaxCacheSize(String maxCacheSize){
spec.setDetail(DataSourceSpec.MAXCACHESIZE, maxCacheSize);
}
public String getNumberOfTopQueriesToReport() {
return spec.getDetail(DataSourceSpec.NUMBEROFTOPQUERIESTOREPORT);
}
public void setNumberOfTopQueriesToReport(String numTopQueriesToReport) {
spec.setDetail(DataSourceSpec.NUMBEROFTOPQUERIESTOREPORT, numTopQueriesToReport);
}
public String getTimeToKeepQueriesInMinutes() {
return spec.getDetail(DataSourceSpec.TIMETOKEEPQUERIESINMINUTES);
}
public void setTimeToKeepQueriesInMinutes(String timeToKeepQueries) {
spec.setDetail(DataSourceSpec.TIMETOKEEPQUERIESINMINUTES, timeToKeepQueries);
}
public String getInitSql() {
return spec.getDetail(DataSourceSpec.INITSQL);
}
public void setInitSql(String initSql) {
//TODO remove case where "null" is checked. Might be a CLI/GUI bug.
if(initSql != null && !initSql.equalsIgnoreCase("null") &&
!initSql.equals("")) {
spec.setDetail(DataSourceSpec.INITSQL, initSql);
}
}
/**
* Set StatementTimeout value
*
* @param timeout String
* @see getStatementTimeout
*/
public void setStatementTimeout(String timeout) {
spec.setDetail(DataSourceSpec.STATEMENTTIMEOUT, timeout);
}
/**
* Gets the StatementTimeout value
*
* @return String representing "true" or "false"
* @see setStatementTimeout
*/
public String getStatementTimeout() {
return spec.getDetail(DataSourceSpec.STATEMENTTIMEOUT);
}
public String getSqlTraceListeners() {
return spec.getDetail(DataSourceSpec.SQLTRACELISTENERS);
}
public void setSqlTraceListeners(String sqlTraceListeners) {
if(sqlTraceListeners != null) {
spec.setDetail(DataSourceSpec.SQLTRACELISTENERS, sqlTraceListeners);
detectSqlTraceListeners();
}
}
public void setSlowQueryThresholdInSeconds(String seconds) {
spec.setDetail(DataSourceSpec.SLOWSQLLOGTHRESHOLD, seconds);
double threshold = Double.valueOf(seconds);
if (threshold > 0) {
if (sqlTraceDelegator == null) {
sqlTraceDelegator = new SQLTraceDelegator(getPoolName(), getApplicationName(), getModuleName());
}
sqlTraceDelegator.registerSQLTraceListener(new SlowSQLLogger((long)(threshold * 1000), TimeUnit.MILLISECONDS));
}
}
public String getSlowQueryThresholdInSeconds() {
return spec.getDetail(DataSourceSpec.SLOWSQLLOGTHRESHOLD);
}
public void setLogJdbcCalls(String enabled) {
spec.setDetail(DataSourceSpec.LOGJDBCCALLS, enabled);
if (Boolean.valueOf(enabled)) {
if (sqlTraceDelegator == null) {
sqlTraceDelegator = new SQLTraceDelegator(getPoolName(), getApplicationName(), getModuleName());
}
sqlTraceDelegator.registerSQLTraceListener(new SQLTraceLogger());
}
}
public String getLogJdbcCalls() {
return spec.getDetail(DataSourceSpec.LOGJDBCCALLS);
}
/**
* Sets the description.
*
* @param desc String
* @see getDescription
*/
@ConfigProperty(type = String.class, defaultValue = "Derby driver for datasource")
public void setDescription(String desc) {
spec.setDetail(DataSourceSpec.DESCRIPTION, desc);
}
/**
* Gets the description.
*
* @return desc
* @see setDescription
*/
public String getDescription() {
return spec.getDetail(DataSourceSpec.DESCRIPTION);
}
/**
* Sets the network protocol.
*
* @param nwProtocol String
* @see getNetworkProtocol
*/
@ConfigProperty(type = String.class, defaultValue = "")
public void setNetworkProtocol(String nwProtocol) {
spec.setDetail(DataSourceSpec.NETWORKPROTOCOL, nwProtocol);
}
/**
* Gets the network protocol.
*
* @return nwProtocol
* @see setNetworkProtocol
*/
public String getNetworkProtocol() {
return spec.getDetail(DataSourceSpec.NETWORKPROTOCOL);
}
/**
* Sets the role name.
*
* @param roleName String
* @see getRoleName
*/
@ConfigProperty(type = String.class, defaultValue = "")
public void setRoleName(String roleName) {
spec.setDetail(DataSourceSpec.ROLENAME, roleName);
}
/**
* Gets the role name.
*
* @return roleName
* @see setRoleName
*/
public String getRoleName() {
return spec.getDetail(DataSourceSpec.ROLENAME);
}
/**
* Sets the login timeout.
*
* @param loginTimeOut String
* @see getLoginTimeOut
*/
@ConfigProperty(type = String.class, defaultValue = "0")
public void setLoginTimeOut(String loginTimeOut) {
spec.setDetail(DataSourceSpec.LOGINTIMEOUT, loginTimeOut);
}
/**
* Gets the login timeout.
*
* @return loginTimeout
* @see setLoginTimeOut
*/
public String getLoginTimeOut() {
return spec.getDetail(DataSourceSpec.LOGINTIMEOUT);
}
/**
* Sets the delimiter.
*
* @param delim String
* @see getDelimiter
*/
@ConfigProperty(type = String.class, defaultValue = "#")
public void setDelimiter(String delim) {
spec.setDetail(DataSourceSpec.DELIMITER, delim);
}
/**
* Gets the delimiter.
*
* @return delim
* @see setDelimiter
*/
public String getDelimiter() {
return spec.getDetail(DataSourceSpec.DELIMITER);
}
public void setEscapeCharacter(String escapeCharacter){
spec.setDetail(DataSourceSpec.ESCAPECHARACTER, escapeCharacter);
}
public String getEscapeCharacter(){
return spec.getDetail(DataSourceSpec.ESCAPECHARACTER);
}
/**
* Sets the driver specific properties.
*
* @param driverProps String
* @see getDriverProperties
*/
@ConfigProperty(type = String.class, defaultValue = "")
public void setDriverProperties(String driverProps) {
spec.setDetail(DataSourceSpec.DRIVERPROPERTIES, driverProps);
}
/**
* Gets the driver specific properties.
*
* @return driverProps
* @see setDriverProperties
*/
public String getDriverProperties() {
return spec.getDetail(DataSourceSpec.DRIVERPROPERTIES);
}
protected PoolInfo getPoolInfo(){
return new PoolInfo(getPoolName(), getApplicationName(), getModuleName());
}
protected ManagedConnectionImpl constructManagedConnection(PooledConnection pc,
Connection sqlCon, PasswordCredential passCred,
ManagedConnectionFactoryImpl mcf) throws ResourceException {
return new ManagedConnectionImpl(pc, sqlCon, passCred, mcf,
getPoolInfo(), statementCacheSize, statementCacheType, sqlTraceDelegator,
statementLeakTimeout, statementLeakReclaim);
}
/**
* Returns the underlying datasource
*
* @return DataSource of jdbc vendor
* @throws ResourceException
*/
public Object getDataSource() throws ResourceException {
if (dsObjBuilder == null) {
dsObjBuilder = new DataSourceObjectBuilder(spec);
}
return dsObjBuilder.constructDataSourceObject();
}
protected static final int JVM_OPTION_STATEMENT_WRAPPING_ON = 1;
protected static final int JVM_OPTION_STATEMENT_WRAPPING_OFF = 0;
protected static final int JVM_OPTION_STATEMENT_WRAPPING_NOT_SET = -1;
/**
* This wrapStatement flag is used to enable disable wrapping the
* statement objects. This can be enabled by passing jvm option,
* com.sun.appserv.jdbc.wrapstatement = true.
* This can be disabled by removing this option or by passing non true
* value.
* By default this will be disabled
*/
private static int wrapStatement = JVM_OPTION_STATEMENT_WRAPPING_NOT_SET;
static {
wrapStatement = getStatementWrappingJVMOption();
}
/**
* Gets the Statement Wrapping JVM Option (available in 8.2)
* Which will be deprecated in future versions.
*
* @return int representing the JVM Option value of statement wrapping.
*/
private static int getStatementWrappingJVMOption() {
int result = JVM_OPTION_STATEMENT_WRAPPING_NOT_SET;
String str = System.getProperty(
"com.sun.appserv.jdbc.wrapJdbcObjects");
if ("true".equalsIgnoreCase(str)) {
result = JVM_OPTION_STATEMENT_WRAPPING_ON;
} else if ("false".equalsIgnoreCase(str)) {
result = JVM_OPTION_STATEMENT_WRAPPING_OFF;
}
return result;
}
/**
* 9.1 has attribute "wrap-statements" which will be overriden
* when JVM option is specified as "true" or "false"
* JVM Option will be deprecated in future versions.
*/
protected void computeStatementWrappingStatus() {
boolean poolProperty = false;
String statementWrappingString = getStatementWrapping();
if (statementWrappingString != null)
poolProperty = Boolean.valueOf(statementWrappingString);
if (wrapStatement == JVM_OPTION_STATEMENT_WRAPPING_ON ||
(wrapStatement == JVM_OPTION_STATEMENT_WRAPPING_NOT_SET && poolProperty)) {
statementWrapping = true;
} else {
statementWrapping = false;
}
}
/**
* Returns whether statement wrapping is enabled or not.
*
* @return boolean representing statementwrapping status
*/
public boolean isStatementWrappingEnabled() {
return statementWrapping;
}
public JdbcObjectsFactory getJdbcObjectsFactory() {
return jdbcObjectsFactory;
}
protected void logFine(String logMessage){
if(_logger.isLoggable(Level.FINE)) {
_logger.log(Level.FINE, logMessage);
}
}
@Override
public void mcfCreated() {
String poolMonitoringSubTreeRoot = getPoolMonitoringSubTreeRoot();
String sqlTraceListeners = getSqlTraceListeners();
//Default values used in case sql tracing is OFF
int sqlTraceCacheSize = 0;
long timeToKeepQueries = 0;
int maxCacheSize = 0;
if(sqlTraceListeners != null && !sqlTraceListeners.equals("null")) {
if(getNumberOfTopQueriesToReport() != null && !getNumberOfTopQueriesToReport().equals("null")) {
//Some value is set for this property
sqlTraceCacheSize = Integer.parseInt(getNumberOfTopQueriesToReport());
} else {
//No property by this name. default to 10 queries
sqlTraceCacheSize = 10;
}
if(getTimeToKeepQueriesInMinutes() != null && !getTimeToKeepQueriesInMinutes().equals("null")) {
//Time-To-Keep-Queries property has been set
timeToKeepQueries = Integer.parseInt(getTimeToKeepQueriesInMinutes());
} else {
//Default to 5 minutes after which cache is pruned.
timeToKeepQueries = 5;
//Time to keep queries is set to 5 minutes because the timer
//task will keep running till mcf is destroyed even if
//monitoring is turned OFF.
}
if (getMaxCacheSize() != null && !getMaxCacheSize().equals("null")){
maxCacheSize = Integer.parseInt(getMaxCacheSize());
} else {
//Default to 10000 entries
maxCacheSize = 10000;
}
}
if(_logger.isLoggable(Level.FINEST)) {
_logger.finest("MCF Created");
}
if (statementCacheSize > 0 ||
(sqlTraceListeners != null && !sqlTraceListeners.equals("null")) ||
statementLeakTimeout > 0) {
jdbcStatsProvider = new JdbcStatsProvider(getPoolName(), getApplicationName(), getModuleName(),
sqlTraceCacheSize, timeToKeepQueries, maxCacheSize);
//get the poolname and use it to initialize the stats provider n register
StatsProviderManager.register(
"jdbc-connection-pool",
PluginPoint.SERVER,
poolMonitoringSubTreeRoot, jdbcStatsProvider);
if(jdbcStatsProvider.getFreqSqlTraceCache() != null) {
if(_logger.isLoggable(Level.FINEST)) {
_logger.finest("Scheduling timer task for frequent sql trace caching");
}
Timer timer = ((com.sun.gjc.spi.ResourceAdapterImpl) ra).getTimer();
jdbcStatsProvider.getFreqSqlTraceCache().scheduleTimerTask(timer);
}
if (jdbcStatsProvider.getSlowSqlTraceCache() != null) {
if (_logger.isLoggable(Level.FINEST)) {
_logger.finest("Scheduling timer task for slow sql trace caching");
}
Timer timer = ((com.sun.gjc.spi.ResourceAdapterImpl) ra).getTimer();
jdbcStatsProvider.getSlowSqlTraceCache().scheduleTimerTask(timer);
}
if(_logger.isLoggable(Level.FINEST)) {
_logger.finest("Registered JDBCRA Stats Provider");
}
}
}
@Override
public void mcfDestroyed() {
if(_logger.isLoggable(Level.FINEST)) {
_logger.finest("MCF Destroyed");
}
if(jdbcStatsProvider != null) {
if(jdbcStatsProvider.getFreqSqlTraceCache() != null) {
if(_logger.isLoggable(Level.FINEST)) {
_logger.finest("Canceling timer task for frequent sql trace caching");
}
jdbcStatsProvider.getFreqSqlTraceCache().cancelTimerTask();
}
if(jdbcStatsProvider.getSlowSqlTraceCache() != null) {
if(_logger.isLoggable(Level.FINEST)) {
_logger.finest("Canceling timer task for slow sql trace caching");
}
jdbcStatsProvider.getSlowSqlTraceCache().cancelTimerTask();
}
StatsProviderManager.unregister(jdbcStatsProvider);
jdbcStatsProvider = null;
if(_logger.isLoggable(Level.FINEST)) {
_logger.finest("Unregistered JDBCRA Stats Provider");
}
}
}
private void detectStatementLeakSupport() {
String stmtLeakTimeout = getStatementLeakTimeoutInSeconds();
String stmtLeakReclaim = getStatementLeakReclaim();
if (stmtLeakTimeout != null) {
statementLeakTimeout = Integer.parseInt(stmtLeakTimeout) * 1000L;
statementLeakReclaim = Boolean.valueOf(stmtLeakReclaim);
if (_logger.isLoggable(Level.FINE)) {
_logger.log(Level.FINE, "StatementLeakTimeout in seconds: "
+ statementLeakTimeout + " & StatementLeakReclaim: "
+ statementLeakReclaim + " for pool : " + getPoolInfo());
}
}
}
@Override
public void writeExternal(ObjectOutput out) throws IOException {
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
ra = com.sun.gjc.spi.ResourceAdapterImpl.getInstance();
}
}