[jboss-cvs] JBossAS SVN: r93296 - in projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core: connectionmanager and 7 other directories.
jboss-cvs-commits at lists.jboss.org
jboss-cvs-commits at lists.jboss.org
Tue Sep 8 15:59:37 EDT 2009
Author: gurkanerdogdu
Date: 2009-09-08 15:59:36 -0400 (Tue, 08 Sep 2009)
New Revision: 93296
Added:
projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/CachedConnectionManager.java
projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/KeyConnectionAssociation.java
projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/exception/JBossLocalXAException.java
projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/exception/JBossLocalXAExceptionFormatter.java
projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/listener/AbstractConnectionListener.java
projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/listener/NoTxConnectionListener.java
projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/listener/TxConnectionListener.java
projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/transaction/TransactionSynchronizer.java
projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/xa/LocalXAResource.java
projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/xa/XAResourceWrapperImpl.java
Modified:
projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/api/ConnectionManager.java
projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/AbstractConnectionManager.java
projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/ConnectionCounter.java
projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/ConnectionManagerImpl.java
projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/ConnectionRecord.java
projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/listener/ConnectionListener.java
projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/notx/NoTxConnectionManager.java
projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/AbstractPool.java
projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/InternalManagedConnectionPool.java
projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/tx/TxConnectionManager.java
Log:
[JBJCA-167] Generic Connection Manager Implementation
Modified: projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/api/ConnectionManager.java
===================================================================
--- projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/api/ConnectionManager.java 2009-09-08 19:22:26 UTC (rev 93295)
+++ projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/api/ConnectionManager.java 2009-09-08 19:59:36 UTC (rev 93296)
@@ -22,37 +22,33 @@
package org.jboss.jca.core.api;
-import javax.transaction.RollbackException;
-import javax.transaction.SystemException;
+import org.jboss.jca.core.connectionmanager.AbstractConnectionManager;
+import org.jboss.jca.core.connectionmanager.transaction.JTATransactionChecker;
+import java.io.Serializable;
+import org.jboss.tm.TransactionTimeoutConfiguration;
+
/**
* The JBoss specific connection manager interface
* @author <a href="mailto:gurkanerdogdu at yahoo.com">Gurkan Erdogdu</a>
* @version $Rev$ $Date$
*/
-public interface ConnectionManager extends javax.resource.spi.ConnectionManager
-{
+public interface ConnectionManager extends
+ javax.resource.spi.ConnectionManager,
+ Serializable,
+ TransactionTimeoutConfiguration,
+ JTATransactionChecker
+{
/**
- * Document Me!
- * @param errorRollback errorRollback
- * @return time left
- * @throws RollbackException if exception occurs
+ * Sets real connection manager.
+ * @param realConnectionManager real connection manager
*/
- public long getTimeLeftBeforeTransactionTimeout(boolean errorRollback) throws RollbackException;
+ public void setRealConnectionManager(AbstractConnectionManager realConnectionManager);
/**
- * Document Me!
- * @return transaction time out
- * @throws SystemException if any exceptions
+ * Gets real connection manager instance.
+ * @return real connection manager
*/
- public int getTransactionTimeout() throws SystemException;
-
- /**
- * Document Me!
- * @throws RollbackException rollbacked exception
- * @throws SystemException system exception
- */
- public void checkTransactionActive() throws RollbackException, SystemException;
-
+ public AbstractConnectionManager getRealConnectionManager();
}
Property changes on: projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/api/ConnectionManager.java
___________________________________________________________________
Name: svn:keywords
+ Rev Date
Modified: projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/AbstractConnectionManager.java
===================================================================
--- projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/AbstractConnectionManager.java 2009-09-08 19:22:26 UTC (rev 93295)
+++ projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/AbstractConnectionManager.java 2009-09-08 19:59:36 UTC (rev 93296)
@@ -22,25 +22,42 @@
package org.jboss.jca.core.connectionmanager;
+import org.jboss.jca.common.api.JBossResourceException;
import org.jboss.jca.core.connectionmanager.listener.ConnectionCacheListener;
import org.jboss.jca.core.connectionmanager.listener.ConnectionListener;
import org.jboss.jca.core.connectionmanager.listener.ConnectionListenerFactory;
+import org.jboss.jca.core.connectionmanager.listener.ConnectionState;
+import org.jboss.jca.core.connectionmanager.pool.api.ManagedConnectionPool;
import org.jboss.jca.core.connectionmanager.transaction.JTATransactionChecker;
import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
import javax.resource.ResourceException;
-import javax.resource.spi.ManagedConnection;
+import javax.resource.spi.ConnectionRequestInfo;
+import javax.resource.spi.ManagedConnectionFactory;
+import javax.security.auth.Subject;
import javax.transaction.RollbackException;
import javax.transaction.SystemException;
+import javax.transaction.Transaction;
import javax.transaction.TransactionManager;
+import org.jboss.logging.Logger;
+
+import org.jboss.security.SubjectFactory;
import org.jboss.tm.TransactionTimeoutConfiguration;
+import org.jboss.util.NotImplementedException;
+
/**
* AbstractConnectionManager.
+ *
* @author <a href="mailto:gurkanerdogdu at yahoo.com">Gurkan Erdogdu</a>
* @version $Rev$ $Date$
*
@@ -53,23 +70,424 @@
JTATransactionChecker
{
+ /**Log instance*/
+ private Logger log = Logger.getLogger(getClass());
/**
- * {@inheritDoc}
+ * Note that this copy has a trailing / unlike the original in
+ * JaasSecurityManagerService.
*/
- public ConnectionListener createConnectionListener(ManagedConnection managedConnection, Object context)
- throws ResourceException
+ private static final String SECURITY_MGR_PATH = "java:/jaas/";
+
+ /**Connection manager pooling strategy*/
+ private ManagedConnectionPool poolingStrategy;
+
+ /**Security domain jndi name*/
+ private String securityDomainJndiName;
+
+ /**SubjectFactory*/
+ private SubjectFactory subjectFactory;
+
+ /**Log trace*/
+ private boolean trace;
+
+ /**Number of retry to allocate connection*/
+ private int allocationRetry;
+
+ /**Interval between retries*/
+ private long allocationRetryWaitMillis;
+
+ /**Startup/ShutDown flag*/
+ private AtomicBoolean shutdown = new AtomicBoolean(false);
+
+ /**Cached connection manager*/
+ private CachedConnectionManager cachedConnectionManager;
+
+ /**Jndi name*/
+ private String jndiName;
+
+ /**
+ * Creates a new instance of connection manager.
+ */
+ protected AbstractConnectionManager()
{
- // TODO Auto-generated method stub
+ this.trace = log.isTraceEnabled();
+ }
+
+ /**
+ * Gets log.
+ * @return log instance
+ */
+ protected Logger getLog()
+ {
+ return this.log;
+ }
+
+ /**
+ * Sets pooling strategy.
+ * @param poolingStrategy pooling strategy
+ */
+ public void setPoolingStrategy(ManagedConnectionPool poolingStrategy)
+ {
+ this.poolingStrategy = poolingStrategy;
+ }
+
+ /**
+ * Gets pooling strategy.
+ * @return pooling strategy
+ */
+ public ManagedConnectionPool getPoolingStrategy()
+ {
+ return this.poolingStrategy;
+ }
+
+ /**
+ * Sets cached connection manager.
+ * @param cachedConnectionManager cached connection manager
+ */
+ public void setCachedConnectionManager(CachedConnectionManager cachedConnectionManager)
+ {
+ this.cachedConnectionManager = cachedConnectionManager;
+ }
+
+
+ /**
+ * Sets shut down flag.
+ * @param shutDown shut down flag
+ */
+ public void setShutDown(boolean shutDown)
+ {
+ this.shutdown.set(shutDown);
+ }
+
+ /**
+ * Gets cached connection manager.
+ * @return cached connection manager
+ */
+ public CachedConnectionManager getCachedConnectionManager()
+ {
+ return this.cachedConnectionManager;
+ }
+
+ /**
+ * Gets jndi name.
+ * @return jndi name
+ */
+ public String getJndiName()
+ {
+ return jndiName;
+ }
+
+ /**
+ * Sets jndi name.
+ * @param jndiName jndi name
+ */
+ public void setJndiName(String jndiName)
+ {
+ this.jndiName = jndiName;
+ }
+
+ /**
+ * Sets security domain jndi name.
+ * @param securityDomainJndiName security jndi name
+ */
+ public void setSecurityDomainJndiName(String securityDomainJndiName)
+ {
+ if (securityDomainJndiName != null && securityDomainJndiName.startsWith(SECURITY_MGR_PATH))
+ {
+ securityDomainJndiName = securityDomainJndiName.substring(SECURITY_MGR_PATH.length());
+ log.warn("WARNING: UPDATE YOUR SecurityDomainJndiName! REMOVE " + SECURITY_MGR_PATH);
+ }
+
+ this.securityDomainJndiName = securityDomainJndiName;
+ }
+
+ /**
+ * Gets security domain jndi name.
+ * @return security domain jndi name
+ */
+ public String getSecurityDomainJndiName()
+ {
+ return securityDomainJndiName;
+ }
+
+ /**
+ * Gets subject factory instance.
+ * @return subject factory
+ */
+ public SubjectFactory getSubjectFactory()
+ {
+ return subjectFactory;
+ }
+
+ /**
+ * Sets subject factory.
+ * @param subjectFactory subject factory
+ */
+ public void setSubjectFactory(SubjectFactory subjectFactory)
+ {
+ this.subjectFactory = subjectFactory;
+ }
+
+
+ /**
+ * Gets managed connection factory.
+ * @return managed connection factory
+ */
+ public javax.resource.spi.ManagedConnectionFactory getManagedConnectionFactory()
+ {
+ if (this.poolingStrategy == null)
+ {
+ if (this.log.isTraceEnabled())
+ {
+ log.trace("No pooling strategy found! for connection manager : " + this);
+
+ return null;
+ }
+ }
+ else
+ {
+ return poolingStrategy.getManagedConnectionFactory();
+ }
+
return null;
}
+
+ /**
+ * Set the number of allocation retries
+ * @param number retry number
+ */
+ public void setAllocationRetry(int number)
+ {
+ if (number >= 0)
+ allocationRetry = number;
+ }
/**
+ * Get the number of allocation retries
+ * @return The number of retries
+ */
+ public int getAllocationRetry()
+ {
+ return allocationRetry;
+ }
+
+ /**
+ * Set the wait time between each allocation retry
+ * @param millis wait in ms
+ */
+ public void setAllocationRetryWaitMillis(long millis)
+ {
+ if (millis > 0)
+ allocationRetryWaitMillis = millis;
+ }
+
+ /**
+ * Get the wait time between each allocation retry
+ * @return The millis
+ */
+ public long getAllocationRetryWaitMillis()
+ {
+ return allocationRetryWaitMillis;
+ }
+
+ /**
+ * Public for use in testing pooling functionality by itself.
+ * called by both allocateConnection and reconnect.
+ *
+ * @param subject a <code>Subject</code> value
+ * @param cri a <code>ConnectionRequestInfo</code> value
+ * @return a <code>ManagedConnection</code> value
+ * @exception ResourceException if an error occurs
+ */
+ public ConnectionListener getManagedConnection(Subject subject, ConnectionRequestInfo cri) throws ResourceException
+ {
+ return getManagedConnection(null, subject, cri);
+ }
+
+ /**
+ * Get the managed connection from the pool.
+ *
+ * @param transaction the transaction for track by transaction
+ * @param subject the subject
+ * @param cri the ConnectionRequestInfo
+ * @return a managed connection
+ * @exception ResourceException if an error occurs
+ */
+ protected ConnectionListener getManagedConnection(Transaction transaction, Subject subject,
+ ConnectionRequestInfo cri) throws ResourceException
+ {
+ ResourceException failure = null;
+
+ if (this.shutdown.get())
+ {
+ throw new ResourceException("The connection manager is shutdown " + jndiName);
+ }
+
+ // First attempt
+ try
+ {
+ return this.poolingStrategy.getConnection(transaction, subject, cri);
+ }
+ catch (ResourceException e)
+ {
+ failure = e;
+
+ // Retry?
+ if (this.allocationRetry != 0)
+ {
+ for (int i = 0; i < this.allocationRetry; i++)
+ {
+ if (this.shutdown.get())
+ {
+ throw new ResourceException("The connection manager is shutdown " + jndiName);
+ }
+
+ if (this.trace)
+ {
+ log.trace("Attempting allocation retry for cri=" + cri);
+ }
+
+ try
+ {
+ if (allocationRetryWaitMillis != 0)
+ {
+ Thread.sleep(allocationRetryWaitMillis);
+ }
+
+ return poolingStrategy.getConnection(transaction, subject, cri);
+ }
+ catch (ResourceException re)
+ {
+ failure = re;
+ }
+ catch (InterruptedException ie)
+ {
+ JBossResourceException.rethrowAsResourceException("getManagedConnection retry wait was interrupted " +
+ jndiName, ie);
+ }
+ }
+ }
+ }
+
+ // If we get here all retries failed, throw the lastest failure
+ throw new ResourceException("Unable to get managed connection for " + jndiName, failure);
+ }
+
+ /**
+ * Kill given connection listener wrapped connection instance.
+ * @param cl connection listener that wraps connection
+ * @param kill kill connection or not
+ */
+ public void returnManagedConnection(ConnectionListener cl, boolean kill)
+ {
+ ManagedConnectionPool localStrategy = cl.getManagedConnectionPool();
+ if (localStrategy != this.poolingStrategy)
+ {
+ kill = true;
+ }
+
+ try
+ {
+ if (!kill && cl.getState().equals(ConnectionState.NORMAL))
+ {
+ cl.tidyup();
+ }
+ }
+ catch (Throwable t)
+ {
+ log.warn("Error during tidy up connection" + cl, t);
+ kill = true;
+ }
+
+ try
+ {
+ localStrategy.returnConnection(cl, kill);
+ }
+ catch (ResourceException re)
+ {
+ // We can receive notification of an error on the connection
+ // before it has been assigned to the pool. Reduce the noise for
+ // these errors
+ if (kill)
+ {
+ log.debug("resourceException killing connection (error retrieving from pool?)", re);
+ }
+ else
+ {
+ log.warn("resourceException returning connection: " + cl.getManagedConnection(), re);
+ }
+ }
+ }
+
+
+ /**
+ * Gets connection handle instance.
+ * @param mcf managed connection factory
+ * @param cri connection request info
+ * @return ne wconnection
+ * @throws ResourceException for exception
+ */
+ public Object allocateConnection(ManagedConnectionFactory mcf, ConnectionRequestInfo cri) throws ResourceException
+ {
+ //Check for pooling!
+ if (this.poolingStrategy == null)
+ {
+ throw new ResourceException("You are trying to use a connection factory that has been shut down: " +
+ "ManagedConnectionFactory is null.");
+ }
+
+ //it is an explicit spec requirement that equals be used for matching rather than ==.
+ if (!this.poolingStrategy.getManagedConnectionFactory().equals(mcf))
+ {
+ throw new ResourceException("Wrong ManagedConnectionFactory sent to allocateConnection!");
+ }
+
+ // Pick a managed connection from the pool
+ Subject subject = getSubject();
+ ConnectionListener cl = getManagedConnection(subject, cri);
+
+ // Tell each connection manager the managed connection is active
+ reconnectManagedConnection(cl);
+
+ // Ask the managed connection for a connection
+ Object connection = null;
+ try
+ {
+ connection = cl.getManagedConnection().getConnection(subject, cri);
+ }
+ catch (Throwable t)
+ {
+ try
+ {
+ managedConnectionDisconnected(cl);
+ }
+ catch (ResourceException re)
+ {
+ log.trace("Get exception from managedConnectionDisconnected, maybe delist() have problem" + re);
+ returnManagedConnection(cl, true);
+ }
+ JBossResourceException.rethrowAsResourceException(
+ "Unchecked throwable in ManagedConnection.getConnection() cl=" + cl, t);
+ }
+
+ // Associate managed connection with the connection
+ registerAssociation(cl, connection);
+
+ if (this.cachedConnectionManager != null)
+ {
+ this.cachedConnectionManager.registerConnection(this, cl, connection, cri);
+ }
+
+ return connection;
+ }
+
+
+ /**
* {@inheritDoc}
*/
public TransactionManager getTransactionManagerInstance()
{
- // TODO Auto-generated method stub
return null;
}
@@ -78,7 +496,6 @@
*/
public boolean isTransactional()
{
- // TODO Auto-generated method stub
return false;
}
@@ -87,8 +504,7 @@
*/
public long getTimeLeftBeforeTransactionTimeout(boolean arg0) throws RollbackException
{
- // TODO Auto-generated method stub
- return 0;
+ return -1;
}
/**
@@ -96,8 +512,7 @@
*/
public int getTransactionTimeout() throws SystemException
{
- // TODO Auto-generated method stub
- return 0;
+ throw new NotImplementedException("NYI: getTransactionTimeout()");
}
/**
@@ -105,17 +520,40 @@
*/
public void checkTransactionActive() throws RollbackException, SystemException
{
- // TODO Auto-generated method stub
-
+ //Do Nothing as default
}
/**
* {@inheritDoc}
*/
- public void disconnect(Collection<ConnectionRecord> conns, Set<String> unsharableResources) throws ResourceException
+ public void disconnect(Collection<ConnectionRecord> conRecords, Set<String> unsharableResources)
+ throws ResourceException
{
- // TODO Auto-generated method stub
-
+ // if we have an unshareable connection do not remove the association
+ // nothing to do
+ if (unsharableResources.contains(this.jndiName))
+ {
+ log.trace("disconnect for unshareable connection: nothing to do");
+
+ return;
+ }
+
+ Set<ConnectionListener> cls = new HashSet<ConnectionListener>();
+ for (Iterator<ConnectionRecord> i = conRecords.iterator(); i.hasNext();)
+ {
+ ConnectionRecord cr = i.next();
+ ConnectionListener cl = cr.getConnectionListener();
+ cr.setConnectionListener(null);
+ unregisterAssociation(cl, cr.getConnection());
+ if (!cls.contains(cl))
+ {
+ cls.add(cl);
+ }
+ }
+ for (Iterator<ConnectionListener> i = cls.iterator(); i.hasNext();)
+ {
+ disconnectManagedConnection((ConnectionListener) i.next());
+ }
}
/**
@@ -123,8 +561,42 @@
*/
public void reconnect(Collection<ConnectionRecord> conns, Set<String> unsharableResources) throws ResourceException
{
- // TODO Auto-generated method stub
+ // if we have an unshareable connection the association was not removed
+ // nothing to do
+ if (unsharableResources.contains(jndiName))
+ {
+ log.trace("reconnect for unshareable connection: nothing to do");
+ return;
+ }
+
+ Map<ConnectionRequestInfo, ConnectionListener> criToCLMap =
+ new HashMap<ConnectionRequestInfo, ConnectionListener>();
+ for (Iterator<ConnectionRecord> i = conns.iterator(); i.hasNext();)
+ {
+ ConnectionRecord cr = i.next();
+ if (cr.getConnectionListener() != null)
+ {
+ //This might well be an error.
+ log.warn("reconnecting a connection handle that still has a managedConnection! "
+ + cr.getConnectionListener().getManagedConnection() + " " + cr.getConnection());
+ }
+ ConnectionListener cl = (ConnectionListener) criToCLMap.get(cr.getCri());
+ if (cl == null)
+ {
+ cl = getManagedConnection(getSubject(), cr.getCri());
+ criToCLMap.put(cr.getCri(), cl);
+ //only call once per managed connection, when we get it.
+ reconnectManagedConnection(cl);
+ }
+
+ cl.getManagedConnection().associateConnection(cr.getConnection());
+ registerAssociation(cl, cr.getConnection());
+ cr.setConnectionListener(cl);
+ }
+
+ criToCLMap.clear();
+
}
/**
@@ -132,8 +604,120 @@
*/
public void transactionStarted(Collection<ConnectionRecord> conns) throws SystemException
{
- // TODO Auto-generated method stub
+ //reimplement in subclasses
+ }
+
+
+ /**
+ * Unregister association.
+ * @param cl connection listener
+ * @param c connection
+ */
+ //does NOT put the mc back in the pool if no more handles. Doing so would introduce a race condition
+ //whereby the mc got back in the pool while still enlisted in the tx.
+ //The mc could be checked out again and used before the delist occured.
+ public void unregisterAssociation(ConnectionListener cl, Object c)
+ {
+ cl.unregisterConnection(c);
+ }
+
+ /**
+ * Invoked to reassociate a managed connection.
+ *
+ * @param cl the managed connection
+ * @throws ResourceException for exception
+ */
+ protected void reconnectManagedConnection(ConnectionListener cl) throws ResourceException
+ {
+ try
+ {
+ managedConnectionReconnected(cl);
+ }
+ catch (Throwable t)
+ {
+ disconnectManagedConnection(cl);
+ JBossResourceException.rethrowAsResourceException("Unchecked throwable in managedConnectionReconnected() cl="
+ + cl, t);
+ }
+ }
+
+ /**
+ * Invoked when a managed connection is no longer associated
+ *
+ * @param cl the managed connection
+ */
+ protected void disconnectManagedConnection(ConnectionListener cl)
+ {
+ try
+ {
+ managedConnectionDisconnected(cl);
+ }
+ catch (Throwable t)
+ {
+ log.warn("Unchecked throwable in managedConnectionDisconnected() cl=" + cl, t);
+ }
+ }
+
+ /**
+ * For polymorphism.
+ * <p>
+ *
+ * Do not invoke directly, use reconnectManagedConnection
+ * which does the relevent exception handling
+ * @param cl connection listener
+ * @throws ResourceException for exception
+ */
+ protected void managedConnectionReconnected(ConnectionListener cl) throws ResourceException
+ {
+ //Nothing as default
+ }
+
+ /**
+ * For polymorphism.
+ * <p>
+ *
+ * Do not invoke directly, use disconnectManagedConnection
+ * which does the relevent exception handling
+ * @param cl connection listener
+ * @throws ResourceException for exception
+ */
+ protected void managedConnectionDisconnected(ConnectionListener cl) throws ResourceException
+ {
+ //Nothing as default
+ }
+
+ /**
+ * Register connection with connection listener.
+ * @param cl connection listener
+ * @param c connection
+ * @throws ResourceException exception
+ */
+ private void registerAssociation(ConnectionListener cl, Object c) throws ResourceException
+ {
+ cl.registerConnection(c);
+ }
+
+
+ /**
+ * Gets subject.
+ * @return subject
+ */
+ private Subject getSubject()
+ {
+ Subject subject = null;
+ if (subjectFactory != null && securityDomainJndiName != null)
+ {
+ subject = subjectFactory.createSubject(securityDomainJndiName);
+ }
+
+ if (trace)
+ {
+ log.trace("subject: " + subject);
+ }
+
+ return subject;
}
+
}
Property changes on: projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/AbstractConnectionManager.java
___________________________________________________________________
Name: svn:keywords
+ Rev Date
Added: projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/CachedConnectionManager.java
===================================================================
--- projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/CachedConnectionManager.java (rev 0)
+++ projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/CachedConnectionManager.java 2009-09-08 19:59:36 UTC (rev 93296)
@@ -0,0 +1,649 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008-2009, 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.jca.core.connectionmanager;
+
+import org.jboss.jca.core.connectionmanager.listener.ConnectionCacheListener;
+import org.jboss.jca.core.connectionmanager.listener.ConnectionListener;
+import org.jboss.jca.core.connectionmanager.transaction.TransactionSynchronizer;
+import org.jboss.jca.spi.ComponentStack;
+
+import java.lang.reflect.Method;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.WeakHashMap;
+import java.util.concurrent.CopyOnWriteArraySet;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+
+import javax.resource.ResourceException;
+import javax.resource.spi.ConnectionRequestInfo;
+import javax.transaction.Synchronization;
+import javax.transaction.SystemException;
+import javax.transaction.Transaction;
+import javax.transaction.TransactionManager;
+
+import org.jboss.logging.Logger;
+
+import org.jboss.tm.TxUtils;
+import org.jboss.tm.usertx.UserTransactionListener;
+import org.jboss.tm.usertx.client.ServerVMClientUserTransaction.UserTransactionStartedListener;
+import org.jboss.util.Strings;
+
+/**
+ * CacheConnectionManager.
+ * @version $Rev$ $Date$
+ *
+ */
+public class CachedConnectionManager implements
+ UserTransactionStartedListener,
+ UserTransactionListener,
+ ComponentStack
+{
+ /**Log instance*/
+ private static Logger log = Logger.getLogger(CachedConnectionManager.class);
+
+ /**Log trace*/
+ private boolean trace;
+
+ /**Debug flag*/
+ private boolean debug;
+
+ /**Error flag*/
+ private boolean error;
+
+ /**Transaction Manager instance*/
+ private TransactionManager transactionManager;
+
+ /**
+ * ThreadLocal that holds current calling meta-programming aware
+ * object, used in case someone is idiotic enough to cache a
+ * connection between invocations.and want the spec required
+ * behavior of it getting hooked up to an appropriate
+ * ManagedConnection on each method invocation.
+ */
+ private final ThreadLocal<LinkedList<Object>> currentObjects = new ThreadLocal<LinkedList<Object>>();
+
+ /**
+ * The variable <code>objectToConnectionManagerMap</code> holds the
+ * map of meta-aware object to set of connections it holds, used by
+ * the idiot spec compliant behavior.
+ */
+ private final Map<KeyConnectionAssociation, Map<ConnectionCacheListener, Collection<ConnectionRecord>>>
+ objectToConnectionManagerMap = new HashMap<KeyConnectionAssociation,
+ Map<ConnectionCacheListener, Collection<ConnectionRecord>>>();
+
+ /**
+ * Connection stacktraces
+ */
+ private Map<Object, Throwable> connectionStackTraces = new WeakHashMap<Object, Throwable>();
+
+ /**
+ * Creates a new instance.
+ */
+ public CachedConnectionManager()
+ {
+ this.trace = log.isTraceEnabled();
+ }
+
+ /**
+ * Gets transaction manager.
+ * @return transaction manager
+ */
+ public TransactionManager getTransactionManager()
+ {
+ return this.transactionManager;
+ }
+
+ /**
+ * Sets transaction manager.
+ * @param transactionManager transaction manager
+ */
+ public void setTransactionManager(TransactionManager transactionManager)
+ {
+ this.transactionManager = transactionManager;
+
+ // FIXME we should be injecting onto the synchronizer directly
+ if (this.transactionManager != null)
+ {
+ TransactionSynchronizer.setTransactionManager(transactionManager);
+ }
+
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public void userTransactionStarted() throws SystemException
+ {
+ KeyConnectionAssociation key = peekMetaAwareObject();
+ if (trace)
+ {
+ log.trace("user tx started, key: " + key);
+ }
+ if (key == null)
+ {
+ return; //not participating properly in this management scheme.
+ }
+
+ Map<ConnectionCacheListener, Collection<ConnectionRecord>> cmToConnectionsMap = key.getCMToConnectionsMap();
+ Iterator<Entry<ConnectionCacheListener, Collection<ConnectionRecord>>> cmToConnectionsMapIterator =
+ cmToConnectionsMap.entrySet().iterator();
+
+ while (cmToConnectionsMapIterator.hasNext())
+ {
+ Entry<ConnectionCacheListener, Collection<ConnectionRecord>> entry = cmToConnectionsMapIterator.next();
+ ConnectionCacheListener cm = (ConnectionCacheListener) entry.getKey();
+ Collection<ConnectionRecord> conns = entry.getValue();
+
+ cm.transactionStarted(conns);
+ }
+ }
+
+ /**
+ *
+ * @return stack last meta-aware object
+ */
+ KeyConnectionAssociation peekMetaAwareObject()
+ {
+ LinkedList<Object> stack = currentObjects.get();
+ if (stack == null)
+ {
+ return null;
+ }
+
+ if (!stack.isEmpty())
+ {
+ return (KeyConnectionAssociation) stack.getLast();
+ }
+
+ else
+ {
+ return null;
+ }
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @SuppressWarnings("unchecked")
+ public void popMetaAwareObject(Set unsharableResources) throws ResourceException
+ {
+ LinkedList<Object> stack = this.currentObjects.get();
+ KeyConnectionAssociation oldKey = (KeyConnectionAssociation) stack.removeLast();
+ if (this.trace)
+ {
+ log.trace("popped object: " + Strings.defaultToString(oldKey));
+ }
+
+ if (!stack.contains(oldKey))
+ {
+ disconnect(oldKey, unsharableResources);
+ } // end of if ()
+
+ if (this.debug)
+ {
+ if (closeAll(oldKey.getCMToConnectionsMap()) && this.error)
+ {
+ throw new ResourceException("Some connections were not closed, " +
+ "see the log for the allocation stacktraces");
+ }
+ }
+
+ }
+
+ /**
+ * Register connection.
+ * @param cm connection manager
+ * @param cl connection listener
+ * @param connection connection handle
+ * @param cri connection request info.
+ */
+ public void registerConnection(ConnectionCacheListener cm, ConnectionListener cl,
+ Object connection, ConnectionRequestInfo cri)
+ {
+ if (this.debug)
+ {
+ synchronized (this.connectionStackTraces)
+ {
+ this.connectionStackTraces.put(connection, new Throwable("STACKTRACE"));
+ }
+ }
+
+ KeyConnectionAssociation key = peekMetaAwareObject();
+
+ if (this.trace)
+ {
+ log.trace("registering connection from connection manager " + cm +
+ ", connection : " + connection + ", key: " + key);
+ }
+
+ if (key == null)
+ {
+ return; //not participating properly in this management scheme.
+ }
+
+ ConnectionRecord cr = new ConnectionRecord(cl, connection, cri);
+ Map<ConnectionCacheListener, Collection<ConnectionRecord>> cmToConnectionsMap = key.getCMToConnectionsMap();
+ Collection<ConnectionRecord> conns = cmToConnectionsMap.get(cm);
+ if (conns == null)
+ {
+ conns = new ArrayList<ConnectionRecord>();
+ cmToConnectionsMap.put(cm, conns);
+ }
+
+ conns.add(cr);
+ }
+
+ /**
+ * Unregister connection.
+ * @param cm connection manager
+ * @param connection connection handle
+ */
+ public void unregisterConnection(ConnectionCacheListener cm, Object connection)
+ {
+ if (this.debug)
+ {
+ CloseConnectionSynchronization cas = getCloseConnectionSynchronization(false);
+ if (cas != null)
+ {
+ cas.remove(connection);
+ }
+
+ synchronized (this.connectionStackTraces)
+ {
+ this.connectionStackTraces.remove(connection);
+ }
+ }
+
+ KeyConnectionAssociation key = peekMetaAwareObject();
+
+ if (this.trace)
+ {
+ log.trace("unregistering connection from connection manager " + cm +
+ ", object: " + connection + ", key: " + key);
+ }
+
+ if (key == null)
+ {
+ return; //not participating properly in this management scheme.
+ }
+
+ Map<ConnectionCacheListener, Collection<ConnectionRecord>> cmToConnectionsMap = key.getCMToConnectionsMap();
+ Collection<ConnectionRecord> conns = cmToConnectionsMap.get(cm);
+ if (conns == null)
+ {
+ return; // Can happen if connections are "passed" between contexts
+ }
+
+ for (Iterator<ConnectionRecord> i = conns.iterator(); i.hasNext();)
+ {
+ if ((i.next()).getConnection() == connection)
+ {
+ i.remove();
+ return;
+ }
+ }
+
+ throw new IllegalStateException("Trying to return an unknown connection2! " + connection);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @SuppressWarnings("unchecked")
+ public void pushMetaAwareObject(final Object rawKey, Set unsharableResources) throws ResourceException
+ {
+ LinkedList<Object> stack = this.currentObjects.get();
+ if (stack == null)
+ {
+ if (this.trace)
+ {
+ log.trace("new stack for key: " + Strings.defaultToString(rawKey));
+ }
+
+ stack = new LinkedList<Object>();
+ currentObjects.set(stack);
+ }
+ else
+ {
+ if (trace)
+ {
+ log.trace("old stack for key: " + Strings.defaultToString(rawKey));
+ }
+ }
+
+ KeyConnectionAssociation key = new KeyConnectionAssociation(rawKey);
+ if (!stack.contains(key))
+ {
+ reconnect(key, unsharableResources);
+ }
+
+ stack.addLast(key);
+ }
+
+ /**
+ * The <code>reconnect</code> method gets the cmToConnectionsMap
+ * from objectToConnectionManagerMap, copies it to the key, and
+ * reconnects all the connections in it.
+ *
+ * @param key a <code>KeyConnectionAssociation</code> value
+ * @param unsharableResources a <code>Set</code> value
+ * @exception ResourceException if an error occurs
+ */
+ @SuppressWarnings("unchecked")
+ private void reconnect(KeyConnectionAssociation key, Set unsharableResources) throws ResourceException
+ {
+ Map<ConnectionCacheListener, Collection<ConnectionRecord>> cmToConnectionsMap = null;
+ synchronized (this.objectToConnectionManagerMap)
+ {
+ cmToConnectionsMap = this.objectToConnectionManagerMap.get(key);
+ if (cmToConnectionsMap == null)
+ {
+ return;
+ }
+ }
+ key.setCMToConnectionsMap(cmToConnectionsMap);
+ Iterator<Entry<ConnectionCacheListener, Collection<ConnectionRecord>>> cmToConnectionsMapIterator =
+ cmToConnectionsMap.entrySet().iterator();
+
+ while (cmToConnectionsMapIterator.hasNext())
+ {
+ Entry<ConnectionCacheListener, Collection<ConnectionRecord>> entry = cmToConnectionsMapIterator.next();
+ ConnectionCacheListener cm = (ConnectionCacheListener) entry.getKey();
+ Collection<ConnectionRecord> conns = entry.getValue();
+
+ cm.reconnect(conns, unsharableResources);
+ }
+ }
+
+ /**
+ * Disconnect connections.
+ * @param key key
+ * @param unsharableResources resource
+ * @throws ResourceException exception
+ */
+ @SuppressWarnings("unchecked")
+ private void disconnect(KeyConnectionAssociation key, Set unsharableResources) throws ResourceException
+ {
+ Map<ConnectionCacheListener, Collection<ConnectionRecord>> cmToConnectionsMap = null;
+ cmToConnectionsMap = key.getCMToConnectionsMap();
+ if (!cmToConnectionsMap.isEmpty())
+ {
+ synchronized (objectToConnectionManagerMap)
+ {
+ objectToConnectionManagerMap.put(key, cmToConnectionsMap);
+ }
+ Iterator<Entry<ConnectionCacheListener, Collection<ConnectionRecord>>> cmToConnectionsMapIterator =
+ cmToConnectionsMap.entrySet().iterator();
+
+ while (cmToConnectionsMapIterator.hasNext())
+ {
+ Entry<ConnectionCacheListener, Collection<ConnectionRecord>> entry = cmToConnectionsMapIterator.next();
+ ConnectionCacheListener cm = (ConnectionCacheListener) entry.getKey();
+ Collection<ConnectionRecord> conns = entry.getValue();
+
+ cm.disconnect(conns, unsharableResources);
+ }
+ }
+ }
+
+ /**
+ * Describe <code>unregisterConnectionCacheListener</code> method here.
+ * This is a shutdown method called by a connection manager. It will remove all reference
+ * to that connection manager from the cache, so cached connections from that manager
+ * will never be recoverable.
+ * Possibly this method should not exist.
+ *
+ * @param cm a <code>ConnectionCacheListener</code> value
+ */
+ public void unregisterConnectionCacheListener(ConnectionCacheListener cm)
+ {
+ if (trace)
+ {
+ log.trace("unregisterConnectionCacheListener: " + cm);
+ }
+
+ synchronized (objectToConnectionManagerMap)
+ {
+ Iterator<Map<ConnectionCacheListener, Collection<ConnectionRecord>>> it =
+ this.objectToConnectionManagerMap.values().iterator();
+
+ while (it.hasNext())
+ {
+ Map<ConnectionCacheListener, Collection<ConnectionRecord>> cmToConnectionsMap = it.next();
+ if (cmToConnectionsMap != null)
+ {
+ cmToConnectionsMap.remove(cm);
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Close all connections.
+ * @param cmToConnectionsMap connection manager to connections
+ * @return true if close
+ */
+ private boolean closeAll(Map<ConnectionCacheListener, Collection<ConnectionRecord>> cmToConnectionsMap)
+ {
+ if (!debug)
+ {
+ return false;
+ }
+
+ boolean unclosed = false;
+
+ Collection<Collection<ConnectionRecord>> connections = cmToConnectionsMap.values();
+ if (connections.size() != 0)
+ {
+ for (Iterator<Collection<ConnectionRecord>> i = connections.iterator(); i.hasNext();)
+ {
+ Collection<ConnectionRecord> conns = i.next();
+ for (Iterator<ConnectionRecord> j = conns.iterator(); j.hasNext();)
+ {
+ Object c = (j.next()).getConnection();
+ CloseConnectionSynchronization cas = getCloseConnectionSynchronization(true);
+ if (cas == null)
+ {
+ unclosed = true;
+ closeConnection(c);
+ }
+ else
+ {
+ cas.add(c);
+ }
+ }
+ }
+ }
+
+ return unclosed;
+ }
+
+ /**
+ * Gets close sync. instance.
+ * @param createIfNotFound create if not found
+ * @return sync. instance
+ */
+ private CloseConnectionSynchronization getCloseConnectionSynchronization(boolean createIfNotFound)
+ {
+ try
+ {
+ Transaction tx = null;
+ if (this.transactionManager != null)
+ {
+ tx = this.transactionManager.getTransaction();
+ }
+
+ if (tx != null)
+ {
+ TransactionSynchronizer.lock(tx);
+ try
+ {
+ CloseConnectionSynchronization cas = (CloseConnectionSynchronization)
+ TransactionSynchronizer.getCCMSynchronization(tx);
+
+ if (cas == null && createIfNotFound && TxUtils.isActive(tx))
+ {
+ cas = new CloseConnectionSynchronization();
+ TransactionSynchronizer.registerCCMSynchronization(tx, cas);
+ }
+
+ return cas;
+ }
+ finally
+ {
+ TransactionSynchronizer.unlock(tx);
+ }
+ }
+ }
+ catch (Throwable t)
+ {
+ log.debug("Unable to synchronize with transaction", t);
+ }
+
+ return null;
+ }
+
+
+ /**
+ * Close connection handle.
+ * @param connectionHandle connection handle
+ */
+ private void closeConnection(Object connectionHandle)
+ {
+ try
+ {
+ Throwable exception;
+
+ synchronized (connectionStackTraces)
+ {
+ exception = (Throwable) connectionStackTraces.remove(connectionHandle);
+ }
+
+ Method m = connectionHandle.getClass().getMethod("close", new Class[]{});
+
+ try
+ {
+ if (exception != null)
+ {
+ log.info("Closing a connection for you. Please close them yourself: " + connectionHandle, exception);
+ }
+ else
+ {
+ log.info("Closing a connection for you. Please close them yourself: " + connectionHandle);
+ }
+
+ m.invoke(connectionHandle, new Object[]{});
+ }
+ catch (Throwable t)
+ {
+ log.info("Throwable trying to close a connection for you, please close it yourself", t);
+ }
+ }
+ catch (NoSuchMethodException nsme)
+ {
+ log.info("Could not find a close method on alleged connection objects. Please close your own connections.");
+ }
+ }
+
+
+ /**
+ * Close synch. class.
+ */
+ private class CloseConnectionSynchronization implements Synchronization
+ {
+ /**Connection handles*/
+ CopyOnWriteArraySet<Object> connections = new CopyOnWriteArraySet<Object>();
+
+ /**Closing flag*/
+ AtomicBoolean closing = new AtomicBoolean(false);
+
+ /**
+ * Creates a new instance.
+ */
+ public CloseConnectionSynchronization()
+ {
+
+ }
+
+ /**
+ * Add new connection handle.
+ * @param c connection handle
+ */
+ public void add(Object c)
+ {
+ if (closing.get())
+ {
+ return;
+ }
+ connections.add(c);
+ }
+
+ /**
+ * Removes connection handle.
+ * @param c connection handle
+ */
+ public void remove(Object c)
+ {
+ if (closing.get())
+ {
+ return;
+ }
+
+ connections.remove(c);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void beforeCompletion()
+ {
+ //No-action
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void afterCompletion(int status)
+ {
+ this.closing.set(true);
+
+ for (Iterator<Object> i = connections.iterator(); i.hasNext();)
+ {
+ closeConnection(i.next());
+ }
+
+ connections.clear();
+ }
+ }
+
+}
Property changes on: projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/CachedConnectionManager.java
___________________________________________________________________
Name: svn:keywords
+ Rev Date
Name: svn:eol-style
+ native
Modified: projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/ConnectionCounter.java
===================================================================
--- projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/ConnectionCounter.java 2009-09-08 19:22:26 UTC (rev 93295)
+++ projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/ConnectionCounter.java 2009-09-08 19:59:36 UTC (rev 93296)
@@ -124,7 +124,7 @@
* Gets timed out connections.
* @return timeout
*/
- public int getTimedOut()
+ public int getTimedOutCount()
{
return timedOut;
}
@@ -132,7 +132,7 @@
/**
* Increment timeout connection.
*/
- public void incTimedOut()
+ public void incTimedOutCount()
{
++timedOut;
}
Modified: projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/ConnectionManagerImpl.java
===================================================================
--- projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/ConnectionManagerImpl.java 2009-09-08 19:22:26 UTC (rev 93295)
+++ projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/ConnectionManagerImpl.java 2009-09-08 19:59:36 UTC (rev 93296)
@@ -35,16 +35,20 @@
*/
public class ConnectionManagerImpl implements ConnectionManager
{
- /** Serial version UID */
- static final long serialVersionUID = 0L;
-
+ /**Serial version UID*/
+ private static final long serialVersionUID = 2843159124540746692L;
+
+ /**Real connection manager*/
+ private transient AbstractConnectionManager realConnectionManager;
+
/**
- * Default constructor
+ * Creates a new instance of connection manager.
*/
public ConnectionManagerImpl()
{
+
}
-
+
/**
* Allocate a connection
* @param mcf The managed connection factory
@@ -56,7 +60,7 @@
ConnectionRequestInfo cxRequestInfo)
throws ResourceException
{
- throw new ResourceException("NYI");
+ return this.realConnectionManager.allocateConnection(mcf, cxRequestInfo);
}
/**
@@ -64,8 +68,7 @@
*/
public void checkTransactionActive() throws RollbackException, SystemException
{
- // TODO Auto-generated method stub
-
+ this.realConnectionManager.checkTransactionActive();
}
/**
@@ -73,8 +76,7 @@
*/
public long getTimeLeftBeforeTransactionTimeout(boolean errorRollback) throws RollbackException
{
- // TODO Auto-generated method stub
- return 0;
+ return this.realConnectionManager.getTimeLeftBeforeTransactionTimeout(errorRollback);
}
/**
@@ -82,7 +84,22 @@
*/
public int getTransactionTimeout() throws SystemException
{
- // TODO Auto-generated method stub
- return 0;
+ return this.realConnectionManager.getTransactionTimeout();
}
+
+ /**
+ * {@inheritDoc}
+ */
+ public AbstractConnectionManager getRealConnectionManager()
+ {
+ return this.realConnectionManager;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setRealConnectionManager(AbstractConnectionManager realConnectionManager)
+ {
+ this.realConnectionManager = realConnectionManager;
+ }
}
Modified: projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/ConnectionRecord.java
===================================================================
--- projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/ConnectionRecord.java 2009-09-08 19:22:26 UTC (rev 93295)
+++ projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/ConnectionRecord.java 2009-09-08 19:59:36 UTC (rev 93296)
@@ -26,7 +26,7 @@
import javax.resource.spi.ConnectionRequestInfo;
/**
- * Information about a connection
+ * Information about a connection.
*
* @author <a href="mailto:d_jencks at users.sourceforge.net">David Jencks</a>
* @author <a href="mailto:adrian at jboss.org">Adrian Brock</a>
@@ -35,7 +35,7 @@
*/
public class ConnectionRecord
{
- private ConnectionListener cl;
+ private ConnectionListener connectionListener;
private final Object connection;
private final ConnectionRequestInfo cri;
@@ -49,7 +49,7 @@
final Object connection,
final ConnectionRequestInfo cri)
{
- this.cl = cl;
+ this.connectionListener = cl;
this.connection = connection;
this.cri = cri;
}
@@ -57,23 +57,23 @@
/**
* @return the cl
*/
- ConnectionListener getCl()
+ public ConnectionListener getConnectionListener()
{
- return cl;
+ return connectionListener;
}
/**
* @param cl the cl to set
*/
- void setCl(ConnectionListener cl)
+ void setConnectionListener(ConnectionListener cl)
{
- this.cl = cl;
+ this.connectionListener = cl;
}
/**
* @return the connection
*/
- Object getConnection()
+ public Object getConnection()
{
return connection;
}
@@ -81,7 +81,7 @@
/**
* @return the cri
*/
- ConnectionRequestInfo getCri()
+ public ConnectionRequestInfo getCri()
{
return cri;
}
Added: projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/KeyConnectionAssociation.java
===================================================================
--- projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/KeyConnectionAssociation.java (rev 0)
+++ projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/KeyConnectionAssociation.java 2009-09-08 19:59:36 UTC (rev 93296)
@@ -0,0 +1,104 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008-2009, 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.jca.core.connectionmanager;
+
+import org.jboss.jca.core.connectionmanager.listener.ConnectionCacheListener;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.jboss.util.Strings;
+
+
+/**
+ * The class <code>KeyConnectionAssociation</code> wraps objects so they may be used in hashmaps
+ * based on their object identity rather than equals implementation. Used for keys.
+ *
+ * @author gurkanerdogdu
+ * @version $Rev$ $Date$
+ */
+final class KeyConnectionAssociation
+{
+ //key
+ private final Object metaAwareObject;
+
+ //map of cm to list of connections for that cm.
+ private Map<ConnectionCacheListener, Collection<ConnectionRecord>> cmToConnectionsMap;
+
+ /**
+ * Creates a new instance.
+ * @param metaAwareObject meta aware object
+ */
+ KeyConnectionAssociation(final Object metaAwareObject)
+ {
+ this.metaAwareObject = metaAwareObject;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean equals(Object other)
+ {
+ return (other instanceof KeyConnectionAssociation) &&
+ this.metaAwareObject == ((KeyConnectionAssociation) other).metaAwareObject;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String toString()
+ {
+ return Strings.defaultToString(this.metaAwareObject);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int hashCode()
+ {
+ return System.identityHashCode(this.metaAwareObject);
+ }
+
+ /**
+ * Set map instance.
+ * @param cmToConnectionsMap connection manager to connections
+ */
+ public void setCMToConnectionsMap(Map<ConnectionCacheListener, Collection<ConnectionRecord>> cmToConnectionsMap)
+ {
+ this.cmToConnectionsMap = cmToConnectionsMap;
+ }
+
+ /**
+ *
+ * @return map instance
+ */
+ public Map<ConnectionCacheListener, Collection<ConnectionRecord>> getCMToConnectionsMap()
+ {
+ if (cmToConnectionsMap == null)
+ {
+ cmToConnectionsMap = new HashMap<ConnectionCacheListener, Collection<ConnectionRecord>>();
+ }
+
+ return cmToConnectionsMap;
+ }
+}
Property changes on: projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/KeyConnectionAssociation.java
___________________________________________________________________
Name: svn:keywords
+ Rev Date
Name: svn:eol-style
+ native
Added: projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/exception/JBossLocalXAException.java
===================================================================
--- projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/exception/JBossLocalXAException.java (rev 0)
+++ projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/exception/JBossLocalXAException.java 2009-09-08 19:59:36 UTC (rev 93296)
@@ -0,0 +1,173 @@
+/*
+ * 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.jca.core.connectionmanager.exception;
+
+import java.io.PrintStream;
+import java.io.PrintWriter;
+
+import javax.transaction.xa.XAException;
+
+import org.jboss.util.NestedThrowable;
+
+/**
+ * JBossLocalXAException
+ *
+ * @author <a href="mailto:d_jencks at users.sourceforge.net">David Jencks</a>
+ * @author <a href="mailto:adrian at jboss.com">Adrian Brock</a>
+ * @version $Revision$
+ */
+public class JBossLocalXAException extends XAException implements NestedThrowable
+{
+ /**Serial version UID*/
+ private static final long serialVersionUID = -6208145503935506281L;
+
+ /**Cause*/
+ private final Throwable t;
+
+ /**
+ * Creates a new instance.
+ */
+ public JBossLocalXAException()
+ {
+ super();
+ t = null;
+ }
+
+ /**
+ * Creates a new instance.
+ * @param errcode error code
+ */
+ public JBossLocalXAException(int errcode)
+ {
+ super(errcode);
+ t = null;
+ }
+
+ /**
+ * Creates a new instance.
+ * @param message message
+ */
+ public JBossLocalXAException(String message)
+ {
+ super(message);
+ t = null;
+ }
+
+ /**
+ * Creates a new instance.
+ * @param message message
+ * @param errorcode error code
+ */
+ public JBossLocalXAException(String message, int errorcode)
+ {
+ super(message);
+ this.errorCode = errorcode;
+ t = null;
+ }
+
+ /**
+ * Creates a new instance.
+ * @param message message
+ * @param t cause
+ */
+ public JBossLocalXAException(String message, Throwable t)
+ {
+ super(message);
+ this.t = t;
+ }
+
+ /**
+ * Creates a new instance.
+ * @param message message
+ * @param t cause
+ * @param errorcode error code
+ */
+ public JBossLocalXAException(String message, int errorcode, Throwable t)
+ {
+ super(message);
+ this.errorCode = errorcode;
+ this.t = t;
+ }
+
+ // Implementation of org.jboss.util.NestedThrowable
+
+ /**
+ * {@inheritDoc}
+ */
+ public Throwable getNested()
+ {
+ return t;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Throwable getCause()
+ {
+ return t;
+ }
+
+ /**
+ * Returns the composite throwable message.
+ *
+ * @return The composite throwable message.
+ */
+ public String getMessage()
+ {
+ return NestedThrowable.Util.getMessage(super.getMessage(), t);
+ }
+
+ /**
+ * Prints the composite message and the embedded stack trace to the
+ * specified print stream.
+ *
+ * @param stream Stream to print to.
+ */
+ public void printStackTrace(final PrintStream stream)
+ {
+ if (t == null || NestedThrowable.PARENT_TRACE_ENABLED)
+ super.printStackTrace(stream);
+ NestedThrowable.Util.print(t, stream);
+ }
+
+ /**
+ * Prints the composite message and the embedded stack trace to the
+ * specified print writer.
+ *
+ * @param writer Writer to print to.
+ */
+ public void printStackTrace(final PrintWriter writer)
+ {
+ if (t == null || NestedThrowable.PARENT_TRACE_ENABLED)
+ super.printStackTrace(writer);
+ NestedThrowable.Util.print(t, writer);
+ }
+
+ /**
+ * Prints the composite message and the embedded stack trace to
+ * <tt>System.err</tt>.
+ */
+ public void printStackTrace()
+ {
+ printStackTrace(System.err);
+ }
+}
Property changes on: projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/exception/JBossLocalXAException.java
___________________________________________________________________
Name: svn:keywords
+ Rev Date
Name: svn:eol-style
+ native
Added: projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/exception/JBossLocalXAExceptionFormatter.java
===================================================================
--- projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/exception/JBossLocalXAExceptionFormatter.java (rev 0)
+++ projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/exception/JBossLocalXAExceptionFormatter.java 2009-09-08 19:59:36 UTC (rev 93296)
@@ -0,0 +1,63 @@
+/*
+ * 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.jca.core.connectionmanager.exception;
+
+import javax.transaction.xa.XAException;
+
+import org.jboss.logging.Logger;
+import org.jboss.tm.XAExceptionFormatter;
+
+/**
+ * JBossLocalXAExceptionFormatter.java
+ *
+ * @author <a href="mailto:igorfie at yahoo dot com">Igor Fedorenko</a>.
+ * @author <a href="mailto:d_jencks at users.sourceforge.net">David Jencks</a>
+ * @author <a href="mailto:adrian at jboss.com">Adrian Brock</a>
+ * @version $Revision$
+ */
+
+public class JBossLocalXAExceptionFormatter implements XAExceptionFormatter
+{
+
+ /**
+ * Creates a new formatter.
+ */
+ public JBossLocalXAExceptionFormatter()
+ {
+
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void formatXAException(XAException xae, Logger log)
+ {
+ try
+ {
+ log.warn("JBoss Local XA wrapper error: ", ((JBossLocalXAException) xae).getCause());
+ }
+ catch (Exception e)
+ {
+ log.warn("Problem trying to format XAException: ", e);
+ }
+ }
+}
Property changes on: projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/exception/JBossLocalXAExceptionFormatter.java
___________________________________________________________________
Name: svn:keywords
+ Rev Date
Name: svn:eol-style
+ native
Added: projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/listener/AbstractConnectionListener.java
===================================================================
--- projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/listener/AbstractConnectionListener.java (rev 0)
+++ projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/listener/AbstractConnectionListener.java 2009-09-08 19:59:36 UTC (rev 93296)
@@ -0,0 +1,431 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008-2009, 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.jca.core.connectionmanager.listener;
+
+import org.jboss.jca.core.connectionmanager.AbstractConnectionManager;
+import org.jboss.jca.core.connectionmanager.CachedConnectionManager;
+import org.jboss.jca.core.connectionmanager.pool.api.ManagedConnectionPool;
+
+import java.util.Iterator;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import javax.resource.ResourceException;
+import javax.resource.spi.ConnectionEvent;
+import javax.resource.spi.ManagedConnection;
+import javax.transaction.SystemException;
+
+import org.jboss.logging.Logger;
+
+/**
+ * Abstract implementation of the {@link ConnectionListener} interface
+ * contract.
+ *
+ * @author gurkanerdogdu
+ * @version $Rev$ $Date$
+ *
+ */
+public abstract class AbstractConnectionListener implements ConnectionListener
+{
+ private Logger log = Logger.getLogger(getClass());
+
+ /**Wraps managed connection instance*/
+ private final ManagedConnection managedConnection;
+
+ /**Managed connection pool for this connection*/
+ private final ManagedConnectionPool managedConnectionPool;
+
+ /**Pool internal context*/
+ private final Object internalManagedPoolContext;
+
+ /**Connection State*/
+ private ConnectionState state = ConnectionState.NORMAL;
+
+ /**Connection handles*/
+ private final CopyOnWriteArrayList<Object> connectionHandles = new CopyOnWriteArrayList<Object>();
+
+ /**Track by transaction or not*/
+ private AtomicBoolean trackByTx = new AtomicBoolean(false);
+
+ /**Connection permit*/
+ private boolean permit;
+
+ /**Connection last use*/
+ private long lastUse;
+
+ /**Connection last validated time*/
+ private long lastValidated;
+
+ /**Log trace*/
+ protected boolean trace;
+
+ /**Connection Manager*/
+ private AbstractConnectionManager cm;
+
+ /**
+ * Creates a new instance of the listener that is responsible for
+ * tracking the owned connection instance.
+ * @param managedConnection managed connection
+ * @param managedConnectionPool managed connection pool
+ * @param context pool internal context
+ * @param cm connection manager
+ */
+ protected AbstractConnectionListener(AbstractConnectionManager cm, ManagedConnection managedConnection,
+ ManagedConnectionPool managedConnectionPool, Object context)
+ {
+ this.cm = cm;
+ this.managedConnection = managedConnection;
+ this.managedConnectionPool = managedConnectionPool;
+ this.internalManagedPoolContext = context;
+ trace = this.log.isTraceEnabled();
+ lastUse = System.currentTimeMillis();
+ }
+
+ /**
+ * Gets cached connection manager
+ * @return cached connection manager
+ */
+ protected CachedConnectionManager getCachedConnectionManager()
+ {
+ return this.cm.getCachedConnectionManager();
+ }
+
+ /**
+ * Gets connection manager.
+ * @return connection manager
+ */
+ protected AbstractConnectionManager getConnectionManager()
+ {
+ return this.cm;
+ }
+
+ /**
+ * Gets logger.
+ * @return logger instance
+ */
+ protected Logger getLog()
+ {
+ return this.log;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void delist() throws ResourceException
+ {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void enlist() throws SystemException
+ {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Object getContext()
+ {
+ return this.internalManagedPoolContext;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public long getLastValidatedTime()
+ {
+ return this.lastValidated;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ManagedConnection getManagedConnection()
+ {
+ return this.managedConnection;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ManagedConnectionPool getManagedConnectionPool()
+ {
+ return this.managedConnectionPool;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ConnectionState getState()
+ {
+ return this.state;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void grantPermit(boolean value)
+ {
+ this.permit = value;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean hasPermit()
+ {
+ return this.permit;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isManagedConnectionFree()
+ {
+ return this.connectionHandles.isEmpty();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isTimedOut(long timeout)
+ {
+ return lastUse < timeout;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isTrackByTx()
+ {
+ return this.trackByTx.get();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void registerConnection(Object handle)
+ {
+ this.connectionHandles.add(handle);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setLastValidatedTime(long lastValidated)
+ {
+ this.lastValidated = lastValidated;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setState(ConnectionState newState)
+ {
+ this.state = newState;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setTrackByTx(boolean trackByTx)
+ {
+ this.trackByTx.set(trackByTx);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void tidyup() throws ResourceException
+ {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void unregisterConnection(Object handle)
+ {
+ if (!this.connectionHandles.remove(handle))
+ {
+ log.info("Unregistered handle that was not registered! " + handle + " for managedConnection: " +
+ this.managedConnection);
+ }
+
+ if (trace)
+ {
+ log.trace("unregisterConnection: " + this.connectionHandles.size() + " handles left");
+ }
+ }
+
+ /**
+ * Unregister connections.
+ */
+ protected void unregisterConnections()
+ {
+ try
+ {
+ Iterator<Object> itHandles = this.connectionHandles.iterator();
+
+ while (itHandles.hasNext())
+ {
+ Object handle = itHandles.next();
+ this.log.info("Unregister connection handle : " + handle + " from Cached connection manager");
+ //getCcm().unregisterConnection(BaseConnectionManager2.this, i.next());
+ }
+ }
+ finally
+ {
+ this.connectionHandles.clear();
+ }
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public void used()
+ {
+ this.lastUse = System.currentTimeMillis();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void connectionClosed(ConnectionEvent event)
+ {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void connectionErrorOccurred(ConnectionEvent event)
+ {
+ if (state == ConnectionState.NORMAL)
+ {
+ if (event != null)
+ {
+ Throwable cause = event.getException();
+ if (cause == null)
+ {
+ cause = new Exception("No exception was reported");
+ }
+
+ log.warn("Connection error occured: " + this, cause);
+ }
+ else
+ {
+ Throwable cause = new Exception("No exception was reported");
+ log.warn("Unknown Connection error occured: " + this, cause);
+ }
+ }
+
+ try
+ {
+ unregisterConnections();
+ }
+ catch (Throwable t)
+ {
+ //ignore, it wasn't checked out.
+ }
+
+ if (event != null && event.getSource() != getManagedConnection())
+ {
+ log.warn("Notified of error on a different managed connection?");
+ }
+
+ getConnectionManager().returnManagedConnection(this, true);
+
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public void localTransactionCommitted(ConnectionEvent event)
+ {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void localTransactionRolledback(ConnectionEvent event)
+ {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void localTransactionStarted(ConnectionEvent event)
+ {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ // For debugging
+ public String toString()
+ {
+ StringBuffer buffer = new StringBuffer(100);
+ buffer.append(getClass().getName()).append('@').append(Integer.toHexString(System.identityHashCode(this)));
+ buffer.append("[state=");
+
+ if (state.equals(ConnectionState.NORMAL))
+ {
+ buffer.append("NORMAL");
+ }
+ else if (state.equals(ConnectionState.DESTROY))
+ {
+ buffer.append("DESTROY");
+ }
+ else if (state.equals(ConnectionState.DESTROYED))
+ {
+ buffer.append("DESTROYED");
+ }
+ else
+ {
+ buffer.append("UNKNOWN?");
+ }
+ buffer.append(" managed connection=").append(this.managedConnection);
+ buffer.append(" connection handles=").append(this.connectionHandles.size());
+ buffer.append(" lastUse=").append(lastUse);
+ buffer.append(" permit=").append(permit);
+ buffer.append(" trackByTx=").append(trackByTx.get());
+ buffer.append(" managed connection pool=").append(this.managedConnectionPool);
+ buffer.append(" pool internal context=").append(this.internalManagedPoolContext);
+ toString(buffer);
+ buffer.append(']');
+
+ return buffer.toString();
+ }
+
+ /**
+ * Add specific properties.
+ * @param buffer buffer instance
+ */
+ // For debugging
+ protected void toString(StringBuffer buffer)
+ {
+
+ }
+
+}
Property changes on: projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/listener/AbstractConnectionListener.java
___________________________________________________________________
Name: svn:eol-style
+ native
Modified: projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/listener/ConnectionListener.java
===================================================================
--- projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/listener/ConnectionListener.java 2009-09-08 19:22:26 UTC (rev 93295)
+++ projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/listener/ConnectionListener.java 2009-09-08 19:59:36 UTC (rev 93296)
@@ -169,9 +169,9 @@
/**
* Set the last time, in milliseconds, that this connection was validated.
*
- * @param interval the last time the connection was validated in
+ * @param lastValidated the last time the connection was validated in
* milliseconds.
*/
- void setLastValidatedTime(long interval);
+ void setLastValidatedTime(long lastValidated);
}
Added: projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/listener/NoTxConnectionListener.java
===================================================================
--- projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/listener/NoTxConnectionListener.java (rev 0)
+++ projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/listener/NoTxConnectionListener.java 2009-09-08 19:59:36 UTC (rev 93296)
@@ -0,0 +1,75 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008-2009, 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.jca.core.connectionmanager.listener;
+
+import org.jboss.jca.core.connectionmanager.AbstractConnectionManager;
+import org.jboss.jca.core.connectionmanager.pool.api.ManagedConnectionPool;
+
+import javax.resource.spi.ConnectionEvent;
+import javax.resource.spi.ManagedConnection;
+
+
+/**
+ * NoTx Connection Listener.
+ *
+ * @author <a href="mailto:gurkanerdogdu at yahoo.com">Gurkan Erdogdu</a>
+ * @version $Rev$ $Date$
+ * @see AbstractConnectionListener
+ */
+public class NoTxConnectionListener extends AbstractConnectionListener
+{
+ /**
+ * Creates a new no-tx listener.
+ * @param cm connection manager
+ * @param mc managed connection
+ * @param mcp managed connection pool
+ * @param context context
+ */
+ public NoTxConnectionListener(final AbstractConnectionManager cm, final ManagedConnection mc,
+ final ManagedConnectionPool mcp, final Object context)
+ {
+ super(cm, mc, mcp, context);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void connectionClosed(ConnectionEvent ce)
+ {
+ try
+ {
+ getCachedConnectionManager().unregisterConnection(getConnectionManager(), ce.getConnectionHandle());
+ }
+ catch (Throwable t)
+ {
+ getLog().info("Throwable from unregisterConnection", t);
+ }
+
+ getConnectionManager().unregisterAssociation(this, ce.getConnectionHandle());
+
+ if (isManagedConnectionFree())
+ {
+ getConnectionManager().returnManagedConnection(this, false);
+ }
+ }
+
+}
Property changes on: projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/listener/NoTxConnectionListener.java
___________________________________________________________________
Name: svn:keywords
+ Rev Date
Name: svn:eol-style
+ native
Added: projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/listener/TxConnectionListener.java
===================================================================
--- projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/listener/TxConnectionListener.java (rev 0)
+++ projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/listener/TxConnectionListener.java 2009-09-08 19:59:36 UTC (rev 93296)
@@ -0,0 +1,656 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008-2009, 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.jca.core.connectionmanager.listener;
+
+import org.jboss.jca.common.api.JBossResourceException;
+import org.jboss.jca.core.connectionmanager.AbstractConnectionManager;
+import org.jboss.jca.core.connectionmanager.pool.api.ManagedConnectionPool;
+import org.jboss.jca.core.connectionmanager.transaction.TransactionSynchronizer;
+import org.jboss.jca.core.connectionmanager.tx.TxConnectionManager;
+import org.jboss.jca.core.connectionmanager.xa.LocalXAResource;
+
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import javax.resource.ResourceException;
+import javax.resource.spi.ConnectionEvent;
+import javax.resource.spi.LocalTransaction;
+import javax.resource.spi.ManagedConnection;
+import javax.transaction.Status;
+import javax.transaction.Synchronization;
+import javax.transaction.SystemException;
+import javax.transaction.Transaction;
+import javax.transaction.TransactionManager;
+import javax.transaction.xa.XAResource;
+
+import org.jboss.tm.TxUtils;
+
+
+/**
+ * Tx connection listener.
+ * @author <a href="mailto:gurkanerdogdu at yahoo.com">Gurkan Erdogdu</a>
+ * @version $Rev$ $Date$
+ *
+ */
+public class TxConnectionListener extends AbstractConnectionListener
+{
+
+ /**Transaction synch. instance*/
+ private TransactionSynchronization transactionSynchronization;
+
+ /**XAResource instance*/
+ private final XAResource xaResource;
+
+ /** Whether there is a local transaction */
+ private AtomicBoolean localTransaction = new AtomicBoolean(false);
+
+ /**
+ * Creates a new tx listener.
+ * @param cm connection manager
+ * @param mc managed connection
+ * @param mcp managed connection pool
+ * @param context context
+ * @param xaResource xaresource instance
+ * @throws ResourceException if aexception while creating
+ */
+ public TxConnectionListener(final AbstractConnectionManager cm, final ManagedConnection mc,
+ final ManagedConnectionPool mcp, final Object context, final XAResource xaResource)
+ throws ResourceException
+ {
+ super(cm, mc, mcp, context);
+
+ this.xaResource = xaResource;
+
+ if (xaResource instanceof LocalXAResource)
+ {
+ ((LocalXAResource) xaResource).setConnectionListener(this);
+ }
+
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void enlist() throws SystemException
+ {
+ // This method is a bit convulted, but it has to be such because
+ // there is a race condition in the transaction manager where it
+ // unlocks during the enlist of the XAResource. It does this
+ // to avoid distributed deadlocks and to ensure the transaction
+ // timeout can fail a badly behaving resource during the enlist.
+ //
+ // When two threads in the same transaction are trying to enlist
+ // connections they could be from the same resource manager
+ // or even the same connection when tracking the connection by transaction.
+ //
+ // For the same connection, we only want to do the real enlist once.
+ // For two connections from the same resource manager we don't
+ // want the join before the initial start request.
+ //
+ // The solution is to build up a list of unenlisted resources
+ // in the TransactionSynchronizer and then choose one of the
+ // threads that is contending in the transaction to enlist them
+ // in order. The actual order doesn't really matter as it is the
+ // transaction manager that calculates the enlist flags and determines
+ // whether the XAResource was already enlisted.
+ //
+ // Once there are no unenlisted resources the threads are released
+ // to return the result of the enlistments.
+ //
+ // In practice, a thread just takes a snapshot to try to avoid one
+ // thread having to do all the work. If it did not do them all
+ // the next waiting thread will do the next snapshot until there
+ // there is either no snapshot or no waiting threads.
+ //
+ // A downside to this design is a thread could have its resource enlisted by
+ // an earlier thread while it enlists some later thread's resource.
+ // Since they are all a part of the same transaction, this is probably
+ // not a real issue.
+
+ // No transaction associated with the thread
+ TransactionManager tm = getConnectionManager().getTransactionManagerInstance();
+ int status = tm.getStatus();
+ if (status == Status.STATUS_NO_TRANSACTION)
+ {
+ if (transactionSynchronization != null && transactionSynchronization.currentTx != null)
+ {
+ String error = "Attempt to use connection outside a transaction when already a tx!";
+ if (trace)
+ {
+ getLog().trace(error + " " + this);
+ }
+
+ throw new IllegalStateException(error);
+ }
+ if (trace)
+ {
+ getLog().trace("No transaction, no need to enlist: " + this);
+ }
+
+ return;
+ }
+
+ // Inactive transaction
+ Transaction threadTx = tm.getTransaction();
+ if (threadTx == null || status != Status.STATUS_ACTIVE)
+ {
+ String error = "Transaction " + threadTx + " is not active " + TxUtils.getStatusAsString(status);
+ if (trace)
+ {
+ getLog().trace(error + " cl=" + this);
+ }
+
+ throw new IllegalStateException(error);
+ }
+
+ if (trace)
+ {
+ getLog().trace("Pre-enlist: " + this + " threadTx=" + threadTx);
+ }
+
+ // Our synchronization
+ TransactionSynchronization ourSynchronization = null;
+
+ // Serializes enlistment when two different threads are enlisting
+ // different connections in the same transaction concurrently
+ TransactionSynchronizer synchronizer = null;
+
+ TransactionSynchronizer.lock(threadTx);
+ try
+ {
+ // Interleaving should have an unenlisted transaction
+ // TODO We should be able to do some sharing shouldn't we?
+ if (!isTrackByTx() && transactionSynchronization != null)
+ {
+ String error = "Can't enlist - already a tx!";
+ if (trace)
+ {
+ getLog().trace(error + " " + this);
+ }
+ throw new IllegalStateException(error);
+ }
+
+ // Check for different transaction
+ if (transactionSynchronization != null && !transactionSynchronization.currentTx.equals(threadTx))
+ {
+ String error = "Trying to change transaction " + threadTx + " in enlist!";
+ if (trace)
+ {
+ getLog().trace(error + " " + this);
+ }
+ throw new IllegalStateException(error);
+ }
+
+ // Get the synchronizer
+ try
+ {
+ if (this.trace)
+ {
+ getLog().trace("Get synchronizer " + this + " threadTx=" + threadTx);
+ }
+
+ synchronizer = TransactionSynchronizer.getRegisteredSynchronizer(threadTx);
+ }
+ catch (Throwable t)
+ {
+ setTrackByTx(false);
+ TxConnectionManager.rethrowAsSystemException("Cannot register synchronization", threadTx, t);
+ }
+
+ // First time through, create a transaction synchronization
+ if (transactionSynchronization == null)
+ {
+ TransactionSynchronization synchronization = new TransactionSynchronization(threadTx, isTrackByTx());
+ synchronizer.addUnenlisted(synchronization);
+ transactionSynchronization = synchronization;
+ }
+
+ ourSynchronization = transactionSynchronization;
+ }
+ finally
+ {
+ TransactionSynchronizer.unlock(threadTx);
+ }
+
+ // Perform the enlistment(s)
+ CopyOnWriteArrayList<Synchronization> unenlisted = synchronizer.getUnenlisted();
+ if (unenlisted != null)
+ {
+ try
+ {
+ for (int i = 0; i < unenlisted.size(); ++i)
+ {
+ TransactionSynchronization sync = (TransactionSynchronization) unenlisted.get(i);
+ if (sync.enlist())
+ {
+ synchronizer.addEnlisted(sync);
+ }
+ }
+ }
+ finally
+ {
+ synchronizer.enlisted();
+ }
+ }
+
+ // What was the result of our enlistment?
+ if (this.trace)
+ {
+ getLog().trace("Check enlisted " + this + " threadTx=" + threadTx);
+ }
+
+ ourSynchronization.checkEnlisted();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void delist() throws ResourceException
+ {
+ if (trace)
+ getLog().trace("delisting " + this);
+
+ try
+ {
+ if (!isTrackByTx() && transactionSynchronization != null)
+ {
+ Transaction tx = transactionSynchronization.currentTx;
+ TransactionSynchronization synchronization = transactionSynchronization;
+ transactionSynchronization = null;
+ if (TxUtils.isUncommitted(tx))
+ {
+ TransactionSynchronizer synchronizer = TransactionSynchronizer.getRegisteredSynchronizer(tx);
+ if (synchronization.enlisted)
+ synchronizer.removeEnlisted(synchronization);
+ if (!tx.delistResource(getXAResource(), XAResource.TMSUSPEND))
+ {
+ throw new ResourceException("Failure to delist resource: " + this);
+ }
+ }
+ }
+ }
+ catch (Throwable t)
+ {
+ JBossResourceException.rethrowAsResourceException("Error in delist!", t);
+ }
+ }
+
+ //local will return this, xa will return one from mc.
+ /**
+ * Get XA resource.
+ * @return xa resource
+ */
+ protected XAResource getXAResource()
+ {
+ return xaResource;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void connectionClosed(ConnectionEvent ce)
+ {
+ if (trace)
+ getLog().trace("connectionClosed called mc=" + this.getManagedConnection());
+ if (this.getManagedConnection() != (ManagedConnection)ce.getSource())
+ throw new IllegalArgumentException("ConnectionClosed event received from wrong ManagedConnection! Expected: " +
+ this.getManagedConnection() + ", actual: " + ce.getSource());
+ try
+ {
+ this.getCachedConnectionManager().unregisterConnection(this.getConnectionManager(), ce.getConnectionHandle());
+ }
+ catch (Throwable t)
+ {
+ getLog().info("throwable from unregister connection", t);
+ }
+
+ try
+ {
+ if (wasFreed(ce.getConnectionHandle()))
+ {
+ delist();
+ if (trace)
+ getLog().trace("isManagedConnectionFree=true mc=" + this.getManagedConnection());
+ this.getConnectionManager().returnManagedConnection(this, false);
+ }
+ else
+ {
+ if (trace)
+ getLog().trace("isManagedConnectionFree=false mc=" + this.getManagedConnection());
+ }
+ }
+ catch (Throwable t)
+ {
+ getLog().error("Error while closing connection handle!", t);
+ this.getConnectionManager().returnManagedConnection(this, true);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void localTransactionStarted(ConnectionEvent ce)
+ {
+ localTransaction.set(true);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void localTransactionCommitted(ConnectionEvent ce)
+ {
+ localTransaction.set(false);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void localTransactionRolledback(ConnectionEvent ce)
+ {
+ localTransaction.set(false);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void tidyup() throws ResourceException
+ {
+ // We have a hanging transaction
+ if (localTransaction.get())
+ {
+ LocalTransaction local = null;
+ ManagedConnection mc = getManagedConnection();
+ try
+ {
+ local = mc.getLocalTransaction();
+ }
+ catch (Throwable t)
+ {
+ JBossResourceException.rethrowAsResourceException("Unfinished local transaction - " +
+ "error getting local transaction from " + this, t);
+ }
+ if (local == null)
+ throw new ResourceException("Unfinished local transaction but managed connection does not " +
+ "provide a local transaction. " + this);
+ else
+ {
+ local.rollback();
+ getLog().debug("Unfinished local transaction was rolled back." + this);
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void connectionErrorOccurred(ConnectionEvent ce)
+ {
+ transactionSynchronization = null;
+ super.connectionErrorOccurred(ce);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ //Important method!!
+ public boolean isManagedConnectionFree()
+ {
+ if (isTrackByTx() && transactionSynchronization != null)
+ return false;
+ return super.isManagedConnectionFree();
+ }
+
+ /**
+ * This method changes the number of handles or
+ * the track-by-tx value depending on the parameter passed in
+ * @param handle The handle; if <code>null</code> track-by-tx is changed
+ * @return True if the managed connection was freed
+ */
+ synchronized boolean wasFreed(Object handle)
+ {
+ if (handle != null)
+ {
+ if (isManagedConnectionFree())
+ {
+ // This shouldn't really happen now all the state is changed atomically
+ return false;
+ }
+
+ // Change the number of handles
+ getConnectionManager().unregisterAssociation(this, handle);
+ }
+ else
+ {
+ if (!isTrackByTx())
+ {
+ // Only change the state once
+ return false;
+ }
+
+ // Set track-by-tx to false
+ setTrackByTx(false);
+ }
+
+ // Return if the managed connection was just freed
+ return isManagedConnectionFree();
+ }
+
+
+ /**
+ * Transaction sync. class.
+ */
+ private class TransactionSynchronization implements Synchronization
+ {
+ /**Error message*/
+ private final Throwable failedToEnlist =
+ new Throwable("Unabled to enlist resource, see the previous warnings.");
+
+ /** Transaction */
+ private Transaction currentTx;
+
+ /** This is the status when we were registered */
+ private boolean wasTrackByTx;
+
+ /** Whether we are enlisted */
+ private boolean enlisted = false;
+
+ /** Any error during enlistment */
+ private Throwable enlistError;
+
+ /**
+ * Create a new TransactionSynchronization.
+ *
+ * @param trackByTx whether this is track by connection
+ */
+ public TransactionSynchronization(Transaction tx, boolean trackByTx)
+ {
+ this.currentTx = tx;
+ this.wasTrackByTx = trackByTx;
+ }
+
+ /**
+ * Get the result of the enlistment.
+ *
+ * @throws SystemExeption for any error
+ */
+ public void checkEnlisted() throws SystemException
+ {
+ if (this.enlistError != null)
+ {
+ String error = "Error enlisting resource in transaction=" + this.currentTx;
+ if (TxConnectionListener.this.trace)
+ {
+ TxConnectionListener.this.getLog().trace(error + " " + TxConnectionListener.this);
+ }
+
+ // Wrap the error to give a reasonable stacktrace since the resource
+ // could have been enlisted by a different thread
+ if (enlistError == failedToEnlist)
+ {
+ throw new SystemException(failedToEnlist + " tx=" + this.currentTx);
+ }
+ else
+ {
+ SystemException e = new SystemException(error);
+ e.initCause(enlistError);
+ throw e;
+ }
+ }
+ if (!enlisted)
+ {
+ String error = "Resource is not enlisted in transaction=" + currentTx;
+ if (trace)
+ {
+ getLog().trace(error + " " + TxConnectionListener.this);
+ }
+ throw new IllegalStateException("Resource was not enlisted.");
+ }
+ }
+
+ /**
+ * Enlist the resource
+ *
+ * @return true when enlisted, false otherwise
+ */
+ public boolean enlist()
+ {
+ if (TxConnectionListener.this.trace)
+ {
+ TxConnectionListener.this.getLog().trace("Enlisting resource " + TxConnectionListener.this);
+ }
+ try
+ {
+ XAResource resource = getXAResource();
+ if (!currentTx.enlistResource(resource))
+ {
+ enlistError = failedToEnlist;
+ }
+ }
+ catch (Throwable t)
+ {
+ enlistError = t;
+ }
+
+ synchronized (this)
+ {
+ if (enlistError != null)
+ {
+ if (trace)
+ {
+ getLog().trace("Failed to enlist resource " + TxConnectionListener.this, enlistError);
+ }
+
+ setTrackByTx(false);
+ transactionSynchronization = null;
+
+ return false;
+ }
+
+ if (trace)
+ {
+ getLog().trace("Enlisted resource " + TxConnectionListener.this);
+ }
+
+ enlisted = true;
+ return true;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void beforeCompletion()
+ {
+ //No-op
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void afterCompletion(int status)
+ {
+ // The connection got destroyed during the transaction
+ if (getState().equals(ConnectionState.DESTROYED))
+ {
+ return;
+ }
+
+ // Are we still in the original transaction?
+ if (!this.equals(transactionSynchronization))
+ {
+ // If we are interleaving transactions we have nothing to do
+ if (!wasTrackByTx)
+ {
+ return;
+ }
+ else
+ {
+ // There is something wrong with the pooling
+ String message = "afterCompletion called with wrong tx! Expected: " +
+ this + ", actual: " + transactionSynchronization;
+ IllegalStateException e = new IllegalStateException(message);
+ getLog().error("There is something wrong with the pooling?", e);
+ }
+ }
+ // "Delist"
+ transactionSynchronization = null;
+ // This is where we close when doing track by transaction
+ if (wasTrackByTx)
+ {
+ if (trace)
+ {
+ getLog().trace("afterCompletion(" + status + ") isTrackByTx=" + isTrackByTx() +
+ " for " + TxConnectionListener.this);
+ }
+
+ if (wasFreed(null))
+ {
+ getConnectionManager().returnManagedConnection(TxConnectionListener.this, false);
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String toString()
+ {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append("TxSync").append(System.identityHashCode(this));
+ buffer.append("{tx=").append(currentTx);
+ buffer.append(" wasTrackByTx=").append(wasTrackByTx);
+ buffer.append(" enlisted=").append(enlisted);
+ buffer.append("}");
+ return buffer.toString();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ // For debugging
+ protected void toString(StringBuffer buffer)
+ {
+ buffer.append(" xaResource=").append(xaResource);
+ buffer.append(" txSync=").append(transactionSynchronization);
+ }
+}
Property changes on: projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/listener/TxConnectionListener.java
___________________________________________________________________
Name: svn:keywords
+ Rev Date
Name: svn:eol-style
+ native
Modified: projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/notx/NoTxConnectionManager.java
===================================================================
--- projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/notx/NoTxConnectionManager.java 2009-09-08 19:22:26 UTC (rev 93295)
+++ projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/notx/NoTxConnectionManager.java 2009-09-08 19:59:36 UTC (rev 93296)
@@ -22,6 +22,14 @@
package org.jboss.jca.core.connectionmanager.notx;
+import org.jboss.jca.core.connectionmanager.AbstractConnectionManager;
+import org.jboss.jca.core.connectionmanager.listener.ConnectionListener;
+import org.jboss.jca.core.connectionmanager.listener.NoTxConnectionListener;
+
+
+import javax.resource.ResourceException;
+import javax.resource.spi.ManagedConnection;
+
/**
* Non transactional connection manager implementation.
*
@@ -29,7 +37,27 @@
* @version $Rev$ $Date$
*
*/
-public class NoTxConnectionManager
+public class NoTxConnectionManager extends AbstractConnectionManager
{
+ /**
+ * Default constructor.
+ */
+ public NoTxConnectionManager()
+ {
+
+ }
+ /**
+ * {@inheritDoc}
+ */
+ public ConnectionListener createConnectionListener(ManagedConnection managedConnection, Object context)
+ throws ResourceException
+ {
+ ConnectionListener cli = new NoTxConnectionListener(this, managedConnection, getPoolingStrategy(), context);
+ managedConnection.addConnectionEventListener(cli);
+
+ return cli;
+
+ }
+
}
Property changes on: projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/notx/NoTxConnectionManager.java
___________________________________________________________________
Name: svn:keywords
+ Rev Date
Modified: projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/AbstractPool.java
===================================================================
--- projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/AbstractPool.java 2009-09-08 19:22:26 UTC (rev 93295)
+++ projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/AbstractPool.java 2009-09-08 19:59:36 UTC (rev 93296)
@@ -266,7 +266,7 @@
if (trackByTransaction == null || trackByTx == null)
{
- cl = getSimpleConnection(subject, cri, separateNoTx);
+ cl = getSimpleConnection(subject, cri, subPoolContext);
} //end of if trackByTransaction
//Transaction old connections
@@ -292,27 +292,21 @@
* @return connection listener
* @throws ResourceException
*/
- private ConnectionListener getSimpleConnection(Subject subject, ConnectionRequestInfo cri, boolean separateNoTx)
+ private ConnectionListener getSimpleConnection(final Subject subject, final ConnectionRequestInfo cri,
+ final SubPoolContext subPoolContext)
throws ResourceException
{
ConnectionListener cl = null;
- SubPoolContext subPoolContext = null;
- Object key = null;
InternalManagedConnectionPool imcp = null;
try
{
- //Find key for pool
- key = getKey(subject, cri, separateNoTx);
-
- //Get pool context from key
- subPoolContext = getSubPool(key, subject, cri);
-
//Find internal managed pool
imcp = subPoolContext.getSubPool();
//Get connection from imcp
cl = imcp.getConnection(subject, cri);
+
if (this.traceEnabled)
{
dump("Got connection from pool : " + cl);
@@ -329,7 +323,6 @@
}
// The IMCP is down - retry
- subPoolContext = getSubPool(key, subject, cri);
imcp = subPoolContext.getSubPool();
// Make sure that IMCP is running
Property changes on: projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/AbstractPool.java
___________________________________________________________________
Name: svn:keywords
+ Rev Date
Modified: projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/InternalManagedConnectionPool.java
===================================================================
--- projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/InternalManagedConnectionPool.java 2009-09-08 19:22:26 UTC (rev 93295)
+++ projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/InternalManagedConnectionPool.java 2009-09-08 19:59:36 UTC (rev 93296)
@@ -452,7 +452,7 @@
ConnectionListener cl = (ConnectionListener) cls.get(0);
if (cl.isTimedOut(timeout) && shouldRemove())
{
- connectionCounter.incTimedOut();
+ connectionCounter.incTimedOutCount();
// We need to destroy this one
cls.remove(0);
if (destroy == null)
@@ -687,9 +687,9 @@
* Gets timed out.
* @return timed out
*/
- public int getTimedOut()
+ public int getTimedOutCount()
{
- return this.connectionCounter.getTimedOut();
+ return this.connectionCounter.getTimedOutCount();
}
/**
Added: projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/transaction/TransactionSynchronizer.java
===================================================================
--- projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/transaction/TransactionSynchronizer.java (rev 0)
+++ projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/transaction/TransactionSynchronizer.java 2009-09-08 19:59:36 UTC (rev 93296)
@@ -0,0 +1,335 @@
+/*
+ * 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.jca.core.connectionmanager.transaction;
+
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import javax.transaction.RollbackException;
+import javax.transaction.Synchronization;
+import javax.transaction.SystemException;
+import javax.transaction.Transaction;
+import javax.transaction.TransactionManager;
+
+import org.jboss.logging.Logger;
+import org.jboss.tm.TransactionLocal;
+import org.jboss.util.NestedRuntimeException;
+
+/**
+ * Organizes transaction synchronization done by JCA.
+ *
+ * <p>
+ * This class exists to make sure all Tx synchronizations
+ * are invoked before the cached connection manager closes any
+ * closed connections.
+ *
+ * @author <a href="mailto:adrian at jboss.org">Adrian Brock</a>
+ * @author gurkanerdogdu
+ * @version $Rev$ $Date$
+ */
+public class TransactionSynchronizer implements Synchronization
+{
+ /** The logger */
+ private static Logger log = Logger.getLogger(TransactionSynchronizer.class);
+
+ /** The transaction synchronizations */
+ private static TransactionLocal txSynchs;
+
+ /** The transaction */
+ private Transaction tx;
+
+ /** The enlisting thread */
+ private Thread enlistingThread;
+
+ /** Unenlisted */
+ private CopyOnWriteArrayList<Synchronization> unenlisted;
+
+ /** Enlisted */
+ private CopyOnWriteArrayList<Synchronization> enlisted;
+
+ /** The cached connection manager synchronization */
+ private Synchronization ccmSynch;
+
+ /**
+ * Initialization.
+ * @param tm transaction manager
+ */
+ public static void setTransactionManager(TransactionManager tm)
+ {
+ txSynchs = new TransactionLocal(tm);
+ }
+
+ /**
+ * Create a new transaction synchronizer
+ *
+ * @param tx the transaction to synchronize with
+ */
+ private TransactionSynchronizer(Transaction tx)
+ {
+ this.tx = tx;
+ }
+
+ /**
+ * Add a new Tx synchronization that has not been enlisted
+ *
+ * @param synch the synchronization
+ */
+ public void addUnenlisted(Synchronization synch)
+ {
+ unenlisted.add(synch);
+ }
+
+ /**
+ * Get the unenlisted synchronizations
+ * and say we are enlisting if some are returned.
+ *
+ * @return the unenlisted synchronizations
+ */
+ public CopyOnWriteArrayList<Synchronization> getUnenlisted()
+ {
+ Thread currentThread = Thread.currentThread();
+ while (enlistingThread != null && enlistingThread != currentThread)
+ {
+ boolean interrupted = false;
+ try
+ {
+ wait();
+ }
+ catch (InterruptedException e)
+ {
+ interrupted = true;
+ }
+
+ if (interrupted)
+ {
+ currentThread.interrupt();
+ }
+ }
+ CopyOnWriteArrayList<Synchronization> result = unenlisted;
+
+ unenlisted = null;
+
+ if (result != null)
+ {
+ enlistingThread = currentThread;
+ }
+ return result;
+ }
+
+ /**
+ * The synchronization is now enlisted
+ *
+ * @param synch the synchronization
+ */
+ public void addEnlisted(Synchronization synch)
+ {
+ enlisted.add(synch);
+ }
+
+ /**
+ * Remove an enlisted synchronization
+ *
+ * @param synch the synchronization
+ * @return true when the synchronization was enlisted
+ */
+ public boolean removeEnlisted(Synchronization synch)
+ {
+ return enlisted.remove(synch);
+ }
+
+ /**
+ * This thread has finished enlisting.
+ */
+ public void enlisted()
+ {
+ Thread currentThread = Thread.currentThread();
+ if (enlistingThread == null || enlistingThread != currentThread)
+ {
+ log.warn("Thread " + currentThread + " not the enlisting thread " +
+ enlistingThread, new Exception("STACKTRACE"));
+
+ return;
+ }
+
+ enlistingThread = null;
+ notifyAll();
+ }
+
+ /**
+ * Get a registered transaction synchronizer.
+ *
+ * @param tx the transaction
+ * @throws SystemException sys. exception
+ * @throws RollbackException rollback exception
+ * @return the registered transaction synchronizer for this transaction
+ */
+ public static TransactionSynchronizer getRegisteredSynchronizer(Transaction tx)
+ throws SystemException, RollbackException
+ {
+ TransactionSynchronizer result = (TransactionSynchronizer) txSynchs.get(tx);
+ if (result == null)
+ {
+ result = new TransactionSynchronizer(tx);
+ tx.registerSynchronization(result);
+ txSynchs.set(tx, result);
+ }
+ return result;
+ }
+
+ /**
+ * Check whether we have a CCM synchronization
+ *
+ * @param tx the transaction
+ * @return synch
+ */
+ public static Synchronization getCCMSynchronization(Transaction tx)
+ {
+ TransactionSynchronizer ts = (TransactionSynchronizer) txSynchs.get(tx);
+ if (ts != null)
+ {
+ return ts.ccmSynch;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Register a new CCM synchronization
+ *
+ * @param tx the transaction
+ * @param synch the synchronization
+ * @throws Exception e
+ */
+ public static void registerCCMSynchronization(Transaction tx, Synchronization synch)
+ throws Exception
+ {
+ TransactionSynchronizer ts = getRegisteredSynchronizer(tx);
+ ts.ccmSynch = synch;
+ }
+
+ /**
+ * Lock for the given transaction
+ *
+ * @param tx the transaction
+ */
+ public static void lock(Transaction tx)
+ {
+ try
+ {
+ txSynchs.lock(tx);
+ }
+ catch (InterruptedException e)
+ {
+ throw new NestedRuntimeException("Unable to get synchronization", e);
+ }
+ }
+
+ /**
+ * Unlock for the given transaction
+ *
+ * @param tx the transaction
+ */
+ public static void unlock(Transaction tx)
+ {
+ txSynchs.unlock(tx);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void beforeCompletion()
+ {
+ if (enlisted != null)
+ {
+ int i = 0;
+ while (i < enlisted.size())
+ {
+ Synchronization synch = enlisted.get(i);
+ invokeBefore(synch);
+ ++i;
+ }
+ }
+
+ if (ccmSynch != null)
+ {
+ invokeBefore(ccmSynch);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void afterCompletion(int status)
+ {
+ if (enlisted != null)
+ {
+ int i = 0;
+ while (i < enlisted.size())
+ {
+ Synchronization synch = enlisted.get(i);
+ invokeAfter(synch, status);
+ ++i;
+ }
+ }
+
+ if (ccmSynch != null)
+ {
+ invokeAfter(ccmSynch, status);
+ }
+ }
+
+ /**
+ * Invoke a beforeCompletion
+ *
+ * @param synch the synchronization
+ */
+ protected void invokeBefore(Synchronization synch)
+ {
+ try
+ {
+ synch.beforeCompletion();
+ }
+ catch (Throwable t)
+ {
+ log.warn("Transaction " + tx + " error in before completion " + synch, t);
+ }
+ }
+
+ /**
+ * Invoke an afterCompletion
+ *
+ * @param synch the synchronization
+ * @param status the status of the transaction
+ */
+ protected void invokeAfter(Synchronization synch, int status)
+ {
+ try
+ {
+ synch.afterCompletion(status);
+ }
+ catch (Throwable t)
+ {
+ log.warn("Transaction " + tx + " error in after completion " + synch, t);
+ }
+ }
+}
Property changes on: projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/transaction/TransactionSynchronizer.java
___________________________________________________________________
Name: svn:keywords
+ Rev Date
Name: svn:eol-style
+ native
Modified: projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/tx/TxConnectionManager.java
===================================================================
--- projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/tx/TxConnectionManager.java 2009-09-08 19:22:26 UTC (rev 93295)
+++ projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/tx/TxConnectionManager.java 2009-09-08 19:59:36 UTC (rev 93296)
@@ -1,6 +1,6 @@
/*
* JBoss, Home of Professional Open Source.
- * Copyright 2008-2009, Red Hat Middleware LLC, and individual contributors
+ * 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.
*
@@ -19,17 +19,517 @@
* 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.jca.core.connectionmanager.tx;
+import org.jboss.jca.common.api.JBossResourceException;
+import org.jboss.jca.core.connectionmanager.AbstractConnectionManager;
+import org.jboss.jca.core.connectionmanager.ConnectionRecord;
+import org.jboss.jca.core.connectionmanager.listener.ConnectionListener;
+import org.jboss.jca.core.connectionmanager.listener.TxConnectionListener;
+import org.jboss.jca.core.connectionmanager.xa.LocalXAResource;
+import org.jboss.jca.core.connectionmanager.xa.XAResourceWrapperImpl;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import javax.resource.ResourceException;
+import javax.resource.spi.ConnectionRequestInfo;
+import javax.resource.spi.ManagedConnection;
+import javax.security.auth.Subject;
+import javax.transaction.RollbackException;
+import javax.transaction.Status;
+import javax.transaction.SystemException;
+import javax.transaction.Transaction;
+import javax.transaction.TransactionManager;
+import javax.transaction.xa.XAException;
+import javax.transaction.xa.XAResource;
+
+import org.jboss.tm.TransactionTimeoutConfiguration;
+import org.jboss.tm.TxUtils;
+import org.jboss.util.NestedRuntimeException;
+
/**
- * Transactional connection manager implementation.
+ * The TxConnectionManager is a JBoss ConnectionManager
+ * implementation for jca adapters implementing LocalTransaction and XAResource support.
*
- * @author <a href="mailto:gurkanerdogdu at yahoo.com">Gurkan Erdogdu</a>
- * @version $Rev$ $Date$
+ * It implements a ConnectionEventListener that implements XAResource to
+ * manage transactions through the Transaction Manager. To assure that all
+ * work in a local transaction occurs over the same ManagedConnection, it
+ * includes a xid to ManagedConnection map. When a Connection is requested
+ * or a transaction started with a connection handle in use, it checks to
+ * see if a ManagedConnection already exists enrolled in the global
+ * transaction and uses it if found. Otherwise a free ManagedConnection
+ * has its LocalTransaction started and is used. From the
+ * BaseConnectionManager2, it includes functionality to obtain managed
+ * connections from
+ * a ManagedConnectionPool mbean, find the Subject from a SubjectSecurityDomain,
+ * and interact with the CachedConnectionManager for connections held over
+ * transaction and method boundaries. Important mbean references are to a
+ * ManagedConnectionPool supplier (typically a JBossManagedConnectionPool), and a
+ * RARDeployment representing the ManagedConnectionFactory.
*
+ * This connection manager has to perform the following operations:
+ *
+ * 1. When an application component requests a new ConnectionHandle,
+ * it must find a ManagedConnection, and make sure a
+ * ConnectionEventListener is registered. It must inform the
+ * CachedConnectionManager that a connection handle has been given
+ * out. It needs to count the number of handles for each
+ * ManagedConnection. If there is a current transaction, it must
+ * enlist the ManagedConnection's LocalTransaction in the transaction
+ * using the ConnectionEventListeners XAResource XAResource implementation.
+ * Entry point: ConnectionManager.allocateConnection.
+ * written.
+ *
+ * 2. When a ConnectionClosed event is received from the
+ * ConnectionEventListener, it must reduce the handle count. If
+ * the handle count is zero, the XAResource should be delisted from
+ * the Transaction, if any. The CachedConnectionManager must be
+ * notified that the connection is closed.
+ * Entry point: ConnectionEventListener.ConnectionClosed.
+ * written
+ *
+ *3. When a transaction begun notification is received from the
+ * UserTransaction (via the CachedConnectionManager, all
+ * managedConnections associated with the current object must be
+ * enlisted in the transaction.
+ * Entry point: (from
+ * CachedConnectionManager)
+ * ConnectionCacheListener.transactionStarted(Transaction,
+ * Collection). The collection is of ConnectionRecord objects.
+ * written.
+ *
+ * 5. When an "entering object" notification is received from the
+ * CachedConnectionInterceptor, all the connections for the current
+ * object must be associated with a ManagedConnection. if there is a
+ * Transaction, the XAResource must be enlisted with it.
+ * Entry point: ConnectionCacheListener.reconnect(Collection conns) The Collection
+ * is of ConnectionRecord objects.
+ * written.
+ *
+ * 6. When a "leaving object" notification is received from the
+ * CachedConnectionInterceptor, all the managedConnections for the
+ * current object must have their XAResources delisted from the
+ * current Transaction, if any, and cleanup called on each
+ * ManagedConnection.
+ * Entry point: ConnectionCacheListener.disconnect(Collection conns).
+ * written.
+ *
+ * @author <a href="mailto:d_jencks at users.sourceforge.net">David Jencks</a>
+ * @author <a href="mailto:adrian at jboss.org">Adrian Brock</a>
+ * @author <a href="weston.price at jboss.com">Weston Price</a>
+ * @version $Revision: 77961 $
*/
-public class TxConnectionManager
+public class TxConnectionManager extends AbstractConnectionManager
{
+ /**Transaction manager instance*/
+ private TransactionManager tm;
+ /**Interleaving or not*/
+ private boolean interleaving;
+
+ /**Local tx or not*/
+ private boolean localTransactions;
+
+ /**XA resource timeout*/
+ private int xaResourceTimeout = 0;
+
+ /**Xid pad*/
+ private boolean padXid;
+
+ /**XA resource wrapped or not*/
+ private boolean wrapXAResource;
+
+ /**Same RM override*/
+ private Boolean isSameRMOverrideValue;
+
+ /**Log trace*/
+ private boolean trace = getLog().isTraceEnabled();
+
+ /**
+ * Default managed TxConnectionManager constructor for mbean instances.
+ */
+ public TxConnectionManager()
+ {
+ }
+
+ /**
+ * Gets transaction manager instance.
+ * @return transaction manager
+ */
+ public TransactionManager getTransactionManagerInstance()
+ {
+ return tm;
+ }
+
+ /**
+ * Sets transaction manager.
+ * @param tm transaction manager
+ */
+ public void setTransactionManagerInstance(TransactionManager tm)
+ {
+ this.tm = tm;
+ }
+
+ /**
+ * Gets track connection by tx.
+ * @return track connection by tx
+ */
+ @Deprecated
+ public boolean isTrackConnectionByTx()
+ {
+ getLog().warn("isTrackConnectionByTx() is deprecated in favor of isInterleaving()");
+ return !isInterleaving();
+ }
+
+ /**
+ * Set track connection by tx.
+ * @param trackConnectionByTx track connection by tx
+ */
+ @Deprecated
+ public void setTrackConnectionByTx(boolean trackConnectionByTx)
+ {
+ getLog().warn("setTrackConnectionByTx(boolean value) is deprecated in favor of setInterleaving(boolean value)");
+ setInterleaving(!trackConnectionByTx);
+ }
+
+ /**
+ * Gets interleaving flag.
+ * @return interleaving flag
+ */
+ public boolean isInterleaving()
+ {
+ return interleaving;
+ }
+
+ /**
+ * Sets interleaving flag.
+ * @param value interleaving
+ */
+ public void setInterleaving(boolean value)
+ {
+ this.interleaving = value;
+ }
+
+ /**
+ * Returns local tx or not.
+ * @return local tx or not
+ */
+ public boolean isLocalTransactions()
+ {
+ return localTransactions;
+ }
+
+ /**
+ * Sets local transaction or not.
+ * @param localTransactions local transaction flag
+ */
+ public void setLocalTransactions(boolean localTransactions)
+ {
+ this.localTransactions = localTransactions;
+ if (localTransactions)
+ setInterleaving(false);
+ }
+
+ /**
+ * Gets XA resource transaction time out.
+ * @return xa resource transaction timeout
+ */
+ public int getXAResourceTransactionTimeout()
+ {
+ return xaResourceTimeout;
+ }
+
+ /**
+ * Sets XA resource transaction timeout.
+ * @param timeout xa resource transaction timeout
+ */
+ public void setXAResourceTransactionTimeout(int timeout)
+ {
+ this.xaResourceTimeout = timeout;
+ }
+
+ /**
+ * Get the IsSameRMOverrideValue value.
+ *
+ * @return the IsSameRMOverrideValue value.
+ */
+ public Boolean getIsSameRMOverrideValue()
+ {
+ return isSameRMOverrideValue;
+ }
+
+ /**
+ * Returns true if wrap xa resource.
+ * @return true if wrap xa resource
+ */
+ public boolean getWrapXAResource()
+ {
+ return wrapXAResource;
+ }
+
+ /**
+ * Sets use xa wrapper.
+ * @param useXAWrapper use xa wrapper
+ */
+ public void setWrapXAResource(boolean useXAWrapper)
+ {
+ this.wrapXAResource = useXAWrapper;
+
+ }
+
+ /**
+ * Gets pad.
+ * @return pad
+ */
+ public boolean getPadXid()
+ {
+ return this.padXid;
+
+ }
+
+ /**
+ * Sets pad.
+ * @param padXid pad
+ */
+ public void setPadXid(boolean padXid)
+ {
+ this.padXid = padXid;
+ }
+ /**
+ * Set the IsSameRMOverrideValue value.
+ *
+ * @param isSameRMOverrideValue The new IsSameRMOverrideValue value.
+ */
+ public void setIsSameRMOverrideValue(Boolean isSameRMOverrideValue)
+ {
+ this.isSameRMOverrideValue = isSameRMOverrideValue;
+ }
+
+ /**
+ * Gets time left.
+ * @param errorRollback error rollback
+ * @return time left
+ * @throws RollbackException if exception
+ */
+ public long getTimeLeftBeforeTransactionTimeout(boolean errorRollback) throws RollbackException
+ {
+ if (tm == null)
+ throw new IllegalStateException("No transaction manager: " + getCachedConnectionManager());
+ if (tm instanceof TransactionTimeoutConfiguration)
+ return ((TransactionTimeoutConfiguration) tm).getTimeLeftBeforeTransactionTimeout(errorRollback);
+ return -1;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void checkTransactionActive() throws RollbackException, SystemException
+ {
+ if (tm == null)
+ throw new IllegalStateException("No transaction manager: " + getCachedConnectionManager());
+ Transaction tx = tm.getTransaction();
+ if (tx != null)
+ {
+ int status = tx.getStatus();
+ // Only allow states that will actually succeed
+ if (status != Status.STATUS_ACTIVE && status != Status.STATUS_PREPARING &&
+ status != Status.STATUS_PREPARED && status != Status.STATUS_COMMITTING)
+ throw new RollbackException("Transaction " + tx + " cannot proceed " + TxUtils.getStatusAsString(status));
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ConnectionListener getManagedConnection(Subject subject, ConnectionRequestInfo cri)
+ throws ResourceException
+ {
+ Transaction trackByTransaction = null;
+ try
+ {
+ Transaction tx = tm.getTransaction();
+ if (tx != null && !TxUtils.isActive(tx))
+ throw new ResourceException("Transaction is not active: tx=" + tx);
+ if (!interleaving)
+ trackByTransaction = tx;
+ }
+ catch (Throwable t)
+ {
+ JBossResourceException.rethrowAsResourceException("Error checking for a transaction.", t);
+ }
+
+ if (this.trace)
+ getLog().trace("getManagedConnection interleaving=" + interleaving + " tx=" + trackByTransaction);
+ return super.getManagedConnection(trackByTransaction, subject, cri);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void transactionStarted(Collection<ConnectionRecord> crs) throws SystemException
+ {
+ Set<ConnectionListener> cls = new HashSet<ConnectionListener>();
+ for (Iterator<ConnectionRecord> i = crs.iterator(); i.hasNext(); )
+ {
+ ConnectionRecord cr = i.next();
+ ConnectionListener cl = cr.getConnectionListener();
+ if (!cls.contains(cl))
+ {
+ cls.add(cl);
+ cl.enlist();
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected void managedConnectionReconnected(ConnectionListener cl) throws ResourceException
+ {
+ try
+ {
+ cl.enlist();
+ }
+ catch (Throwable t)
+ {
+ if (trace)
+ {
+ getLog().trace("Could not enlist in transaction on entering meta-aware object! " + cl, t);
+ }
+ throw new JBossResourceException("Could not enlist in transaction on entering meta-aware object!", t);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected void managedConnectionDisconnected(ConnectionListener cl) throws ResourceException
+ {
+ Throwable throwable = null;
+ try
+ {
+ cl.delist();
+ }
+ catch (Throwable t)
+ {
+ throwable = t;
+ }
+
+ //if there are no more handles and tx is complete, we can return to pool.
+ if (cl.isManagedConnectionFree())
+ {
+ if (trace)
+ getLog().trace("Disconnected isManagedConnectionFree=true" + " cl=" + cl);
+ returnManagedConnection(cl, false);
+ }
+ else if (trace)
+ {
+ getLog().trace("Disconnected isManagedConnectionFree=false" + " cl=" + cl);
+ }
+
+ // Rethrow the error
+ if (throwable != null)
+ {
+ JBossResourceException.rethrowAsResourceException(
+ "Could not delist resource, probably a transaction rollback? ", throwable);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ConnectionListener createConnectionListener(ManagedConnection mc, Object context)
+ throws ResourceException
+ {
+ XAResource xaResource = null;
+
+ if (localTransactions)
+ {
+ xaResource = new LocalXAResource(this);
+
+ if (xaResourceTimeout != 0)
+ getLog().debug("XAResource transaction timeout cannot be set for local transactions: " + getJndiName());
+ }
+
+ else
+ {
+
+ if (this.wrapXAResource)
+ {
+ String eisProductName = null;
+ String eisProductVersion = null;
+
+ try
+ {
+ eisProductName = mc.getMetaData().getEISProductName();
+ eisProductVersion = mc.getMetaData().getEISProductVersion();
+ }
+ catch (ResourceException re)
+ {
+ // Ignore
+ }
+
+ getLog().trace("Generating XAResourceWrapper for TxConnectionManager" + this);
+ xaResource = new XAResourceWrapperImpl(mc.getXAResource(), padXid,
+ isSameRMOverrideValue, eisProductName, eisProductVersion);
+ }
+
+ else
+ {
+ getLog().trace("Not wrapping XAResource.");
+ xaResource = mc.getXAResource();
+ }
+
+ if (xaResourceTimeout != 0)
+ {
+ try
+ {
+ if (!xaResource.setTransactionTimeout(xaResourceTimeout))
+ getLog().debug("XAResource does not support transaction timeout configuration: " + getJndiName());
+ }
+ catch (XAException e)
+ {
+ throw new JBossResourceException("Unable to set XAResource transaction timeout: " + getJndiName(), e);
+ }
+ }
+ }
+
+ ConnectionListener cli = new TxConnectionListener(this, mc, getPoolingStrategy(), context, xaResource);
+ mc.addConnectionEventListener(cli);
+ return cli;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isTransactional()
+ {
+ return !TxUtils.isCompleted(tm);
+ }
+
+ /**
+ * RethrowAsSystemException.
+ * @param context context
+ * @param tx transaction
+ * @param t throwable
+ * @throws SystemException system exception
+ */
+ public static void rethrowAsSystemException(String context, Transaction tx, Throwable t)
+ throws SystemException
+ {
+ if (t instanceof SystemException)
+ throw (SystemException) t;
+ if (t instanceof RuntimeException)
+ throw (RuntimeException) t;
+ if (t instanceof Error)
+ throw (Error) t;
+ if (t instanceof RollbackException)
+ throw new IllegalStateException(context + " tx=" + tx + " marked for rollback.");
+ throw new NestedRuntimeException(context + " tx=" + tx + " got unexpected error ", t);
+ }
+
}
Added: projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/xa/LocalXAResource.java
===================================================================
--- projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/xa/LocalXAResource.java (rev 0)
+++ projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/xa/LocalXAResource.java 2009-09-08 19:59:36 UTC (rev 93296)
@@ -0,0 +1,252 @@
+/*
+ * 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.jca.core.connectionmanager.xa;
+
+import org.jboss.jca.core.connectionmanager.AbstractConnectionManager;
+import org.jboss.jca.core.connectionmanager.exception.JBossLocalXAException;
+import org.jboss.jca.core.connectionmanager.listener.ConnectionListener;
+
+import javax.resource.ResourceException;
+import javax.transaction.xa.XAException;
+import javax.transaction.xa.XAResource;
+import javax.transaction.xa.Xid;
+
+import org.jboss.logging.Logger;
+import org.jboss.tm.LastResource;
+
+/**
+ * Local XA resource implementation.
+ *
+ * @author <a href="mailto:gurkanerdogdu at yahoo.com">Gurkan Erdogdu</a>
+ * @version $Rev$ $Date$
+ */
+public class LocalXAResource implements XAResource, LastResource
+{
+ /** Log instance */
+ private static Logger log = Logger.getLogger(LocalXAResource.class);
+
+ /** Connection listener */
+ private ConnectionListener cl;
+
+ /** Log trace */
+ private boolean trace;
+
+ /**Connection manager*/
+ private AbstractConnectionManager connectionManager = null;
+
+ /**
+ * <code>warned</code> is set after one warning about a local participant in
+ * a multi-branch jta transaction is logged.
+ */
+ private boolean warned = false;
+
+ /** Current transction branch id */
+ private Xid currentXid;
+
+ /**
+ * Creates a new instance.
+ * @param connectionManager connection manager
+ */
+ public LocalXAResource(AbstractConnectionManager connectionManager)
+ {
+ this.trace = log.isTraceEnabled();
+ this.connectionManager = connectionManager;
+ }
+
+ /**
+ * Sets connection listener.
+ *
+ * @param cl connection listener
+ */
+ public void setConnectionListener(ConnectionListener cl)
+ {
+ this.cl = cl;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void start(Xid xid, int flags) throws XAException
+ {
+ if (this.trace)
+ {
+ log.trace("start, xid: " + xid + ", flags: " + flags);
+ }
+
+ if (this.currentXid != null && flags == XAResource.TMNOFLAGS)
+ {
+ throw new JBossLocalXAException("Trying to start a new tx when old is not complete! old: " +
+ currentXid + ", new " + xid + ", flags " + flags, XAException.XAER_PROTO);
+ }
+
+ if (this.currentXid == null && flags != XAResource.TMNOFLAGS)
+ {
+ throw new JBossLocalXAException("Trying to start a new tx with wrong flags! new " + xid +
+ ", flags " + flags, XAException.XAER_PROTO);
+ }
+
+ if (this.currentXid == null)
+ {
+ try
+ {
+ this.cl.getManagedConnection().getLocalTransaction().begin();
+ }
+ catch (ResourceException re)
+ {
+ throw new JBossLocalXAException("Error trying to start local tx: ", XAException.XAER_RMERR, re);
+ }
+ catch (Throwable t)
+ {
+ throw new JBossLocalXAException("Throwable trying to start local transaction!", XAException.XAER_RMERR, t);
+ }
+
+ this.currentXid = xid;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void end(Xid xid, int flags) throws XAException
+ {
+ if (this.trace)
+ {
+ log.trace("end on xid: " + xid + " called with flags " + flags);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void commit(Xid xid, boolean onePhase) throws XAException
+ {
+ if (!xid.equals(this.currentXid))
+ {
+ throw new JBossLocalXAException("wrong xid in commit: expected: " + this.currentXid +
+ ", got: " + xid, XAException.XAER_PROTO);
+
+ }
+
+ this.currentXid = null;
+
+ try
+ {
+ this.cl.getManagedConnection().getLocalTransaction().commit();
+ }
+ catch (ResourceException re)
+ {
+ this.connectionManager.returnManagedConnection(this.cl, true);
+
+ if (this.trace)
+ {
+ log.trace("commit problem: ", re);
+ }
+
+ throw new JBossLocalXAException("could not commit local tx", XAException.XA_RBROLLBACK, re);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void forget(Xid xid) throws XAException
+ {
+ throw new JBossLocalXAException("forget not supported in local tx", XAException.XAER_RMERR);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int getTransactionTimeout() throws XAException
+ {
+ // TODO implement this javax.transaction.xa.XAResource method
+ return 0;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isSameRM(XAResource xaResource) throws XAException
+ {
+ return xaResource == this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int prepare(Xid xid) throws XAException
+ {
+ if (!this.warned)
+ {
+ log.warn("Prepare called on a local tx. Use of local transactions on a jta transaction with more " +
+ "than one branch may result in inconsistent data in some cases of failure.");
+ }
+ warned = true;
+
+ return XAResource.XA_OK;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Xid[] recover(int flag) throws XAException
+ {
+ throw new JBossLocalXAException("no recover with local-tx only resource managers", XAException.XAER_RMERR);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void rollback(Xid xid) throws XAException
+ {
+ if (!xid.equals(this.currentXid))
+ {
+ throw new JBossLocalXAException("wrong xid in rollback: expected: " +
+ this.currentXid + ", got: " + xid, XAException.XAER_PROTO);
+ }
+ this.currentXid = null;
+ try
+ {
+ this.cl.getManagedConnection().getLocalTransaction().rollback();
+ }
+ catch (ResourceException re)
+ {
+ this.connectionManager.returnManagedConnection(this.cl, true);
+
+ if (this.trace)
+ {
+ log.trace("rollback problem: ", re);
+ }
+
+ throw new JBossLocalXAException("could not rollback local tx", XAException.XAER_RMERR, re);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean setTransactionTimeout(int seconds) throws XAException
+ {
+ // TODO implement this javax.transaction.xa.XAResource method
+ return false;
+ }
+}
Property changes on: projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/xa/LocalXAResource.java
___________________________________________________________________
Name: svn:keywords
+ Rev Date
Name: svn:eol-style
+ native
Added: projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/xa/XAResourceWrapperImpl.java
===================================================================
--- projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/xa/XAResourceWrapperImpl.java (rev 0)
+++ projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/xa/XAResourceWrapperImpl.java 2009-09-08 19:59:36 UTC (rev 93296)
@@ -0,0 +1,264 @@
+/*
+ * 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.jca.core.connectionmanager.xa;
+import org.jboss.jca.core.connectionmanager.xa.api.XidWrapper;
+
+import javax.transaction.xa.XAException;
+import javax.transaction.xa.XAResource;
+import javax.transaction.xa.Xid;
+
+import org.jboss.logging.Logger;
+import org.jboss.tm.XAResourceWrapper;
+
+/**
+ * A XAResourceWrapper.
+ *
+ * @author <a href="weston.price at jboss.com">Weston Price</a>
+ * @author <a href="jesper.pedersen at jboss.org">Jesper Pedersen</a>
+ * @version $Revision$
+ */
+public class XAResourceWrapperImpl implements XAResourceWrapper
+{
+ /**Serial version UID*/
+ private static final long serialVersionUID = -7463658256795280905L;
+
+ /**Log instance*/
+ private static Logger log = Logger.getLogger(XAResourceWrapperImpl.class);
+
+ /** The xaResource */
+ private XAResource xaResource;
+
+ /**Pad*/
+ private boolean pad;
+
+ /**Override Rm Value*/
+ private Boolean overrideRmValue;
+
+ /**Product name*/
+ private String productName;
+
+ /**Product version*/
+ private String productVersion;
+
+ /**
+ * Creates a new wrapper instance.
+ * @param resource xaresource
+ */
+ public XAResourceWrapperImpl(XAResource resource)
+ {
+ this(resource, false, Boolean.FALSE, null, null);
+ }
+
+ /**
+ * Creates a new wrapper instance.
+ * @param resource xaresource
+ * @param pad pad
+ */
+ public XAResourceWrapperImpl(XAResource resource, boolean pad)
+ {
+ this(resource, pad, Boolean.FALSE, null, null);
+ }
+
+ /**
+ * Creates a new wrapper instance.
+ * @param resource xaresource
+ * @param pad pad
+ * @param override override
+ */
+ public XAResourceWrapperImpl(XAResource resource, boolean pad, Boolean override)
+ {
+ this(resource, pad, override, null, null);
+ }
+
+
+ /**
+ * Creates a new wrapper instance.
+ * @param resource xaresource
+ * @param pad pad
+ * @param override override
+ * @param productName product name
+ * @param productVersion product version
+ */
+ public XAResourceWrapperImpl(XAResource resource, boolean pad, Boolean override,
+ String productName, String productVersion)
+ {
+ this.overrideRmValue = override;
+ this.pad = pad;
+ this.xaResource = resource;
+ this.productName = productName;
+ this.productVersion = productVersion;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void commit(Xid xid, boolean onePhase) throws XAException
+ {
+ xid = convertXid(xid);
+ xaResource.commit(xid, onePhase);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void end(Xid xid, int flags) throws XAException
+ {
+ xid = convertXid(xid);
+ xaResource.end(xid, flags);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void forget(Xid xid) throws XAException
+ {
+ xid = convertXid(xid);
+ xaResource.forget(xid);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int getTransactionTimeout() throws XAException
+ {
+ return xaResource.getTransactionTimeout();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isSameRM(XAResource resource) throws XAException
+ {
+ if (overrideRmValue != null)
+ {
+ if (log.isTraceEnabled())
+ {
+ log.trace("Executing isSameRM with override value" + overrideRmValue + " for XAResourceWrapper" + this);
+ }
+ return overrideRmValue.booleanValue();
+ }
+ else
+ {
+ if (resource instanceof XAResourceWrapper)
+ {
+ XAResourceWrapper other = (XAResourceWrapper)resource;
+ return xaResource.isSameRM(other.getResource());
+ }
+ else
+ {
+ return xaResource.isSameRM(resource);
+ }
+
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int prepare(Xid xid) throws XAException
+ {
+ xid = convertXid(xid);
+ return xaResource.prepare(xid);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Xid[] recover(int flag) throws XAException
+ {
+ return xaResource.recover(flag);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void rollback(Xid xid) throws XAException
+ {
+ xid = convertXid(xid);
+ xaResource.rollback(xid);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean setTransactionTimeout(int flag) throws XAException
+ {
+ return xaResource.setTransactionTimeout(flag);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void start(Xid xid, int flags) throws XAException
+ {
+ xid = convertXid(xid);
+ xaResource.start(xid, flags);
+ }
+
+ /**
+ * Get the XAResource that is being wrapped
+ * @return The XAResource
+ */
+ public XAResource getResource()
+ {
+ return xaResource;
+ }
+
+ /**
+ * Get product name
+ * @return Product name of the instance if defined; otherwise <code>null</code>
+ */
+ public String getProductName()
+ {
+ return productName;
+ }
+
+ /**
+ * Get product version
+ * @return Product version of the instance if defined; otherwise <code>null</code>
+ */
+ public String getProductVersion()
+ {
+ return productVersion;
+ }
+
+ /**
+ * Return wrapper for given xid.
+ * @param xid xid
+ * @return return wrapper
+ */
+ private Xid convertXid(Xid xid)
+ {
+ if (xid instanceof XidWrapper)
+ return xid;
+ else
+ return new XidWrapperImpl(pad, xid);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String toString()
+ {
+ return super.toString();
+ }
+}
Property changes on: projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/xa/XAResourceWrapperImpl.java
___________________________________________________________________
Name: svn:keywords
+ Rev Date
Name: svn:eol-style
+ native
More information about the jboss-cvs-commits
mailing list