From jboss-cvs-commits at lists.jboss.org Thu Feb 12 13:08:11 2015 From: jboss-cvs-commits at lists.jboss.org (jboss-cvs-commits at lists.jboss.org) Date: Thu, 12 Feb 2015 13:08:11 -0500 Subject: [jboss-cvs] JBossAS SVN: r114833 - branches. Message-ID: <201502121808.t1CI8BIi032579@svn01.web.mwc.hst.phx2.redhat.com> Author: jolee Date: 2015-02-12 13:08:11 -0500 (Thu, 12 Feb 2015) New Revision: 114833 Added: branches/JBPAPP_5_0_1_GA_JBPAPP-11214/ Log: JBPAPP-11214 From jboss-cvs-commits at lists.jboss.org Fri Feb 13 00:36:48 2015 From: jboss-cvs-commits at lists.jboss.org (jboss-cvs-commits at lists.jboss.org) Date: Fri, 13 Feb 2015 00:36:48 -0500 Subject: [jboss-cvs] JBossAS SVN: r114834 - in branches/JBPAPP_5_0_1_GA_JBPAPP-11214/connector: src/main/org/jboss/resource/adapter/jdbc and 2 other directories. Message-ID: <201502130536.t1D5amo3007395@svn01.web.mwc.hst.phx2.redhat.com> Author: dstephan Date: 2015-02-13 00:36:48 -0500 (Fri, 13 Feb 2015) New Revision: 114834 Added: branches/JBPAPP_5_0_1_GA_JBPAPP-11214/connector/src/main/org/jboss/resource/adapter/jdbc/ReentrantLock.java branches/JBPAPP_5_0_1_GA_JBPAPP-11214/connector/src/main/org/jboss/resource/adapter/jms/ReentrantLock.java Modified: branches/JBPAPP_5_0_1_GA_JBPAPP-11214/connector/build.xml branches/JBPAPP_5_0_1_GA_JBPAPP-11214/connector/src/main/org/jboss/resource/adapter/jdbc/BaseWrapperManagedConnection.java branches/JBPAPP_5_0_1_GA_JBPAPP-11214/connector/src/main/org/jboss/resource/adapter/jdbc/WrappedConnection.java branches/JBPAPP_5_0_1_GA_JBPAPP-11214/connector/src/main/org/jboss/resource/adapter/jdbc/remote/WrapperDataSourceService.java branches/JBPAPP_5_0_1_GA_JBPAPP-11214/connector/src/main/org/jboss/resource/adapter/jms/JmsManagedConnection.java branches/JBPAPP_5_0_1_GA_JBPAPP-11214/connector/src/main/org/jboss/resource/adapter/jms/JmsSession.java Log: JBPAPP-11214 - Backport multiple multi-threaded JCA issues ( JBPAPP-5596, JBPAPP-6684, JBPAPP-7102 ) Modified: branches/JBPAPP_5_0_1_GA_JBPAPP-11214/connector/build.xml =================================================================== --- branches/JBPAPP_5_0_1_GA_JBPAPP-11214/connector/build.xml 2015-02-12 18:08:11 UTC (rev 114833) +++ branches/JBPAPP_5_0_1_GA_JBPAPP-11214/connector/build.xml 2015-02-13 05:36:48 UTC (rev 114834) @@ -354,6 +354,7 @@ + Modified: branches/JBPAPP_5_0_1_GA_JBPAPP-11214/connector/src/main/org/jboss/resource/adapter/jdbc/BaseWrapperManagedConnection.java =================================================================== --- branches/JBPAPP_5_0_1_GA_JBPAPP-11214/connector/src/main/org/jboss/resource/adapter/jdbc/BaseWrapperManagedConnection.java 2015-02-12 18:08:11 UTC (rev 114833) +++ branches/JBPAPP_5_0_1_GA_JBPAPP-11214/connector/src/main/org/jboss/resource/adapter/jdbc/BaseWrapperManagedConnection.java 2015-02-13 05:36:48 UTC (rev 114834) @@ -36,7 +36,6 @@ import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.locks.ReentrantLock; import javax.resource.ResourceException; import javax.resource.spi.ConnectionEvent; @@ -54,709 +53,761 @@ /** * BaseWrapperManagedConnection - * + * * @author David Jencks * @author Adrian Brock * @author 0) - psCache = new PreparedStatementCache(psCacheSize); + static + { + Class connectionFactory = null; + try + { + connectionFactory = BaseWrapperManagedConnection.class.forName("org.jboss.resource.adapter.jdbc.jdk6.WrappedConnectionFactoryJDK6"); + } + catch (ClassNotFoundException e) + { + try + { + connectionFactory = BaseWrapperManagedConnection.class.forName("org.jboss.resource.adapter.jdbc.jdk5.WrappedConnectionFactoryJDK5"); + } + catch (ClassNotFoundException ex) + { + throw new RuntimeException("Unabled to load wrapped connection factory", ex); + } + } + try + { + wrappedConnectionFactory = (WrappedConnectionFactory) connectionFactory.newInstance(); + } + catch (Exception e) + { + throw new RuntimeException("Error initializign connection factory", e); + } + } - if (transactionIsolation == -1) - this.transactionIsolation = con.getTransactionIsolation(); + public BaseWrapperManagedConnection(final BaseWrapperManagedConnectionFactory mcf, final Connection con, final Properties props, + final int transactionIsolation, final int psCacheSize) throws SQLException + { + this.mcf = mcf; + this.con = con; + this.props = props; - else - { - this.transactionIsolation = transactionIsolation; - con.setTransactionIsolation(transactionIsolation); - } + if (psCacheSize > 0) + psCache = new PreparedStatementCache(psCacheSize); - readOnly = con.isReadOnly(); + if (transactionIsolation == -1) + this.transactionIsolation = con.getTransactionIsolation(); - if (mcf.getNewConnectionSQL() != null) - { - Statement s = con.createStatement(); - try - { - s.execute(mcf.getNewConnectionSQL()); - } - finally - { - s.close(); - } - } + else + { + this.transactionIsolation = transactionIsolation; + con.setTransactionIsolation(transactionIsolation); + } - underlyingReadOnly = readOnly; - jdbcReadOnly = readOnly; - jdbcTransactionIsolation = this.transactionIsolation; - } + readOnly = con.isReadOnly(); - public void addConnectionEventListener(ConnectionEventListener cel) - { - synchronized (cels) - { - cels.add(cel); - } - } + if (mcf.getNewConnectionSQL() != null) + { + Statement s = con.createStatement(); + try + { + s.execute(mcf.getNewConnectionSQL()); + } + finally + { + s.close(); + } + } - public void removeConnectionEventListener(ConnectionEventListener cel) - { - synchronized (cels) - { - cels.remove(cel); - } - } + underlyingReadOnly = readOnly; + jdbcReadOnly = readOnly; + jdbcTransactionIsolation = this.transactionIsolation; + } - public void associateConnection(Object handle) throws ResourceException - { - if (!(handle instanceof WrappedConnection)) - throw new JBossResourceException("Wrong kind of connection handle to associate" + handle); - ((WrappedConnection) handle).setManagedConnection(this); - synchronized (handles) - { - handles.add(handle); - } - } + public void addConnectionEventListener(ConnectionEventListener cel) + { + synchronized (cels) + { + cels.add(cel); + } + } - public PrintWriter getLogWriter() throws ResourceException - { - // TODO: implement this javax.resource.spi.ManagedConnection method - return null; - } + public void removeConnectionEventListener(ConnectionEventListener cel) + { + synchronized (cels) + { + cels.remove(cel); + } + } - public ManagedConnectionMetaData getMetaData() throws ResourceException - { - // TODO: implement this javax.resource.spi.ManagedConnection method - return null; - } + public void associateConnection(Object handle) throws ResourceException + { + if (!(handle instanceof WrappedConnection)) + throw new JBossResourceException("Wrong kind of connection handle to associate" + handle); + ((WrappedConnection) handle).setManagedConnection(this); + synchronized (handles) + { + handles.add(handle); + } + } - public void setLogWriter(PrintWriter param1) throws ResourceException - { - // TODO: implement this javax.resource.spi.ManagedConnection method - } + public PrintWriter getLogWriter() throws ResourceException + { + // TODO: implement this javax.resource.spi.ManagedConnection method + return null; + } - public void cleanup() throws ResourceException - { - synchronized (handles) - { - for (Iterator i = handles.iterator(); i.hasNext();) - { - WrappedConnection lc = (WrappedConnection) i.next(); - lc.setManagedConnection(null); - } - handles.clear(); - } - //reset all the properties we know about to defaults. - synchronized (stateLock) - { - jdbcAutoCommit = true; - jdbcReadOnly = readOnly; - if (jdbcTransactionIsolation != transactionIsolation) - { - try - { - con.setTransactionIsolation(transactionIsolation); - jdbcTransactionIsolation = transactionIsolation; - } - catch (SQLException e) - { - mcf.log.warn("Error resetting transaction isolation ", e); - } - } - } - // I'm recreating the lock object when we return to the pool - // because it looks too nasty to expect the connection handle - // to unlock properly in certain race conditions - // where the dissociation of the managed connection is "random". - lock = new ReentrantLock(); - } + public ManagedConnectionMetaData getMetaData() throws ResourceException + { + // TODO: implement this javax.resource.spi.ManagedConnection method + return null; + } - protected void lock() - { - lock.lock(); - } + public void setLogWriter(PrintWriter param1) throws ResourceException + { + // TODO: implement this javax.resource.spi.ManagedConnection method + } - protected void tryLock() throws SQLException - { - int tryLock = mcf.getUseTryLock(); - if (tryLock <= 0) - { - lock(); - return; - } - try - { - if (lock.tryLock(tryLock, TimeUnit.SECONDS) == false) - throw new SQLException("Unable to obtain lock in " + tryLock + " seconds: " + this); - } - catch (InterruptedException e) - { - throw new SQLException("Interrupted attempting lock: " + this); - } - } - - protected void unlock() - { - lock.unlock(); - } + public void cleanup() throws ResourceException + { + boolean isActive = false; - public Object getConnection(Subject subject, ConnectionRequestInfo cri) throws ResourceException - { - checkIdentity(subject, cri); - WrappedConnection lc = wrappedConnectionFactory.createWrappedConnection(this); - synchronized (handles) - { - handles.add(lc); - } - return lc; - } + if (lock.hasQueuedThreads()) + { + Collection threads = lock.getQueuedThreads(); + for (Thread thread : threads) + { + Throwable t = new Throwable("Thread waiting for lock during cleanup"); + t.setStackTrace(thread.getStackTrace()); - public void destroy() throws ResourceException - { - synchronized (stateLock) - { - destroyed = true; - } + mcf.log.warn(t.getMessage(), t); + } - cleanup(); - try - { - // See JBAS-5678 - if (underlyingAutoCommit == false) - con.rollback(); - } - catch (SQLException ignored) - { - getLog().trace("Ignored error during rollback: ", ignored); - } - try - { - con.close(); - } - catch (SQLException ignored) - { - getLog().trace("Ignored error during close: ", ignored); - } - } + isActive = true; + } - public boolean checkValid() - { - SQLException e = mcf.isValidConnection(con); + if (lock.isLocked()) + { + Throwable t = new Throwable("Lock owned during cleanup"); + t.setStackTrace(lock.getOwner().getStackTrace()); - if (e == null) - // It's ok - return true; - else - { - getLog().warn("Destroying connection that is not valid, due to the following exception: " + con, e); - broadcastConnectionError(e); - return false; - } - } + mcf.log.warn(t.getMessage(), t); - public Properties getProperties() - { - return this.props; + isActive = true; + } + synchronized (handles) + { + for (Iterator i = handles.iterator(); i.hasNext();) + { + WrappedConnection lc = (WrappedConnection) i.next(); + lc.setManagedConnection(null); + } - } + handles.clear(); - void closeHandle(WrappedConnection handle) - { - synchronized (stateLock) - { - if (destroyed) - return; - } + } + // reset all the properties we know about to defaults. + synchronized (stateLock) + { + jdbcAutoCommit = true; + jdbcReadOnly = readOnly; + if (jdbcTransactionIsolation != transactionIsolation) + { + try + { + con.setTransactionIsolation(transactionIsolation); + jdbcTransactionIsolation = transactionIsolation; + } + catch (SQLException e) + { + mcf.log.warn("Error resetting transaction isolation ", e); + } + } + } - synchronized (handles) - { - handles.remove(handle); - } - ConnectionEvent ce = new ConnectionEvent(this, ConnectionEvent.CONNECTION_CLOSED); - ce.setConnectionHandle(handle); - Collection copy = null; - synchronized (cels) - { - copy = new ArrayList(cels); - } - for (Iterator i = copy.iterator(); i.hasNext();) - { - ConnectionEventListener cel = (ConnectionEventListener) i.next(); - cel.connectionClosed(ce); - } - } + if (isActive) + { + // There are active lock - make sure that the JCA container kills + // this handle by throwing an exception - Throwable connectionError(Throwable t) - { - if(t instanceof SQLException) - { - if(mcf.isStaleConnection((SQLException)t)) - { - t = new StaleConnectionException((SQLException)t); - - }else - { - if(mcf.isExceptionFatal((SQLException)t)) - { - broadcastConnectionError(t); - - } - } - } - else - { - broadcastConnectionError(t); - } + throw new ResourceException("Still active locks for " + this); + } + } - return t; - } + protected void lock() + { + lock.lock(); + } + protected void tryLock() throws SQLException + { + int tryLock = mcf.getUseTryLock(); + if (tryLock <= 0) + { + lock(); + return; + } + try + { + if (lock.tryLock(tryLock, TimeUnit.SECONDS) == false) + throw new SQLException("Unable to obtain lock in " + tryLock + " seconds: " + this); + } + catch (InterruptedException e) + { + throw new SQLException("Interrupted attempting lock: " + this); + } + } - protected void broadcastConnectionError(Throwable e) - { - synchronized (stateLock) - { - if (destroyed) - { - Logger log = getLog(); - if (log.isTraceEnabled()) - log.trace("Not broadcasting error, already destroyed " + this, e); - return; - } - } + protected void unlock() + { + if (lock.isLocked()) + { + lock.unlock(); + } + else + { + mcf.log.warn("Owner is null"); + Throwable t = new Throwable("Thread trying to unlock"); + t.setStackTrace(Thread.currentThread().getStackTrace()); - Exception ex = null; - if (e instanceof Exception) - ex = (Exception) e; - else - ex = new ResourceAdapterInternalException("Unexpected error", e); - ConnectionEvent ce = new ConnectionEvent(this, ConnectionEvent.CONNECTION_ERROR_OCCURRED, ex); - Collection copy = null; - synchronized (cels) - { - copy = new ArrayList(cels); - } - for (Iterator i = copy.iterator(); i.hasNext();) - { - ConnectionEventListener cel = (ConnectionEventListener) i.next(); - try - { - cel.connectionErrorOccurred(ce); - } - catch (Throwable t) - { - getLog().warn("Error notifying of connection error for listener: " + cel, t); - } - } - } + mcf.log.warn(t.getMessage(), t); + } - Connection getConnection() throws SQLException - { - if (con == null) - throw new SQLException("Connection has been destroyed!!!"); - return con; - } + } - PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException - { - if (psCache != null) - { - PreparedStatementCache.Key key = new PreparedStatementCache.Key(sql, - PreparedStatementCache.Key.PREPARED_STATEMENT, resultSetType, resultSetConcurrency); - CachedPreparedStatement cachedps = (CachedPreparedStatement) psCache.get(key); - if (cachedps != null) - { - if (canUse(cachedps)) - cachedps.inUse(); - else - return doPrepareStatement(sql, resultSetType, resultSetConcurrency); - } - else - { - PreparedStatement ps = doPrepareStatement(sql, resultSetType, resultSetConcurrency); - cachedps = wrappedConnectionFactory.createCachedPreparedStatement(ps); - psCache.insert(key, cachedps); - } - return cachedps; - } - else - return doPrepareStatement(sql, resultSetType, resultSetConcurrency); - } + public Object getConnection(Subject subject, ConnectionRequestInfo cri) throws ResourceException + { + checkIdentity(subject, cri); + WrappedConnection lc = wrappedConnectionFactory.createWrappedConnection(this); + synchronized (handles) + { + handles.add(lc); + } + return lc; + } - PreparedStatement doPrepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException - { - return con.prepareStatement(sql, resultSetType, resultSetConcurrency); - } + public void destroy() throws ResourceException + { + synchronized (stateLock) + { + destroyed = true; + } - CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException - { - if (psCache != null) - { - PreparedStatementCache.Key key = new PreparedStatementCache.Key(sql, - PreparedStatementCache.Key.CALLABLE_STATEMENT, resultSetType, resultSetConcurrency); - CachedCallableStatement cachedps = (CachedCallableStatement) psCache.get(key); - if (cachedps != null) - { - if (canUse(cachedps)) - cachedps.inUse(); - else - return doPrepareCall(sql, resultSetType, resultSetConcurrency); - } - else - { - CallableStatement cs = doPrepareCall(sql, resultSetType, resultSetConcurrency); - cachedps = wrappedConnectionFactory.createCachedCallableStatement(cs); - psCache.insert(key, cachedps); - } - return cachedps; - } - else - return doPrepareCall(sql, resultSetType, resultSetConcurrency); - } + cleanup(); + try + { + // See JBAS-5678 + if (underlyingAutoCommit == false) + con.rollback(); + } + catch (SQLException ignored) + { + getLog().trace("Ignored error during rollback: ", ignored); + } + try + { + con.close(); + } + catch (SQLException ignored) + { + getLog().trace("Ignored error during close: ", ignored); + } + } - CallableStatement doPrepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException - { - return con.prepareCall(sql, resultSetType, resultSetConcurrency); - } + public boolean checkValid() + { + SQLException e = mcf.isValidConnection(con); - boolean canUse(CachedPreparedStatement cachedps) - { - // Nobody is using it so we are ok - if (cachedps.isInUse() == false) - return true; + if (e == null) + // It's ok + return true; + else + { + getLog().warn("Destroying connection that is not valid, due to the following exception: " + con, e); + broadcastConnectionError(e); + return false; + } + } - // Cannot reuse prepared statements in auto commit mode - // if will close the previous usage of the PS - if (underlyingAutoCommit == true) - return false; + public Properties getProperties() + { + return this.props; - // We have been told not to share - return mcf.sharePS; - } + } - protected Logger getLog() - { - return mcf.log; - } + void closeHandle(WrappedConnection handle) + { + synchronized (stateLock) + { + if (destroyed) + return; + } - private void checkIdentity(Subject subject, ConnectionRequestInfo cri) throws ResourceException - { - Properties newProps = mcf.getConnectionProperties(subject, cri); - if (!props.equals(newProps)) - { - throw new JBossResourceException("Wrong credentials passed to getConnection!"); - } // end of if () - } + synchronized (handles) + { + handles.remove(handle); + } + ConnectionEvent ce = new ConnectionEvent(this, ConnectionEvent.CONNECTION_CLOSED); + ce.setConnectionHandle(handle); + Collection copy = null; + synchronized (cels) + { + copy = new ArrayList(cels); + } + for (Iterator i = copy.iterator(); i.hasNext();) + { + ConnectionEventListener cel = (ConnectionEventListener) i.next(); + cel.connectionClosed(ce); + } + } - /** - * The checkTransaction method makes sure the adapter follows the JCA - * autocommit contract, namely all statements executed outside a container managed transaction - * or a component managed transaction should be autocommitted. To avoid continually calling - * setAutocommit(enable) before and after container managed transactions, we keep track of the state - * and check it before each transactional method call. - */ - void checkTransaction() throws SQLException - { - synchronized (stateLock) - { - if (inManagedTransaction) - return; + Throwable connectionError(Throwable t) + { + if (t instanceof SQLException) + { + boolean stale = mcf.isStaleConnection((SQLException) t); - // Check autocommit - if (jdbcAutoCommit != underlyingAutoCommit) - { - con.setAutoCommit(jdbcAutoCommit); - underlyingAutoCommit = jdbcAutoCommit; - } - } + if (stale) + { + t = new StaleConnectionException((SQLException) t); - if (jdbcAutoCommit == false && inLocalTransaction.getAndSet(true) == false) - { - ArrayList copy; - synchronized (cels) - { - copy = new ArrayList(cels); - } - ConnectionEvent ce = new ConnectionEvent(this, ConnectionEvent.LOCAL_TRANSACTION_STARTED); - for (int i = 0; i < copy.size(); ++i) - { - ConnectionEventListener cel = (ConnectionEventListener) copy.get(i); - try - { - cel.localTransactionStarted(ce); - } - catch (Throwable t) - { - getLog().trace("Error notifying of connection committed for listener: " + cel, t); - } - } - } + } + else + { + boolean fatalException = mcf.isExceptionFatal((SQLException) t); - checkState(); - } + if (fatalException) + { + broadcastConnectionError(t); - protected void checkState() throws SQLException - { - synchronized (stateLock) - { - // Check readonly - if (jdbcReadOnly != underlyingReadOnly) - { - con.setReadOnly(jdbcReadOnly); - underlyingReadOnly = jdbcReadOnly; - } - } - } + } + } + } + else + { + broadcastConnectionError(t); + } - boolean isJdbcAutoCommit() - { - return inManagedTransaction ? false : jdbcAutoCommit; - } + return t; + } - void setJdbcAutoCommit(final boolean jdbcAutoCommit) throws SQLException - { - synchronized (stateLock) - { - if (inManagedTransaction) - throw new SQLException("You cannot set autocommit during a managed transaction!"); - this.jdbcAutoCommit = jdbcAutoCommit; - } + protected void broadcastConnectionError(Throwable e) + { + synchronized (stateLock) + { + if (destroyed) + { + Logger log = getLog(); + if (log.isTraceEnabled()) + log.trace("Not broadcasting error, already destroyed " + this, e); + return; + } + } - if (jdbcAutoCommit && inLocalTransaction.getAndSet(false)) - { - ArrayList copy; - synchronized (cels) - { - copy = new ArrayList(cels); - } - ConnectionEvent ce = new ConnectionEvent(this, ConnectionEvent.LOCAL_TRANSACTION_COMMITTED); - for (int i = 0; i < copy.size(); ++i) - { - ConnectionEventListener cel = (ConnectionEventListener) copy.get(i); - try - { - cel.localTransactionCommitted(ce); - } - catch (Throwable t) - { - getLog().trace("Error notifying of connection committed for listener: " + cel, t); - } - } - } - } + // We need to unlock() before sending the connection error to the + // event listeners. Otherwise the lock won't be in sync once + // cleanup() is called + unlock(); - boolean isJdbcReadOnly() - { - return jdbcReadOnly; - } + Exception ex = null; + if (e instanceof Exception) + ex = (Exception) e; + else + ex = new ResourceAdapterInternalException("Unexpected error", e); + ConnectionEvent ce = new ConnectionEvent(this, ConnectionEvent.CONNECTION_ERROR_OCCURRED, ex); + Collection copy = null; + synchronized (cels) + { + copy = new ArrayList(cels); + } + for (Iterator i = copy.iterator(); i.hasNext();) + { + ConnectionEventListener cel = (ConnectionEventListener) i.next(); + try + { + cel.connectionErrorOccurred(ce); + } + catch (Throwable t) + { + getLog().warn("Error notifying of connection error for listener: " + cel, t); + } + } + } - void setJdbcReadOnly(final boolean readOnly) throws SQLException - { - synchronized (stateLock) - { - if (inManagedTransaction) - throw new SQLException("You cannot set read only during a managed transaction!"); - this.jdbcReadOnly = readOnly; - } - } + Connection getConnection() throws SQLException + { + if (con == null) + throw new SQLException("Connection has been destroyed!!!"); + return con; + } - int getJdbcTransactionIsolation() - { - return jdbcTransactionIsolation; - } + PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException + { + if (psCache != null) + { + PreparedStatementCache.Key key = new PreparedStatementCache.Key(sql, PreparedStatementCache.Key.PREPARED_STATEMENT, resultSetType, + resultSetConcurrency); + CachedPreparedStatement cachedps = (CachedPreparedStatement) psCache.get(key); + if (cachedps != null) + { + if (canUse(cachedps)) + cachedps.inUse(); + else + return doPrepareStatement(sql, resultSetType, resultSetConcurrency); + } + else + { + PreparedStatement ps = doPrepareStatement(sql, resultSetType, resultSetConcurrency); + cachedps = wrappedConnectionFactory.createCachedPreparedStatement(ps); + psCache.insert(key, cachedps); + } + return cachedps; + } + else + return doPrepareStatement(sql, resultSetType, resultSetConcurrency); + } - void setJdbcTransactionIsolation(final int isolationLevel) throws SQLException - { - synchronized (stateLock) - { - this.jdbcTransactionIsolation = isolationLevel; - con.setTransactionIsolation(jdbcTransactionIsolation); - } - } + PreparedStatement doPrepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException + { + return con.prepareStatement(sql, resultSetType, resultSetConcurrency); + } - void jdbcCommit() throws SQLException - { - synchronized (stateLock) - { - if (inManagedTransaction) - throw new SQLException("You cannot commit during a managed transaction!"); - if (jdbcAutoCommit) - throw new SQLException("You cannot commit with autocommit set!"); - } - con.commit(); + CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException + { + if (psCache != null) + { + PreparedStatementCache.Key key = new PreparedStatementCache.Key(sql, PreparedStatementCache.Key.CALLABLE_STATEMENT, resultSetType, + resultSetConcurrency); + CachedCallableStatement cachedps = (CachedCallableStatement) psCache.get(key); + if (cachedps != null) + { + if (canUse(cachedps)) + cachedps.inUse(); + else + return doPrepareCall(sql, resultSetType, resultSetConcurrency); + } + else + { + CallableStatement cs = doPrepareCall(sql, resultSetType, resultSetConcurrency); + cachedps = wrappedConnectionFactory.createCachedCallableStatement(cs); + psCache.insert(key, cachedps); + } + return cachedps; + } + else + return doPrepareCall(sql, resultSetType, resultSetConcurrency); + } - if (inLocalTransaction.getAndSet(false)) - { - ArrayList copy; - synchronized (cels) - { - copy = new ArrayList(cels); - } - ConnectionEvent ce = new ConnectionEvent(this, ConnectionEvent.LOCAL_TRANSACTION_COMMITTED); - for (int i = 0; i < copy.size(); ++i) - { - ConnectionEventListener cel = (ConnectionEventListener) copy.get(i); - try - { - cel.localTransactionCommitted(ce); - } - catch (Throwable t) - { - getLog().trace("Error notifying of connection committed for listener: " + cel, t); - } - } - } - } + CallableStatement doPrepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException + { + return con.prepareCall(sql, resultSetType, resultSetConcurrency); + } - void jdbcRollback() throws SQLException - { - synchronized (stateLock) - { - if (inManagedTransaction) - throw new SQLException("You cannot rollback during a managed transaction!"); - if (jdbcAutoCommit) - throw new SQLException("You cannot rollback with autocommit set!"); - } - con.rollback(); + boolean canUse(CachedPreparedStatement cachedps) + { + // Nobody is using it so we are ok + if (cachedps.isInUse() == false) + return true; - if (inLocalTransaction.getAndSet(false)) - { - ArrayList copy; - synchronized (cels) - { - copy = new ArrayList(cels); - } - ConnectionEvent ce = new ConnectionEvent(this, ConnectionEvent.LOCAL_TRANSACTION_ROLLEDBACK); - for (int i = 0; i < copy.size(); ++i) - { - ConnectionEventListener cel = (ConnectionEventListener) copy.get(i); - try - { - cel.localTransactionRolledback(ce); - } - catch (Throwable t) - { - getLog().trace("Error notifying of connection rollback for listener: " + cel, t); - } - } - } - } + // Cannot reuse prepared statements in auto commit mode + // if will close the previous usage of the PS + if (underlyingAutoCommit == true) + return false; - void jdbcRollback(Savepoint savepoint) throws SQLException - { - synchronized (stateLock) - { - if (inManagedTransaction) - throw new SQLException("You cannot rollback during a managed transaction!"); - if (jdbcAutoCommit) - throw new SQLException("You cannot rollback with autocommit set!"); - } - con.rollback(savepoint); - } + // We have been told not to share + return mcf.sharePS; + } - int getTrackStatements() - { - return mcf.trackStatements; - } + protected Logger getLog() + { + return mcf.log; + } - boolean isTransactionQueryTimeout() - { - return mcf.isTransactionQueryTimeout; - } + private void checkIdentity(Subject subject, ConnectionRequestInfo cri) throws ResourceException + { + Properties newProps = mcf.getConnectionProperties(subject, cri); + if (!props.equals(newProps)) + { + throw new JBossResourceException("Wrong credentials passed to getConnection!"); + } // end of if () + } - int getQueryTimeout() - { - return mcf.getQueryTimeout(); - } + /** + * The checkTransaction method makes sure the adapter follows + * the JCA autocommit contract, namely all statements executed outside a + * container managed transaction or a component managed transaction should + * be autocommitted. To avoid continually calling setAutocommit(enable) + * before and after container managed transactions, we keep track of the + * state and check it before each transactional method call. + */ + void checkTransaction() throws SQLException + { + synchronized (stateLock) + { + if (inManagedTransaction) + return; - protected void checkException(SQLException e) throws ResourceException - { - connectionError(e); - throw new JBossResourceException("SQLException", e); - } - - public Object listConnectionStats() - { - if(psCache != null) - return psCache.toString(); - else - return "-1"; //-1 indicates NoCache - } + // Check autocommit + if (jdbcAutoCommit != underlyingAutoCommit) + { + con.setAutoCommit(jdbcAutoCommit); + underlyingAutoCommit = jdbcAutoCommit; + } + } + + if (jdbcAutoCommit == false && inLocalTransaction.getAndSet(true) == false) + { + ArrayList copy; + synchronized (cels) + { + copy = new ArrayList(cels); + } + ConnectionEvent ce = new ConnectionEvent(this, ConnectionEvent.LOCAL_TRANSACTION_STARTED); + for (int i = 0; i < copy.size(); ++i) + { + ConnectionEventListener cel = (ConnectionEventListener) copy.get(i); + try + { + cel.localTransactionStarted(ce); + } + catch (Throwable t) + { + getLog().trace("Error notifying of connection committed for listener: " + cel, t); + } + } + } + + checkState(); + } + + protected void checkState() throws SQLException + { + synchronized (stateLock) + { + // Check readonly + if (jdbcReadOnly != underlyingReadOnly) + { + con.setReadOnly(jdbcReadOnly); + underlyingReadOnly = jdbcReadOnly; + } + } + } + + boolean isJdbcAutoCommit() + { + return inManagedTransaction ? false : jdbcAutoCommit; + } + + void setJdbcAutoCommit(final boolean jdbcAutoCommit) throws SQLException + { + synchronized (stateLock) + { + if (inManagedTransaction) + throw new SQLException("You cannot set autocommit during a managed transaction!"); + this.jdbcAutoCommit = jdbcAutoCommit; + } + + if (jdbcAutoCommit && inLocalTransaction.getAndSet(false)) + { + ArrayList copy; + synchronized (cels) + { + copy = new ArrayList(cels); + } + ConnectionEvent ce = new ConnectionEvent(this, ConnectionEvent.LOCAL_TRANSACTION_COMMITTED); + for (int i = 0; i < copy.size(); ++i) + { + ConnectionEventListener cel = (ConnectionEventListener) copy.get(i); + try + { + cel.localTransactionCommitted(ce); + } + catch (Throwable t) + { + getLog().trace("Error notifying of connection committed for listener: " + cel, t); + } + } + } + } + + boolean isJdbcReadOnly() + { + return jdbcReadOnly; + } + + void setJdbcReadOnly(final boolean readOnly) throws SQLException + { + synchronized (stateLock) + { + if (inManagedTransaction) + throw new SQLException("You cannot set read only during a managed transaction!"); + this.jdbcReadOnly = readOnly; + } + } + + int getJdbcTransactionIsolation() + { + return jdbcTransactionIsolation; + } + + void setJdbcTransactionIsolation(final int isolationLevel) throws SQLException + { + synchronized (stateLock) + { + this.jdbcTransactionIsolation = isolationLevel; + con.setTransactionIsolation(jdbcTransactionIsolation); + } + } + + void jdbcCommit() throws SQLException + { + synchronized (stateLock) + { + if (inManagedTransaction) + throw new SQLException("You cannot commit during a managed transaction!"); + if (jdbcAutoCommit) + throw new SQLException("You cannot commit with autocommit set!"); + } + con.commit(); + + if (inLocalTransaction.getAndSet(false)) + { + ArrayList copy; + synchronized (cels) + { + copy = new ArrayList(cels); + } + ConnectionEvent ce = new ConnectionEvent(this, ConnectionEvent.LOCAL_TRANSACTION_COMMITTED); + for (int i = 0; i < copy.size(); ++i) + { + ConnectionEventListener cel = (ConnectionEventListener) copy.get(i); + try + { + cel.localTransactionCommitted(ce); + } + catch (Throwable t) + { + getLog().trace("Error notifying of connection committed for listener: " + cel, t); + } + } + } + } + + void jdbcRollback() throws SQLException + { + synchronized (stateLock) + { + if (inManagedTransaction) + throw new SQLException("You cannot rollback during a managed transaction!"); + if (jdbcAutoCommit) + throw new SQLException("You cannot rollback with autocommit set!"); + } + con.rollback(); + + if (inLocalTransaction.getAndSet(false)) + { + ArrayList copy; + synchronized (cels) + { + copy = new ArrayList(cels); + } + ConnectionEvent ce = new ConnectionEvent(this, ConnectionEvent.LOCAL_TRANSACTION_ROLLEDBACK); + for (int i = 0; i < copy.size(); ++i) + { + ConnectionEventListener cel = (ConnectionEventListener) copy.get(i); + try + { + cel.localTransactionRolledback(ce); + } + catch (Throwable t) + { + getLog().trace("Error notifying of connection rollback for listener: " + cel, t); + } + } + } + } + + void jdbcRollback(Savepoint savepoint) throws SQLException + { + synchronized (stateLock) + { + if (inManagedTransaction) + throw new SQLException("You cannot rollback during a managed transaction!"); + if (jdbcAutoCommit) + throw new SQLException("You cannot rollback with autocommit set!"); + } + con.rollback(savepoint); + } + + int getTrackStatements() + { + return mcf.trackStatements; + } + + boolean isTransactionQueryTimeout() + { + return mcf.isTransactionQueryTimeout; + } + + int getQueryTimeout() + { + return mcf.getQueryTimeout(); + } + + protected void checkException(SQLException e) throws ResourceException + { + connectionError(e); + throw new JBossResourceException("SQLException", e); + } + + public Object listConnectionStats() + { + if (psCache != null) + return psCache.toString(); + else + return "-1"; // -1 indicates NoCache + } } Added: branches/JBPAPP_5_0_1_GA_JBPAPP-11214/connector/src/main/org/jboss/resource/adapter/jdbc/ReentrantLock.java =================================================================== --- branches/JBPAPP_5_0_1_GA_JBPAPP-11214/connector/src/main/org/jboss/resource/adapter/jdbc/ReentrantLock.java (rev 0) +++ branches/JBPAPP_5_0_1_GA_JBPAPP-11214/connector/src/main/org/jboss/resource/adapter/jdbc/ReentrantLock.java 2015-02-13 05:36:48 UTC (rev 114834) @@ -0,0 +1,59 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2006, Red Hat Middleware LLC, and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.jboss.resource.adapter.jdbc; + +import java.util.Collection; + +/** + * ReentrantLock override + * @author Jesper Pedersen + */ +public class ReentrantLock extends java.util.concurrent.locks.ReentrantLock +{ + /** Serial version uid */ + private static final long serialVersionUID = 1L; + + /** + * Constructor + * @param fair Fair locking + */ + public ReentrantLock(boolean fair) + { + super(fair); + } + + /** + * {@inheritDoc} + */ + public Thread getOwner() + { + return super.getOwner(); + } + + /** + * {@inheritDoc} + */ + public Collection getQueuedThreads() + { + return super.getQueuedThreads(); + } +} \ No newline at end of file Modified: branches/JBPAPP_5_0_1_GA_JBPAPP-11214/connector/src/main/org/jboss/resource/adapter/jdbc/WrappedConnection.java =================================================================== --- branches/JBPAPP_5_0_1_GA_JBPAPP-11214/connector/src/main/org/jboss/resource/adapter/jdbc/WrappedConnection.java 2015-02-12 18:08:11 UTC (rev 114833) +++ branches/JBPAPP_5_0_1_GA_JBPAPP-11214/connector/src/main/org/jboss/resource/adapter/jdbc/WrappedConnection.java 2015-02-13 05:36:48 UTC (rev 114834) @@ -47,893 +47,906 @@ */ public abstract class WrappedConnection extends JBossWrapper implements Connection { - private static final Logger log = Logger.getLogger(WrappedConnection.class); + private static final Logger log = Logger.getLogger(WrappedConnection.class); - private BaseWrapperManagedConnection mc; + private volatile BaseWrapperManagedConnection mc; - private WrapperDataSource dataSource; - - private HashMap statements; + private BaseWrapperManagedConnection lockedMC; - private boolean closed = false; + private int lockCount; - private int trackStatements; - - public WrappedConnection(final BaseWrapperManagedConnection mc) - { - this.mc = mc; - if (mc != null) - trackStatements = mc.getTrackStatements(); - } + private WrapperDataSource dataSource; - void setManagedConnection(final BaseWrapperManagedConnection mc) - { - this.mc = mc; - if (mc != null) - trackStatements = mc.getTrackStatements(); - } + private HashMap statements; - protected void lock() throws SQLException - { - BaseWrapperManagedConnection mc = this.mc; - if (mc != null) - mc.tryLock(); - else - throw new SQLException("Connection is not associated with a managed connection." + this); - } + private boolean closed = false; - protected void unlock() - { - BaseWrapperManagedConnection mc = this.mc; - if (mc != null) - mc.unlock(); - // We recreate the lock when returned to the pool - // so missing the unlock after disassociation is not important - } + private int trackStatements; - public WrapperDataSource getDataSource() - { - return dataSource; - } - - protected void setDataSource(WrapperDataSource dataSource) - { - this.dataSource = dataSource; - } - - public void setReadOnly(boolean readOnly) throws SQLException - { - lock(); - try - { - checkStatus(); - mc.setJdbcReadOnly(readOnly); - } - finally - { - unlock(); - } - } + public WrappedConnection(final BaseWrapperManagedConnection mc) + { + setManagedConnection(mc); + } - public boolean isReadOnly() throws SQLException - { - checkStatus(); - return mc.isJdbcReadOnly(); - } + void setManagedConnection(final BaseWrapperManagedConnection mc) + { + this.mc = mc; + this.lockCount = 0; - public void close() throws SQLException - { - closed = true; - if (mc != null) - { - if (trackStatements != BaseWrapperManagedConnectionFactory.TRACK_STATEMENTS_FALSE_INT) - { - synchronized (this) - { - if (statements != null) - { - for (Iterator> i = statements.entrySet().iterator(); i.hasNext(); ) - { - Map.Entry entry = i.next(); - WrappedStatement ws = entry.getKey(); - if (trackStatements == BaseWrapperManagedConnectionFactory.TRACK_STATEMENTS_TRUE_INT) - { - Throwable stackTrace = entry.getValue(); - log.warn("Closing a statement you left open, please do your own housekeeping", stackTrace); - } - try - { - ws.internalClose(); - } - catch (Throwable t) - { - log.warn("Exception trying to close statement:", t); - } - } - } - } - } - mc.closeHandle(this); - } - mc = null; - dataSource = null; - } + if (mc != null) + { + trackStatements = mc.getTrackStatements(); + } + else + { + // Reset the lockedMC reference when returned to the pool + lockedMC = null; + } + } - public boolean isClosed() throws SQLException - { - return closed; - } + protected void lock() throws SQLException + { + BaseWrapperManagedConnection mc = this.mc; + if (mc != null) + { + mc.tryLock(); + if (lockedMC == null) + lockedMC = mc; - protected abstract WrappedStatement wrapStatement(Statement statement); - - public Statement createStatement() throws SQLException - { - lock(); - try - { - checkTransaction(); - try - { - return wrapStatement(mc.getConnection().createStatement()); - } - catch (Throwable t) - { - throw checkException(t); - } - } - finally - { - unlock(); - } - } + lockCount++; + } + else + throw new SQLException("Connection is not associated with a managed connection." + this); + } - public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException - { - lock(); - try - { - checkTransaction(); - try - { - return wrapStatement(mc.getConnection().createStatement(resultSetType, resultSetConcurrency)); - } - catch (Throwable t) - { - throw checkException(t); - } - } - finally - { - unlock(); - } - } + protected void unlock() + { + BaseWrapperManagedConnection mc = this.lockedMC; + if (--lockCount == 0) + lockedMC = null; + if (mc != null) + mc.unlock(); + } - public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) - throws SQLException - { - lock(); - try - { - checkTransaction(); - try - { - return wrapStatement(mc.getConnection() - .createStatement(resultSetType, resultSetConcurrency, resultSetHoldability)); - } - catch (Throwable t) - { - throw checkException(t); - } - } - finally - { - unlock(); - } - } + public WrapperDataSource getDataSource() + { + return dataSource; + } - protected abstract WrappedPreparedStatement wrapPreparedStatement(PreparedStatement statement); + protected void setDataSource(WrapperDataSource dataSource) + { + this.dataSource = dataSource; + } - public PreparedStatement prepareStatement(String sql) throws SQLException - { - lock(); - try - { - checkTransaction(); - try - { - return wrapPreparedStatement(mc.prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY)); - } - catch (Throwable t) - { - throw checkException(t); - } - } - finally - { - unlock(); - } - } + public void setReadOnly(boolean readOnly) throws SQLException + { + lock(); + try + { + checkStatus(); + mc.setJdbcReadOnly(readOnly); + } + finally + { + unlock(); + } + } - public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) - throws SQLException - { - lock(); - try - { - checkTransaction(); - try - { - return wrapPreparedStatement(mc.prepareStatement(sql, resultSetType, resultSetConcurrency)); - } - catch (Throwable t) - { - throw checkException(t); - } - } - finally - { - unlock(); - } - } + public boolean isReadOnly() throws SQLException + { + checkStatus(); + return mc.isJdbcReadOnly(); + } - public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, - int resultSetHoldability) throws SQLException - { - lock(); - try - { - checkTransaction(); - try - { - return wrapPreparedStatement(mc.getConnection() - .prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability)); - } - catch (Throwable t) - { - throw checkException(t); - } - } - finally - { - unlock(); - } - } + public void close() throws SQLException + { + closed = true; + if (mc != null) + { + if (trackStatements != BaseWrapperManagedConnectionFactory.TRACK_STATEMENTS_FALSE_INT) + { + synchronized (this) + { + if (statements != null) + { + for (Iterator> i = statements.entrySet().iterator(); i.hasNext();) + { + Map.Entry entry = i.next(); + WrappedStatement ws = entry.getKey(); + if (trackStatements == BaseWrapperManagedConnectionFactory.TRACK_STATEMENTS_TRUE_INT) + { + Throwable stackTrace = entry.getValue(); + log.warn("Closing a statement you left open, please do your own housekeeping", stackTrace); + } + try + { + ws.internalClose(); + } + catch (Throwable t) + { + log.warn("Exception trying to close statement:", t); + } + } + } + } + } + mc.closeHandle(this); + } + mc = null; + dataSource = null; + } - public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException - { - lock(); - try - { - checkTransaction(); - try - { - return wrapPreparedStatement(mc.getConnection().prepareStatement(sql, autoGeneratedKeys)); - } - catch (Throwable t) - { - throw checkException(t); - } - } - finally - { - unlock(); - } - } + public boolean isClosed() throws SQLException + { + return closed; + } - public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException - { - lock(); - try - { - checkTransaction(); - try - { - return wrapPreparedStatement(mc.getConnection().prepareStatement(sql, columnIndexes)); - } - catch (Throwable t) - { - throw checkException(t); - } - } - finally - { - unlock(); - } - } + protected abstract WrappedStatement wrapStatement(Statement statement); - public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException - { - lock(); - try - { - checkTransaction(); - try - { - return wrapPreparedStatement(mc.getConnection().prepareStatement(sql, columnNames)); - } - catch (Throwable t) - { - throw checkException(t); - } - } - finally - { - unlock(); - } - } + public Statement createStatement() throws SQLException + { + lock(); + try + { + checkTransaction(); + try + { + return wrapStatement(mc.getConnection().createStatement()); + } + catch (Throwable t) + { + throw checkException(t); + } + } + finally + { + unlock(); + } + } - protected abstract WrappedCallableStatement wrapCallableStatement(CallableStatement statement); + public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException + { + lock(); + try + { + checkTransaction(); + try + { + return wrapStatement(mc.getConnection().createStatement(resultSetType, resultSetConcurrency)); + } + catch (Throwable t) + { + throw checkException(t); + } + } + finally + { + unlock(); + } + } - public CallableStatement prepareCall(String sql) throws SQLException - { - lock(); - try - { - checkTransaction(); - try - { - return wrapCallableStatement(mc.prepareCall(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY)); - } - catch (Throwable t) - { - throw checkException(t); - } - } - finally - { - unlock(); - } - } + public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException + { + lock(); + try + { + checkTransaction(); + try + { + return wrapStatement(mc.getConnection().createStatement(resultSetType, resultSetConcurrency, resultSetHoldability)); + } + catch (Throwable t) + { + throw checkException(t); + } + } + finally + { + unlock(); + } + } - public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException - { - lock(); - try - { - checkTransaction(); - try - { - return wrapCallableStatement(mc.prepareCall(sql, resultSetType, resultSetConcurrency)); - } - catch (Throwable t) - { - throw checkException(t); - } - } - finally - { - unlock(); - } - } + protected abstract WrappedPreparedStatement wrapPreparedStatement(PreparedStatement statement); - public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, - int resultSetHoldability) throws SQLException - { - lock(); - try - { - checkTransaction(); - try - { - return wrapCallableStatement(mc.getConnection() - .prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability)); - } - catch (Throwable t) - { - throw checkException(t); - } - } - finally - { - unlock(); - } - } + public PreparedStatement prepareStatement(String sql) throws SQLException + { + lock(); + try + { + checkTransaction(); + try + { + return wrapPreparedStatement(mc.prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY)); + } + catch (Throwable t) + { + throw checkException(t); + } + } + finally + { + unlock(); + } + } - public String nativeSQL(String sql) throws SQLException - { - lock(); - try - { - checkTransaction(); - try - { - return mc.getConnection().nativeSQL(sql); - } - catch (Throwable t) - { - throw checkException(t); - } - } - finally - { - unlock(); - } - } + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException + { + lock(); + try + { + checkTransaction(); + try + { + return wrapPreparedStatement(mc.prepareStatement(sql, resultSetType, resultSetConcurrency)); + } + catch (Throwable t) + { + throw checkException(t); + } + } + finally + { + unlock(); + } + } - public void setAutoCommit(boolean autocommit) throws SQLException - { - lock(); - try - { - checkStatus(); - mc.setJdbcAutoCommit(autocommit); - } - finally - { - unlock(); - } - } + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException + { + lock(); + try + { + checkTransaction(); + try + { + return wrapPreparedStatement(mc.getConnection().prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability)); + } + catch (Throwable t) + { + throw checkException(t); + } + } + finally + { + unlock(); + } + } - public boolean getAutoCommit() throws SQLException - { - lock(); - try - { - checkStatus(); - return mc.isJdbcAutoCommit(); - } - finally - { - unlock(); - } - } + public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException + { + lock(); + try + { + checkTransaction(); + try + { + return wrapPreparedStatement(mc.getConnection().prepareStatement(sql, autoGeneratedKeys)); + } + catch (Throwable t) + { + throw checkException(t); + } + } + finally + { + unlock(); + } + } - public void commit() throws SQLException - { - lock(); - try - { - checkTransaction(); - mc.jdbcCommit(); - } - finally - { - unlock(); - } - } + public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException + { + lock(); + try + { + checkTransaction(); + try + { + return wrapPreparedStatement(mc.getConnection().prepareStatement(sql, columnIndexes)); + } + catch (Throwable t) + { + throw checkException(t); + } + } + finally + { + unlock(); + } + } - public void rollback() throws SQLException - { - lock(); - try - { - checkTransaction(); - mc.jdbcRollback(); - } - finally - { - unlock(); - } - } + public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException + { + lock(); + try + { + checkTransaction(); + try + { + return wrapPreparedStatement(mc.getConnection().prepareStatement(sql, columnNames)); + } + catch (Throwable t) + { + throw checkException(t); + } + } + finally + { + unlock(); + } + } - public void rollback(Savepoint savepoint) throws SQLException - { - lock(); - try - { - checkTransaction(); - mc.jdbcRollback(savepoint); - } - finally - { - unlock(); - } - } + protected abstract WrappedCallableStatement wrapCallableStatement(CallableStatement statement); - public DatabaseMetaData getMetaData() throws SQLException - { - lock(); - try - { - checkTransaction(); - try - { - return mc.getConnection().getMetaData(); - } - catch (Throwable t) - { - throw checkException(t); - } - } - finally - { - unlock(); - } - } + public CallableStatement prepareCall(String sql) throws SQLException + { + lock(); + try + { + checkTransaction(); + try + { + return wrapCallableStatement(mc.prepareCall(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY)); + } + catch (Throwable t) + { + throw checkException(t); + } + } + finally + { + unlock(); + } + } - public void setCatalog(String catalog) throws SQLException - { - lock(); - try - { - checkTransaction(); - try - { - mc.getConnection().setCatalog(catalog); - } - catch (Throwable t) - { - throw checkException(t); - } - } - finally - { - unlock(); - } - } + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException + { + lock(); + try + { + checkTransaction(); + try + { + return wrapCallableStatement(mc.prepareCall(sql, resultSetType, resultSetConcurrency)); + } + catch (Throwable t) + { + throw checkException(t); + } + } + finally + { + unlock(); + } + } - public String getCatalog() throws SQLException - { - lock(); - try - { - checkTransaction(); - try - { - return mc.getConnection().getCatalog(); - } - catch (Throwable t) - { - throw checkException(t); - } - } - finally - { - unlock(); - } - } + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException + { + lock(); + try + { + checkTransaction(); + try + { + return wrapCallableStatement(mc.getConnection().prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability)); + } + catch (Throwable t) + { + throw checkException(t); + } + } + finally + { + unlock(); + } + } - public void setTransactionIsolation(int isolationLevel) throws SQLException - { - lock(); - try - { - checkStatus(); - mc.setJdbcTransactionIsolation(isolationLevel); - } - finally - { - unlock(); - } - } + public String nativeSQL(String sql) throws SQLException + { + lock(); + try + { + checkTransaction(); + try + { + return mc.getConnection().nativeSQL(sql); + } + catch (Throwable t) + { + throw checkException(t); + } + } + finally + { + unlock(); + } + } - public int getTransactionIsolation() throws SQLException - { - lock(); - try - { - checkStatus(); - return mc.getJdbcTransactionIsolation(); - } - finally - { - unlock(); - } - } + public void setAutoCommit(boolean autocommit) throws SQLException + { + lock(); + try + { + checkStatus(); + mc.setJdbcAutoCommit(autocommit); + } + finally + { + unlock(); + } + } - public SQLWarning getWarnings() throws SQLException - { - lock(); - try - { - checkTransaction(); - try - { - return mc.getConnection().getWarnings(); - } - catch (Throwable t) - { - throw checkException(t); - } - } - finally - { - unlock(); - } - } + public boolean getAutoCommit() throws SQLException + { + lock(); + try + { + checkStatus(); + return mc.isJdbcAutoCommit(); + } + finally + { + unlock(); + } + } - public void clearWarnings() throws SQLException - { - lock(); - try - { - checkTransaction(); - try - { - mc.getConnection().clearWarnings(); - } - catch (Throwable t) - { - throw checkException(t); - } - } - finally - { - unlock(); - } - } + public void commit() throws SQLException + { + lock(); + try + { + checkTransaction(); + mc.jdbcCommit(); + } + finally + { + unlock(); + } + } - @SuppressWarnings("unchecked") - public Map getTypeMap() throws SQLException - { - lock(); - try - { - checkTransaction(); - try - { - return mc.getConnection().getTypeMap(); - } - catch (Throwable t) - { - throw checkException(t); - } - } - finally - { - unlock(); - } - } + public void rollback() throws SQLException + { + lock(); + try + { + checkTransaction(); + mc.jdbcRollback(); + } + finally + { + unlock(); + } + } - @SuppressWarnings("unchecked") - public void setTypeMap(Map typeMap) throws SQLException - { - lock(); - try - { - checkTransaction(); - try - { - mc.getConnection().setTypeMap(typeMap); - } - catch (Throwable t) - { - throw checkException(t); - } - } - finally - { - unlock(); - } - } + public void rollback(Savepoint savepoint) throws SQLException + { + lock(); + try + { + checkTransaction(); + mc.jdbcRollback(savepoint); + } + finally + { + unlock(); + } + } - public void setHoldability(int holdability) throws SQLException - { - lock(); - try - { - checkTransaction(); - try - { - mc.getConnection().setHoldability(holdability); - } - catch (Throwable t) - { - throw checkException(t); - } - } - finally - { - unlock(); - } - } + public DatabaseMetaData getMetaData() throws SQLException + { + lock(); + try + { + checkTransaction(); + try + { + return mc.getConnection().getMetaData(); + } + catch (Throwable t) + { + throw checkException(t); + } + } + finally + { + unlock(); + } + } - public int getHoldability() throws SQLException - { - lock(); - try - { - checkTransaction(); - try - { - return mc.getConnection().getHoldability(); - } - catch (Throwable t) - { - throw checkException(t); - } - } - finally - { - unlock(); - } - } + public void setCatalog(String catalog) throws SQLException + { + lock(); + try + { + checkTransaction(); + try + { + mc.getConnection().setCatalog(catalog); + } + catch (Throwable t) + { + throw checkException(t); + } + } + finally + { + unlock(); + } + } - public Savepoint setSavepoint() throws SQLException - { - lock(); - try - { - checkTransaction(); - try - { - return mc.getConnection().setSavepoint(); - } - catch (Throwable t) - { - throw checkException(t); - } - } - finally - { - unlock(); - } - } + public String getCatalog() throws SQLException + { + lock(); + try + { + checkTransaction(); + try + { + return mc.getConnection().getCatalog(); + } + catch (Throwable t) + { + throw checkException(t); + } + } + finally + { + unlock(); + } + } - public Savepoint setSavepoint(String name) throws SQLException - { - lock(); - try - { - checkTransaction(); - try - { - return mc.getConnection().setSavepoint(name); - } - catch (Throwable t) - { - throw checkException(t); - } - } - finally - { - unlock(); - } - } + public void setTransactionIsolation(int isolationLevel) throws SQLException + { + lock(); + try + { + checkStatus(); + mc.setJdbcTransactionIsolation(isolationLevel); + } + finally + { + unlock(); + } + } - public void releaseSavepoint(Savepoint savepoint) throws SQLException - { - lock(); - try - { - checkTransaction(); - try - { - mc.getConnection().releaseSavepoint(savepoint); - } - catch (Throwable t) - { - throw checkException(t); - } - } - finally - { - unlock(); - } - } + public int getTransactionIsolation() throws SQLException + { + lock(); + try + { + checkStatus(); + return mc.getJdbcTransactionIsolation(); + } + finally + { + unlock(); + } + } - public Connection getUnderlyingConnection() throws SQLException - { - lock(); - try - { - checkTransaction(); - return mc.getConnection(); - } - finally - { - unlock(); - } - } + public SQLWarning getWarnings() throws SQLException + { + lock(); + try + { + checkTransaction(); + try + { + return mc.getConnection().getWarnings(); + } + catch (Throwable t) + { + throw checkException(t); + } + } + finally + { + unlock(); + } + } - protected Connection getWrappedObject() throws SQLException - { - return getUnderlyingConnection(); - } + public void clearWarnings() throws SQLException + { + lock(); + try + { + checkTransaction(); + try + { + mc.getConnection().clearWarnings(); + } + catch (Throwable t) + { + throw checkException(t); + } + } + finally + { + unlock(); + } + } - protected void checkTransaction() throws SQLException - { - checkStatus(); - mc.checkTransaction(); - } + @SuppressWarnings("unchecked") + public Map getTypeMap() throws SQLException + { + lock(); + try + { + checkTransaction(); + try + { + return mc.getConnection().getTypeMap(); + } + catch (Throwable t) + { + throw checkException(t); + } + } + finally + { + unlock(); + } + } - void checkTransactionActive() throws SQLException - { - if (dataSource == null) - return; - dataSource.checkTransactionActive(); - } + @SuppressWarnings("unchecked") + public void setTypeMap(Map typeMap) throws SQLException + { + lock(); + try + { + checkTransaction(); + try + { + mc.getConnection().setTypeMap(typeMap); + } + catch (Throwable t) + { + throw checkException(t); + } + } + finally + { + unlock(); + } + } - /** - * The checkStatus method checks that the handle has not been closed and - * that it is associated with a managed connection. - * - * @exception SQLException if an error occurs - */ - protected void checkStatus() throws SQLException - { - if (closed) - throw new SQLException("Connection handle has been closed and is unusable"); - if (mc == null) - throw new SQLException("Connection handle is not currently associated with a ManagedConnection"); - checkTransactionActive(); - } + public void setHoldability(int holdability) throws SQLException + { + lock(); + try + { + checkTransaction(); + try + { + mc.getConnection().setHoldability(holdability); + } + catch (Throwable t) + { + throw checkException(t); + } + } + finally + { + unlock(); + } + } - /** - * The base checkException method rethrows the supplied exception, informing - * the ManagedConnection of the error. Subclasses may override this to - * filter exceptions based on their severity. - * - * @param t a throwable - * @return the sql exception - * @exception SQLException if an error occurs - */ - protected SQLException checkException(Throwable t) throws SQLException - { - Throwable result = null; - if (t instanceof AbstractMethodError) - { - t = new SQLFeatureNotSupportedException("Method is not implemented by JDBC driver", t); - } + public int getHoldability() throws SQLException + { + lock(); + try + { + checkTransaction(); + try + { + return mc.getConnection().getHoldability(); + } + catch (Throwable t) + { + throw checkException(t); + } + } + finally + { + unlock(); + } + } - if (mc != null) - result = mc.connectionError(t); + public Savepoint setSavepoint() throws SQLException + { + lock(); + try + { + checkTransaction(); + try + { + return mc.getConnection().setSavepoint(); + } + catch (Throwable t) + { + throw checkException(t); + } + } + finally + { + unlock(); + } + } - if (result instanceof SQLException) - { - throw (SQLException) result; - } - else - { - throw new NestedSQLException("Error", result); - } - - } + public Savepoint setSavepoint(String name) throws SQLException + { + lock(); + try + { + checkTransaction(); + try + { + return mc.getConnection().setSavepoint(name); + } + catch (Throwable t) + { + throw checkException(t); + } + } + finally + { + unlock(); + } + } - int getTrackStatements() - { - return trackStatements; - } - - void registerStatement(WrappedStatement ws) - { - if (trackStatements == BaseWrapperManagedConnectionFactory.TRACK_STATEMENTS_FALSE_INT) - return; - - synchronized (this) - { - if (statements == null) - statements = new HashMap(); - - if (trackStatements == BaseWrapperManagedConnectionFactory.TRACK_STATEMENTS_TRUE_INT) - statements.put(ws, new Throwable("STACKTRACE")); - else - statements.put(ws, null); - } - } + public void releaseSavepoint(Savepoint savepoint) throws SQLException + { + lock(); + try + { + checkTransaction(); + try + { + mc.getConnection().releaseSavepoint(savepoint); + } + catch (Throwable t) + { + throw checkException(t); + } + } + finally + { + unlock(); + } + } - void unregisterStatement(WrappedStatement ws) - { - if (trackStatements == BaseWrapperManagedConnectionFactory.TRACK_STATEMENTS_FALSE_INT) - return; - synchronized (this) - { - if (statements != null) - statements.remove(ws); - } - } + public Connection getUnderlyingConnection() throws SQLException + { + lock(); + try + { + checkTransaction(); + return mc.getConnection(); + } + finally + { + unlock(); + } + } - void checkConfiguredQueryTimeout(WrappedStatement ws) throws SQLException - { - if (mc == null || dataSource == null) - return; + protected Connection getWrappedObject() throws SQLException + { + return getUnderlyingConnection(); + } - int timeout = 0; - - // Use the transaction timeout - if (mc.isTransactionQueryTimeout()) - timeout = dataSource.getTimeLeftBeforeTransactionTimeout(); - - // Look for a configured value - if (timeout <= 0) - timeout = mc.getQueryTimeout(); - - if (timeout > 0) - ws.setQueryTimeout(timeout); - } - - Logger getLogger() - { - return log; - } + protected void checkTransaction() throws SQLException + { + checkStatus(); + mc.checkTransaction(); + } + + void checkTransactionActive() throws SQLException + { + if (dataSource == null) + return; + dataSource.checkTransactionActive(); + } + + /** + * The checkStatus method checks that the handle has not been closed and + * that it is associated with a managed connection. + * + * @exception SQLException + * if an error occurs + */ + protected void checkStatus() throws SQLException + { + if (closed) + throw new SQLException("Connection handle has been closed and is unusable"); + if (mc == null) + throw new SQLException("Connection handle is not currently associated with a ManagedConnection"); + checkTransactionActive(); + } + + /** + * The base checkException method rethrows the supplied exception, informing + * the ManagedConnection of the error. Subclasses may override this to + * filter exceptions based on their severity. + * + * @param t + * a throwable + * @return the sql exception + * @exception SQLException + * if an error occurs + */ + protected SQLException checkException(Throwable t) throws SQLException + { + Throwable result = null; + if (t instanceof AbstractMethodError) + { + t = new SQLFeatureNotSupportedException("Method is not implemented by JDBC driver", t); + } + + if (mc != null) + result = mc.connectionError(t); + + if (result instanceof SQLException) + { + throw (SQLException) result; + } + else + { + throw new NestedSQLException("Error", result); + } + + } + + int getTrackStatements() + { + return trackStatements; + } + + void registerStatement(WrappedStatement ws) + { + if (trackStatements == BaseWrapperManagedConnectionFactory.TRACK_STATEMENTS_FALSE_INT) + return; + + synchronized (this) + { + if (statements == null) + statements = new HashMap(); + + if (trackStatements == BaseWrapperManagedConnectionFactory.TRACK_STATEMENTS_TRUE_INT) + statements.put(ws, new Throwable("STACKTRACE")); + else + statements.put(ws, null); + } + } + + void unregisterStatement(WrappedStatement ws) + { + if (trackStatements == BaseWrapperManagedConnectionFactory.TRACK_STATEMENTS_FALSE_INT) + return; + synchronized (this) + { + if (statements != null) + statements.remove(ws); + } + } + + void checkConfiguredQueryTimeout(WrappedStatement ws) throws SQLException + { + if (mc == null || dataSource == null) + return; + + int timeout = 0; + + // Use the transaction timeout + if (mc.isTransactionQueryTimeout()) + timeout = dataSource.getTimeLeftBeforeTransactionTimeout(); + + // Look for a configured value + if (timeout <= 0) + timeout = mc.getQueryTimeout(); + + if (timeout > 0) + ws.setQueryTimeout(timeout); + } + + Logger getLogger() + { + return log; + } } Modified: branches/JBPAPP_5_0_1_GA_JBPAPP-11214/connector/src/main/org/jboss/resource/adapter/jdbc/remote/WrapperDataSourceService.java =================================================================== --- branches/JBPAPP_5_0_1_GA_JBPAPP-11214/connector/src/main/org/jboss/resource/adapter/jdbc/remote/WrapperDataSourceService.java 2015-02-12 18:08:11 UTC (rev 114833) +++ branches/JBPAPP_5_0_1_GA_JBPAPP-11214/connector/src/main/org/jboss/resource/adapter/jdbc/remote/WrapperDataSourceService.java 2015-02-13 05:36:48 UTC (rev 114834) @@ -39,6 +39,7 @@ import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.Map; @@ -84,12 +85,12 @@ private ObjectName jmxInvokerName; private Invoker delegateInvoker; private Object theProxy; - private HashMap marshalledInvocationMapping = new HashMap(); - private HashMap connectionMap = new HashMap(); - private HashMap statementMap = new HashMap(); - private HashMap resultSetMap = new HashMap(); - private HashMap lobMap = new HashMap(); - private HashMap databaseMetaDataMap = new HashMap(); + private Map marshalledInvocationMapping = new HashMap(); + private Map connectionMap = Collections.synchronizedMap(new HashMap()); + private Map statementMap = Collections.synchronizedMap(new HashMap()); + private Map resultSetMap = Collections.synchronizedMap(new HashMap()); + private Map lobMap = Collections.synchronizedMap(new HashMap()); + private Map databaseMetaDataMap = Collections.synchronizedMap(new HashMap()); private boolean trace = log.isTraceEnabled(); protected void startService() throws Exception Modified: branches/JBPAPP_5_0_1_GA_JBPAPP-11214/connector/src/main/org/jboss/resource/adapter/jms/JmsManagedConnection.java =================================================================== --- branches/JBPAPP_5_0_1_GA_JBPAPP-11214/connector/src/main/org/jboss/resource/adapter/jms/JmsManagedConnection.java 2015-02-12 18:08:11 UTC (rev 114833) +++ branches/JBPAPP_5_0_1_GA_JBPAPP-11214/connector/src/main/org/jboss/resource/adapter/jms/JmsManagedConnection.java 2015-02-13 05:36:48 UTC (rev 114834) @@ -22,13 +22,13 @@ package org.jboss.resource.adapter.jms; import java.io.PrintWriter; +import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import java.util.Vector; import java.util.concurrent.TimeUnit; -import java.util.concurrent.locks.ReentrantLock; import javax.jms.Connection; import javax.jms.ExceptionListener; @@ -68,772 +68,821 @@ /** * Managed Connection, manages one or more JMS sessions. - * - *

Every ManagedConnection will have a physical JMSConnection under the - * hood. This may leave out several session, as specifyed in 5.5.4 Multiple - * Connection Handles. Thread safe semantics is provided - * - *

Hm. If we are to follow the example in 6.11 this will not work. We would - * have to use the SAME session. This means we will have to guard against - * concurrent access. We use a stack, and only allowes the handle at the - * top of the stack to do things. - * - *

As to transactions we some fairly hairy alternatives to handle: - * XA - we get an XA. We may now only do transaction through the - * XAResource, since a XASession MUST throw exceptions in commit etc. But - * since XA support implies LocatTransaction support, we will have to use - * the XAResource in the LocalTransaction class. - * LocalTx - we get a normal session. The LocalTransaction will then work - * against the normal session api. - * - *

An invokation of JMS MAY BE DONE in none transacted context. What do we - * do then? How much should we leave to the user??? - * - *

One possible solution is to use transactions any way, but under the hood. - * If not LocalTransaction or XA has been aquired by the container, we have - * to do the commit in send and publish. (CHECK is the container required - * to get a XA every time it uses a managed connection? No its is not, only - * at creation!) - * - *

Does this mean that a session one time may be used in a transacted env, - * and another time in a not transacted. - * - *

Maybe we could have this simple rule: - * - *

If a user is going to use non trans: + * + *

+ * Every ManagedConnection will have a physical JMSConnection under the hood. + * This may leave out several session, as specifyed in 5.5.4 Multiple Connection + * Handles. Thread safe semantics is provided + * + *

+ * Hm. If we are to follow the example in 6.11 this will not work. We would have + * to use the SAME session. This means we will have to guard against concurrent + * access. We use a stack, and only allowes the handle at the top of the stack + * to do things. + * + *

+ * As to transactions we some fairly hairy alternatives to handle: XA - we get + * an XA. We may now only do transaction through the XAResource, since a + * XASession MUST throw exceptions in commit etc. But since XA support implies + * LocatTransaction support, we will have to use the XAResource in the + * LocalTransaction class. LocalTx - we get a normal session. The + * LocalTransaction will then work against the normal session api. + * + *

+ * An invokation of JMS MAY BE DONE in none transacted context. What do we do + * then? How much should we leave to the user??? + * + *

+ * One possible solution is to use transactions any way, but under the hood. If + * not LocalTransaction or XA has been aquired by the container, we have to do + * the commit in send and publish. (CHECK is the container required to get a XA + * every time it uses a managed connection? No its is not, only at creation!) + * + *

+ * Does this mean that a session one time may be used in a transacted env, and + * another time in a not transacted. + * + *

+ * Maybe we could have this simple rule: + * + *

+ * If a user is going to use non trans: *

    *
  • mark that i ra deployment descr *
  • Use a JmsProviderAdapter with non XA factorys *
  • Mark session as non transacted (this defeats the purpose of specifying *
  • trans attrinbutes in deploy descr NOT GOOD *
- * - *

From the JMS tutorial: - * "When you create a session in an enterprise bean, the container ignores - * the arguments you specify, because it manages all transactional - * properties for enterprise beans." - * - *

And further: - * "You do not specify a message acknowledgment mode when you create a - * message-driven bean that uses container-managed transactions. The - * container handles acknowledgment automatically." - * - *

On Session or Connection: - *

From Tutorial: - * "A JMS API resource is a JMS API connection or a JMS API session." But in - * the J2EE spec only connection is considered a resource. - * - *

Not resolved: connectionErrorOccurred: it is verry hard to know from the - * exceptions thrown if it is a connection error. Should we register an - * ExceptionListener and mark al handles as errounous? And then let them - * send the event and throw an exception? - * + * + *

+ * From the JMS tutorial: "When you create a session in an enterprise bean, the + * container ignores the arguments you specify, because it manages all + * transactional properties for enterprise beans." + * + *

+ * And further: "You do not specify a message acknowledgment mode when you + * create a message-driven bean that uses container-managed transactions. The + * container handles acknowledgment automatically." + * + *

+ * On Session or Connection: + *

+ * From Tutorial: + * "A JMS API resource is a JMS API connection or a JMS API session." But in the + * J2EE spec only connection is considered a resource. + * + *

+ * Not resolved: connectionErrorOccurred: it is verry hard to know from the + * exceptions thrown if it is a connection error. Should we register an + * ExceptionListener and mark al handles as errounous? And then let them send + * the event and throw an exception? + * * @author Peter Antman. * @author Jason Dillon * @author Adrian Brock * @version $Revision$ */ -public class JmsManagedConnection - implements ManagedConnection, ExceptionListener +public class JmsManagedConnection implements ManagedConnection, ExceptionListener { - private static final Logger log = Logger.getLogger(JmsManagedConnection.class); + private static final Logger log = Logger.getLogger(JmsManagedConnection.class); - private JmsManagedConnectionFactory mcf; - private JmsConnectionRequestInfo info; - private String user; - private String pwd; - private boolean isDestroyed; + private JmsManagedConnectionFactory mcf; + private JmsConnectionRequestInfo info; + private String user; + private String pwd; + private boolean isDestroyed; - private ReentrantLock lock = new ReentrantLock(); - - // Physical JMS connection stuff - private Connection con; - private Session session; - private TopicSession topicSession; - private QueueSession queueSession; - private XASession xaSession; - private XATopicSession xaTopicSession; - private XAQueueSession xaQueueSession; - private XAResource xaResource; - private boolean xaTransacted; + private ReentrantLock lock = new ReentrantLock(true); - /** Holds all current JmsSession handles. */ - private Set handles = Collections.synchronizedSet(new HashSet()); + // Physical JMS connection stuff + private Connection con; + private Session session; + private TopicSession topicSession; + private QueueSession queueSession; + private XASession xaSession; + private XATopicSession xaTopicSession; + private XAQueueSession xaQueueSession; + private XAResource xaResource; + private boolean xaTransacted; - /** The event listeners */ - private Vector listeners = new Vector(); + /** Holds all current JmsSession handles. */ + private Set handles = Collections.synchronizedSet(new HashSet()); - /** - * Create a JmsManagedConnection. - * - * @param mcf - * @param info - * @param user - * @param pwd - * - * @throws ResourceException - */ - public JmsManagedConnection(final JmsManagedConnectionFactory mcf, - final ConnectionRequestInfo info, - final String user, - final String pwd) - throws ResourceException - { - this.mcf = mcf; + /** The event listeners */ + private Vector listeners = new Vector(); - // seem like its asking for trouble here - this.info = (JmsConnectionRequestInfo)info; - this.user = user; - this.pwd = pwd; + /** + * Create a JmsManagedConnection. + * + * @param mcf + * @param info + * @param user + * @param pwd + * + * @throws ResourceException + */ + public JmsManagedConnection(final JmsManagedConnectionFactory mcf, final ConnectionRequestInfo info, final String user, final String pwd) + throws ResourceException + { + this.mcf = mcf; - try - { - setup(); - } - catch (Throwable t) - { - try - { - destroy(); - } - catch (Throwable ignored) - { - } - JBossResourceException.rethrowAsResourceException("Error during setup", t); - } - } + // seem like its asking for trouble here + this.info = (JmsConnectionRequestInfo) info; + this.user = user; + this.pwd = pwd; - //---- ManagedConnection API ---- + try + { + setup(); + } + catch (Throwable t) + { + try + { + destroy(); + } + catch (Throwable ignored) + { + } + JBossResourceException.rethrowAsResourceException("Error during setup", t); + } + } - /** - * Get the physical connection handler. - * - *

This bummer will be called in two situations: - *

    - *
  1. When a new mc has bean created and a connection is needed - *
  2. When an mc has been fetched from the pool (returned in match*) - *
- * - *

It may also be called multiple time without a cleanup, to support - * connection sharing. - * - * @param subject - * @param info - * @return A new connection object. - * - * @throws ResourceException - */ - public Object getConnection(final Subject subject, - final ConnectionRequestInfo info) - throws ResourceException - { - // Check user first - JmsCred cred = JmsCred.getJmsCred(mcf,subject,info); + // ---- ManagedConnection API ---- - // Null users are allowed! - if (user != null && !user.equals(cred.name)) - throw new SecurityException - ("Password credentials not the same, reauthentication not allowed"); - if (cred.name != null && user == null) { - throw new SecurityException - ("Password credentials not the same, reauthentication not allowed"); - } + /** + * Get the physical connection handler. + * + *

+ * This bummer will be called in two situations: + *

    + *
  1. When a new mc has bean created and a connection is needed + *
  2. When an mc has been fetched from the pool (returned in match*) + *
+ * + *

+ * It may also be called multiple time without a cleanup, to support + * connection sharing. + * + * @param subject + * @param info + * @return A new connection object. + * + * @throws ResourceException + */ + public Object getConnection(final Subject subject, final ConnectionRequestInfo info) throws ResourceException + { + // Check user first + JmsCred cred = JmsCred.getJmsCred(mcf, subject, info); - user = cred.name; // Basically meaningless + // Null users are allowed! + if (user != null && !user.equals(cred.name)) + throw new SecurityException("Password credentials not the same, reauthentication not allowed"); + if (cred.name != null && user == null) + { + throw new SecurityException("Password credentials not the same, reauthentication not allowed"); + } - if (isDestroyed) - throw new IllegalStateException("ManagedConnection already destroyd"); + user = cred.name; // Basically meaningless - // Create a handle - JmsSession handle = new JmsSession(this, (JmsConnectionRequestInfo) info); - handles.add(handle); - return handle; - } + if (isDestroyed) + throw new IllegalStateException("ManagedConnection already destroyd"); - /** - * Destroy all handles. - * - * @throws ResourceException Failed to close one or more handles. - */ - private void destroyHandles() throws ResourceException - { - try - { - if (con != null) - con.stop(); - } - catch (Throwable t) - { - log.trace("Ignored error stopping connection", t); - } - - Iterator iter = handles.iterator(); - while (iter.hasNext()) - ((JmsSession)iter.next()).destroy(); + // Create a handle + JmsSession handle = new JmsSession(this, (JmsConnectionRequestInfo) info); + handles.add(handle); + return handle; + } - // clear the handles map - handles.clear(); - } + /** + * Destroy all handles. + * + * @throws ResourceException + * Failed to close one or more handles. + */ + private void destroyHandles() throws ResourceException + { + try + { + if (con != null) + con.stop(); + } + catch (Throwable t) + { + log.trace("Ignored error stopping connection", t); + } - /** - * Destroy the physical connection. - * - * @throws ResourceException Could not property close the session and - * connection. - */ - public void destroy() throws ResourceException - { - if (isDestroyed || con == null) return; + Iterator iter = handles.iterator(); + while (iter.hasNext()) + ((JmsSession) iter.next()).destroy(); - isDestroyed = true; + // clear the handles map + handles.clear(); + } - try - { - con.setExceptionListener(null); - } - catch (JMSException e) - { - log.debug("Error unsetting the exception listener " + this, e); - } - - // destory handles - destroyHandles(); - - try - { - // Close session and connection - try - { - if (info.getType() == JmsConnectionFactory.TOPIC) - { - if (topicSession != null) - topicSession.close(); - if (xaTransacted && xaTopicSession != null) { - xaTopicSession.close(); - } - } - else if (info.getType() == JmsConnectionFactory.QUEUE) - { - if (queueSession != null) - queueSession.close(); - if (xaTransacted && xaQueueSession != null) - xaQueueSession.close(); - } - else - { - if (session != null) - session.close(); - if (xaTransacted && xaSession != null) - xaSession.close(); - } - } - catch (JMSException e) - { - log.debug("Error closing session " +this, e); - } - con.close(); - } - catch (Throwable e) - { - throw new JBossResourceException - ("Could not properly close the session and connection", e); - } - } + /** + * Destroy the physical connection. + * + * @throws ResourceException + * Could not property close the session and connection. + */ + public void destroy() throws ResourceException + { + if (isDestroyed || con == null) + return; - /** - * Cleans up the, from the spec - * - The cleanup of ManagedConnection instance resets its client specific - * state. - * - * Does that mean that autentication should be redone. FIXME - */ - public void cleanup() throws ResourceException - { - if (isDestroyed) - throw new IllegalStateException("ManagedConnection already destroyed"); + isDestroyed = true; - // destory handles - destroyHandles(); + try + { + con.setExceptionListener(null); + } + catch (JMSException e) + { + log.debug("Error unsetting the exception listener " + this, e); + } - // I'm recreating the lock object when we return to the pool - // because it looks too nasty to expect the connection handle - // to unlock properly in certain race conditions - // where the dissociation of the managed connection is "random". - lock = new ReentrantLock(); - } + // destory handles + destroyHandles(); - /** - * Move a handler from one mc to this one. - * - * @param obj An object of type JmsSession. - * - * @throws ResourceException Failed to associate connection. - * @throws IllegalStateException ManagedConnection in an illegal state. - */ - public void associateConnection(final Object obj) - throws ResourceException - { - // - // Should we check auth, ie user and pwd? FIXME - // + try + { + // Close session and connection + try + { + if (info.getType() == JmsConnectionFactory.TOPIC) + { + if (topicSession != null) + topicSession.close(); + if (xaTransacted && xaTopicSession != null) + { + xaTopicSession.close(); + } + } + else if (info.getType() == JmsConnectionFactory.QUEUE) + { + if (queueSession != null) + queueSession.close(); + if (xaTransacted && xaQueueSession != null) + xaQueueSession.close(); + } + else + { + if (session != null) + session.close(); + if (xaTransacted && xaSession != null) + xaSession.close(); + } + } + catch (JMSException e) + { + log.debug("Error closing session " + this, e); + } + con.close(); + } + catch (Throwable e) + { + throw new JBossResourceException("Could not properly close the session and connection", e); + } + } - if (!isDestroyed && obj instanceof JmsSession) - { - JmsSession h = (JmsSession)obj; - h.setManagedConnection(this); - handles.add(h); - } - else - throw new IllegalStateException - ("ManagedConnection in an illegal state"); - } + /** + * Cleans up the, from the spec - The cleanup of ManagedConnection instance + * resets its client specific state. + * + * Does that mean that autentication should be redone. FIXME + */ + public void cleanup() throws ResourceException + { + if (isDestroyed) + throw new IllegalStateException("ManagedConnection already destroyed"); - protected void lock() - { - lock.lock(); - } + // destory handles + destroyHandles(); - protected void tryLock() throws JMSException - { - int tryLock = mcf.getUseTryLock(); - if (tryLock <= 0) - { - lock(); - return; - } - try - { - if (lock.tryLock(tryLock, TimeUnit.SECONDS) == false) - throw new ResourceAllocationException("Unable to obtain lock in " + tryLock + " seconds: " + this); - } - catch (InterruptedException e) - { - throw new ResourceAllocationException("Interrupted attempting lock: " + this); - } - } - - protected void unlock() - { - lock.unlock(); - } + boolean isActive = false; - /** - * Add a connection event listener. - * - * @param l The connection event listener to be added. - */ - public void addConnectionEventListener(final ConnectionEventListener l) - { - listeners.addElement(l); + if (lock.hasQueuedThreads()) + { + Collection threads = lock.getQueuedThreads(); + for (Thread thread : threads) + { + Throwable t = new Throwable("Thread waiting for lock during cleanup"); + t.setStackTrace(thread.getStackTrace()); - if (log.isTraceEnabled()) - log.trace("ConnectionEvent listener added: " + l); - } + log.warn(t.getMessage(), t); + } + isActive = true; + } - /** - * Remove a connection event listener. - * - * @param l The connection event listener to be removed. - */ - public void removeConnectionEventListener(final ConnectionEventListener l) - { - listeners.removeElement(l); - } + if (lock.isLocked()) + { + Throwable t = new Throwable("Lock owned during cleanup"); + t.setStackTrace(lock.getOwner().getStackTrace()); - /** - * Get the XAResource for the connection. - * - * @return The XAResource for the connection. - * - * @throws ResourceException XA transaction not supported - */ - public XAResource getXAResource() throws ResourceException - { - // - // Spec says a mc must allways return the same XA resource, - // so we cache it. - // - if (!xaTransacted) - throw new NotSupportedException("Non XA transaction not supported"); + log.warn(t.getMessage(), t); - if (xaResource == null) - { - if (info.getType() == JmsConnectionFactory.TOPIC) - xaResource = xaTopicSession.getXAResource(); - else if (info.getType() == JmsConnectionFactory.QUEUE) - xaResource = xaQueueSession.getXAResource(); - else - xaResource = xaSession.getXAResource(); - } + isActive = true; + } - if (log.isTraceEnabled()) - log.trace("XAResource=" + xaResource); + if (isActive) + { + // There are active lock - make sure that the JCA container kills + // this handle by throwing an exception - xaResource = new JmsXAResource(this, xaResource); - return xaResource; - } + throw new ResourceException("Still active locks for " + this); + } + } - /** - * Get the location transaction for the connection. - * - * @return The local transaction for the connection. - * - * @throws ResourceException - */ - public LocalTransaction getLocalTransaction() throws ResourceException - { - LocalTransaction tx = new JmsLocalTransaction(this); - if (log.isTraceEnabled()) - log.trace("LocalTransaction=" + tx); - return tx; - } + /** + * Move a handler from one mc to this one. + * + * @param obj + * An object of type JmsSession. + * + * @throws ResourceException + * Failed to associate connection. + * @throws IllegalStateException + * ManagedConnection in an illegal state. + */ + public void associateConnection(final Object obj) throws ResourceException + { + // + // Should we check auth, ie user and pwd? FIXME + // - /** - * Get the meta data for the connection. - * - * @return The meta data for the connection. - * - * @throws ResourceException - * @throws IllegalStateException ManagedConnection already destroyed. - */ - public ManagedConnectionMetaData getMetaData() throws ResourceException - { - if (isDestroyed) - throw new IllegalStateException("ManagedConnection already destroyd"); + if (!isDestroyed && obj instanceof JmsSession) + { + JmsSession h = (JmsSession) obj; + h.setManagedConnection(this); + handles.add(h); + } + else + throw new IllegalStateException("ManagedConnection in an illegal state"); + } - return new JmsMetaData(this); - } + protected void lock() + { + lock.lock(); + } - /** - * Set the log writer for this connection. - * - * @param out The log writer for this connection. - * - * @throws ResourceException - */ - public void setLogWriter(final PrintWriter out) throws ResourceException - { - // - // jason: screw the logWriter stuff for now it sucks ass - // - } + protected void tryLock() throws JMSException + { + int tryLock = mcf.getUseTryLock(); + if (tryLock <= 0) + { + lock(); + return; + } + try + { + if (lock.tryLock(tryLock, TimeUnit.SECONDS) == false) + throw new ResourceAllocationException("Unable to obtain lock in " + tryLock + " seconds: " + this); + } + catch (InterruptedException e) + { + throw new ResourceAllocationException("Interrupted attempting lock: " + this); + } + } - /** - * Get the log writer for this connection. - * - * @return Always null - */ - public PrintWriter getLogWriter() throws ResourceException - { - // - // jason: screw the logWriter stuff for now it sucks ass - // + protected void unlock() + { + if (lock.isLocked()) + { + lock.unlock(); + } + else + { + log.warn("Owner is null"); + Throwable t = new Throwable("Thread trying to unlock"); + t.setStackTrace(Thread.currentThread().getStackTrace()); - return null; - } + log.warn(t.getMessage(), t); + } + } - // --- Exception listener implementation - - public void onException(JMSException exception) - { - if (isDestroyed) - { - if (log.isTraceEnabled()) - log.trace("Ignoring error on already destroyed connection " + this, exception); - return; - } + /** + * Add a connection event listener. + * + * @param l + * The connection event listener to be added. + */ + public void addConnectionEventListener(final ConnectionEventListener l) + { + listeners.addElement(l); - log.warn("Handling jms exception failure: " + this, exception); + if (log.isTraceEnabled()) + log.trace("ConnectionEvent listener added: " + l); + } - try - { - con.setExceptionListener(null); - } - catch (JMSException e) - { - log.debug("Unable to unset exception listener", e); - } - - ConnectionEvent event = new ConnectionEvent(this, ConnectionEvent.CONNECTION_ERROR_OCCURRED, exception); - sendEvent(event); - } - - // --- Api to JmsSession + /** + * Remove a connection event listener. + * + * @param l + * The connection event listener to be removed. + */ + public void removeConnectionEventListener(final ConnectionEventListener l) + { + listeners.removeElement(l); + } - /** - * Get the session for this connection. - * - * @return Either a topic or queue connection. - */ - protected Session getSession() - { - if (info.getType() == JmsConnectionFactory.TOPIC) - return topicSession; - else if (info.getType() == JmsConnectionFactory.QUEUE) - return queueSession; - else - return session; - } + /** + * Get the XAResource for the connection. + * + * @return The XAResource for the connection. + * + * @throws ResourceException + * XA transaction not supported + */ + public XAResource getXAResource() throws ResourceException + { + // + // Spec says a mc must allways return the same XA resource, + // so we cache it. + // + if (!xaTransacted) + throw new NotSupportedException("Non XA transaction not supported"); - /** - * Send an event. - * - * @param event The event to send. - */ - protected void sendEvent(final ConnectionEvent event) - { - int type = event.getId(); + if (xaResource == null) + { + if (info.getType() == JmsConnectionFactory.TOPIC) + xaResource = xaTopicSession.getXAResource(); + else if (info.getType() == JmsConnectionFactory.QUEUE) + xaResource = xaQueueSession.getXAResource(); + else + xaResource = xaSession.getXAResource(); + } - if (log.isTraceEnabled()) - log.trace("Sending connection event: " + type); + if (log.isTraceEnabled()) + log.trace("XAResource=" + xaResource); - // convert to an array to avoid concurrent modification exceptions - ConnectionEventListener[] list = - (ConnectionEventListener[])listeners.toArray(new ConnectionEventListener[listeners.size()]); + xaResource = new JmsXAResource(this, xaResource); + return xaResource; + } - for (int i=0; iJmsSession. - * - * @param mc The managed connection for this session. - */ - public JmsSession(final JmsManagedConnection mc, JmsConnectionRequestInfo info) - { - this.mc = mc; - this.info = info; - if (trace) - log.trace("new JmsSession " + this + " mc=" + mc + " cri=" + info); - } + private int lockCount; - public void setJmsSessionFactory(JmsSessionFactoryImpl sf) - { - this.sf = sf; - } - - protected void lock() throws JMSException - { - JmsManagedConnection mc = this.mc; - if (mc != null) - mc.tryLock(); - else - throw new IllegalStateException("Connection is not associated with a managed connection. " + this); - } + /** The connection request info */ + private JmsConnectionRequestInfo info; - protected void unlock() - { - JmsManagedConnection mc = this.mc; - if (mc != null) - mc.unlock(); - // We recreate the lock when returned to the pool - // so missing the unlock after disassociation is not important - } - - /** - * Ensure that the session is opened. - * - * @return The session - * - * @throws IllegalStateException The session is closed - */ - Session getSession() throws JMSException - { - // ensure that the connection is opened - if (mc == null) - throw new IllegalStateException("The session is closed"); - - checkTransactionActive(); - - Session session = mc.getSession(); - if (trace) - log.trace("getSession " + session + " for " + this); - return session; - } + /** The session factory for this session */ + private JmsSessionFactoryImpl sf; - void checkTransactionActive() throws IllegalStateException - { - if (sf != null) - sf.checkTransactionActive(); - } - - // ---- Session API + /** The message consumers */ + private HashSet consumers = new HashSet(); - public BytesMessage createBytesMessage() throws JMSException - { - Session session = getSession(); - if (trace) - log.trace("createBytesMessage" + session); - return session.createBytesMessage(); - } + /** The message producers */ + private HashSet producers = new HashSet(); - public MapMessage createMapMessage() throws JMSException - { - Session session = getSession(); - if (trace) - log.trace("createMapMessage" + session); - return session.createMapMessage(); - } + /** Whether trace is enabled */ + private boolean trace = log.isTraceEnabled(); - public Message createMessage() throws JMSException - { - Session session = getSession(); - if (trace) - log.trace("createMessage" + session); - return session.createMessage(); - } + /** + * Construct a JmsSession. + * + * @param mc + * The managed connection for this session. + */ + public JmsSession(final JmsManagedConnection mc, JmsConnectionRequestInfo info) + { + this.mc = mc; + this.lockedMC = null; + this.lockCount = 0; + this.info = info; + if (trace) + log.trace("new JmsSession " + this + " mc=" + mc + " cri=" + info); + } - public ObjectMessage createObjectMessage() throws JMSException - { - Session session = getSession(); - if (trace) - log.trace("createObjectMessage" + session); - return session.createObjectMessage(); - } + public void setJmsSessionFactory(JmsSessionFactoryImpl sf) + { + this.sf = sf; + } - public ObjectMessage createObjectMessage(Serializable object) throws JMSException - { - Session session = getSession(); - if (trace) - log.trace("createObjectMessage(Object)" + session); - return session.createObjectMessage(object); - } + protected void lock() throws JMSException + { + JmsManagedConnection mc = this.mc; + if (mc != null) + { + mc.tryLock(); - public StreamMessage createStreamMessage() throws JMSException - { - Session session = getSession(); - if (trace) - log.trace("createStreamMessage" + session); - return session.createStreamMessage(); - } + if (lockedMC == null) + lockedMC = mc; - public TextMessage createTextMessage() throws JMSException - { - Session session = getSession(); - if (trace) - log.trace("createTextMessage" + session); - return session.createTextMessage(); - } + lockCount++; + } + else + throw new IllegalStateException("Connection is not associated with a managed connection. " + this); + } - public TextMessage createTextMessage(String string) throws JMSException - { - Session session = getSession(); - if (trace) - log.trace("createTextMessage(String)" + session); - return session.createTextMessage(string); - } + protected void unlock() + { + JmsManagedConnection mc = this.lockedMC; + if (--lockCount == 0) + lockedMC = null; + if (mc != null) + mc.unlock(); + } - public boolean getTransacted() throws JMSException - { - getSession(); // check closed - return info.isTransacted(); - } + /** + * Ensure that the session is opened. + * + * @return The session + * + * @throws IllegalStateException + * The session is closed + */ + Session getSession() throws JMSException + { + // ensure that the connection is opened + if (mc == null) + throw new IllegalStateException("The session is closed"); - /** - * Always throws an Exception. - * - * @throws IllegalStateException Method not allowed. - */ - public MessageListener getMessageListener() throws JMSException - { - throw new IllegalStateException("Method not allowed"); - } + checkTransactionActive(); - /** - * Always throws an Exception. - * - * @throws IllegalStateException Method not allowed. - */ - public void setMessageListener(MessageListener listener) throws JMSException - { - throw new IllegalStateException("Method not allowed"); - } + Session session = mc.getSession(); + if (trace) + log.trace("getSession " + session + " for " + this); + return session; + } - /** - * Always throws an Error. - * - * @throws Error Method not allowed. - */ - public void run() - { - // should this really throw an Error? - throw new Error("Method not allowed"); - } + void checkTransactionActive() throws IllegalStateException + { + if (sf != null) + sf.checkTransactionActive(); + } - /** - * Closes the session. Sends a ConnectionEvent.CONNECTION_CLOSED to the - * managed connection. - * - * @throws JMSException Failed to close session. - */ - public void close() throws JMSException - { - sf.closeSession(this); - closeSession(); - } + // ---- Session API - // FIXME - is this really OK, probably not - public void commit() throws JMSException - { - lock(); - try - { - Session session = getSession(); - if (info.isTransacted() == false) - throw new IllegalStateException("Session is not transacted"); - if (trace) - log.trace("Commit session " + this); - session.commit(); - } - finally - { - unlock(); - } - } + public BytesMessage createBytesMessage() throws JMSException + { + Session session = getSession(); + if (trace) + log.trace("createBytesMessage" + session); + return session.createBytesMessage(); + } - public void rollback() throws JMSException - { - lock(); - try - { - Session session = getSession(); - if (info.isTransacted() == false) - throw new IllegalStateException("Session is not transacted"); - if (trace) - log.trace("Rollback session " + this); - session.rollback(); - } - finally - { - unlock(); - } - } + public MapMessage createMapMessage() throws JMSException + { + Session session = getSession(); + if (trace) + log.trace("createMapMessage" + session); + return session.createMapMessage(); + } - public void recover() throws JMSException - { - lock(); - try - { - Session session = getSession(); - if (info.isTransacted()) - throw new IllegalStateException("Session is transacted"); - if (trace) - log.trace("Recover session " + this); - session.recover(); - } - finally - { - unlock(); - } - } + public Message createMessage() throws JMSException + { + Session session = getSession(); + if (trace) + log.trace("createMessage" + session); + return session.createMessage(); + } - // --- TopicSession API + public ObjectMessage createObjectMessage() throws JMSException + { + Session session = getSession(); + if (trace) + log.trace("createObjectMessage" + session); + return session.createObjectMessage(); + } - public Topic createTopic(String topicName) throws JMSException - { - if(info.getType() == JmsConnectionFactory.QUEUE) - { - throw new IllegalStateException("Cannot create topic for javax.jms.QueueSession"); - } + public ObjectMessage createObjectMessage(Serializable object) throws JMSException + { + Session session = getSession(); + if (trace) + log.trace("createObjectMessage(Object)" + session); + return session.createObjectMessage(object); + } - Session session = getSession(); - if (trace) - log.trace("createTopic " + session + " topicName=" + topicName); - Topic result = session.createTopic(topicName); - if (trace) - log.trace("createdTopic " + session + " topic=" + result); - return result; - } + public StreamMessage createStreamMessage() throws JMSException + { + Session session = getSession(); + if (trace) + log.trace("createStreamMessage" + session); + return session.createStreamMessage(); + } - public TopicSubscriber createSubscriber(Topic topic) throws JMSException - { - lock(); - try - { - TopicSession session = getTopicSession(); - if (trace) - log.trace("createSubscriber " + session + " topic=" + topic); - TopicSubscriber result = session.createSubscriber(topic); - result = new JmsTopicSubscriber(result, this); - if (trace) - log.trace("createdSubscriber " + session + " JmsTopicSubscriber=" + result); - addConsumer(result); - return result; - } - finally - { - unlock(); - } - } + public TextMessage createTextMessage() throws JMSException + { + Session session = getSession(); + if (trace) + log.trace("createTextMessage" + session); + return session.createTextMessage(); + } - public TopicSubscriber createSubscriber(Topic topic, String messageSelector, boolean noLocal) throws JMSException - { - lock(); - try - { - TopicSession session = getTopicSession(); - if (trace) - log.trace("createSubscriber " + session + " topic=" + topic + " selector=" + messageSelector + " noLocal=" + noLocal); - TopicSubscriber result = session.createSubscriber(topic, messageSelector, noLocal); - result = new JmsTopicSubscriber(result, this); - if (trace) - log.trace("createdSubscriber " + session + " JmsTopicSubscriber=" + result); - addConsumer(result); - return result; - } - finally - { - unlock(); - } - } + public TextMessage createTextMessage(String string) throws JMSException + { + Session session = getSession(); + if (trace) + log.trace("createTextMessage(String)" + session); + return session.createTextMessage(string); + } - public TopicSubscriber createDurableSubscriber(Topic topic, String name) throws JMSException - { - if(info.getType() == JmsConnectionFactory.QUEUE) - { - throw new IllegalStateException("Cannot create durable subscriber from javax.jms.QueueSession"); - } - - lock(); - try - { - Session session = getSession(); - if (trace) - log.trace("createDurableSubscriber " + session + " topic=" + topic + " name=" + name); - TopicSubscriber result = session.createDurableSubscriber(topic, name); - result = new JmsTopicSubscriber(result, this); - if (trace) - log.trace("createdDurableSubscriber " + session + " JmsTopicSubscriber=" + result); - addConsumer(result); - return result; - } - finally - { - unlock(); - } - } + public boolean getTransacted() throws JMSException + { + getSession(); // check closed + return info.isTransacted(); + } - public TopicSubscriber createDurableSubscriber(Topic topic, String name, String messageSelector, boolean noLocal) - throws JMSException - { - lock(); - try - { - Session session = getSession(); - if (trace) - log.trace("createDurableSubscriber " + session + " topic=" + topic + " name=" + name + " selector=" + messageSelector + " noLocal=" + noLocal); - TopicSubscriber result = session.createDurableSubscriber(topic, name, messageSelector, noLocal); - result = new JmsTopicSubscriber(result, this); - if (trace) - log.trace("createdDurableSubscriber " + session + " JmsTopicSubscriber=" + result); - addConsumer(result); - return result; - } - finally - { - unlock(); - } - } + /** + * Always throws an Exception. + * + * @throws IllegalStateException + * Method not allowed. + */ + public MessageListener getMessageListener() throws JMSException + { + throw new IllegalStateException("Method not allowed"); + } - public TopicPublisher createPublisher(Topic topic) throws JMSException - { - lock(); - try - { - TopicSession session = getTopicSession(); - if (trace) - log.trace("createPublisher " + session + " topic=" + topic); - TopicPublisher result = session.createPublisher(topic); - result = new JmsTopicPublisher(result, this); - if (trace) - log.trace("createdPublisher " + session + " publisher=" + result); - addProducer(result); - return result; - } - finally - { - unlock(); - } - } + /** + * Always throws an Exception. + * + * @throws IllegalStateException + * Method not allowed. + */ + public void setMessageListener(MessageListener listener) throws JMSException + { + throw new IllegalStateException("Method not allowed"); + } - public TemporaryTopic createTemporaryTopic() throws JMSException - { - if(info.getType() == JmsConnectionFactory.QUEUE) - { - throw new IllegalStateException("Cannot create temporary topic for javax.jms.QueueSession"); - } - - lock(); - try - { - Session session = getSession(); - if (trace) - log.trace("createTemporaryTopic " + session); - TemporaryTopic temp = session.createTemporaryTopic(); - if (trace) - log.trace("createdTemporaryTopic " + session + " temp=" + temp); - sf.addTemporaryTopic(temp); - return temp; - } - finally - { - unlock(); - } - } + /** + * Always throws an Error. + * + * @throws Error + * Method not allowed. + */ + public void run() + { + // should this really throw an Error? + throw new Error("Method not allowed"); + } - public void unsubscribe(String name) throws JMSException - { - if(info.getType() == JmsConnectionFactory.QUEUE) - { - throw new IllegalStateException("Cannot unsubscribe for javax.jms.QueueSession"); - } + /** + * Closes the session. Sends a ConnectionEvent.CONNECTION_CLOSED to the + * managed connection. + * + * @throws JMSException + * Failed to close session. + */ + public void close() throws JMSException + { + sf.closeSession(this); + closeSession(); + } - lock(); - try - { - Session session = getSession(); - if (trace) - log.trace("unsubscribe " + session + " name=" + name); - session.unsubscribe(name); - } - finally - { - unlock(); - } - } + // FIXME - is this really OK, probably not + public void commit() throws JMSException + { + lock(); + try + { + Session session = getSession(); + if (info.isTransacted() == false) + throw new IllegalStateException("Session is not transacted"); + if (trace) + log.trace("Commit session " + this); + session.commit(); + } + finally + { + unlock(); + } + } - //--- QueueSession API + public void rollback() throws JMSException + { + lock(); + try + { + Session session = getSession(); + if (info.isTransacted() == false) + throw new IllegalStateException("Session is not transacted"); + if (trace) + log.trace("Rollback session " + this); + session.rollback(); + } + finally + { + unlock(); + } + } - public QueueBrowser createBrowser(Queue queue) throws JMSException - { - - if(info.getType() == JmsConnectionFactory.TOPIC) - { - throw new IllegalStateException("Cannot create browser for javax.jms.TopicSession"); - - } + public void recover() throws JMSException + { + lock(); + try + { + Session session = getSession(); + if (info.isTransacted()) + throw new IllegalStateException("Session is transacted"); + if (trace) + log.trace("Recover session " + this); + session.recover(); + } + finally + { + unlock(); + } + } - Session session = getSession(); - if (trace) - log.trace("createBrowser " + session + " queue=" + queue); - QueueBrowser result = session.createBrowser(queue); - if (trace) - log.trace("createdBrowser " + session + " browser=" + result); - return result; - } + // --- TopicSession API - public QueueBrowser createBrowser(Queue queue, String messageSelector) throws JMSException - { - Session session = getSession(); - if (trace) - log.trace("createBrowser " + session + " queue=" + queue + " selector=" + messageSelector); - QueueBrowser result = session.createBrowser(queue, messageSelector); - if (trace) - log.trace("createdBrowser " + session + " browser=" + result); - return result; - } + public Topic createTopic(String topicName) throws JMSException + { + if (info.getType() == JmsConnectionFactory.QUEUE) + { + throw new IllegalStateException("Cannot create topic for javax.jms.QueueSession"); + } - public Queue createQueue(String queueName) throws JMSException - { - if(info.getType() == JmsConnectionFactory.TOPIC) - { - throw new IllegalStateException("Cannot create browser or javax.jms.TopicSession"); - - } + Session session = getSession(); + if (trace) + log.trace("createTopic " + session + " topicName=" + topicName); + Topic result = session.createTopic(topicName); + if (trace) + log.trace("createdTopic " + session + " topic=" + result); + return result; + } - Session session = getSession(); - if (trace) - log.trace("createQueue " + session + " queueName=" + queueName); - Queue result = session.createQueue(queueName); - if (trace) - log.trace("createdQueue " + session + " queue=" + result); - return result; - } + public TopicSubscriber createSubscriber(Topic topic) throws JMSException + { + lock(); + try + { + TopicSession session = getTopicSession(); + if (trace) + log.trace("createSubscriber " + session + " topic=" + topic); + TopicSubscriber result = session.createSubscriber(topic); + result = new JmsTopicSubscriber(result, this); + if (trace) + log.trace("createdSubscriber " + session + " JmsTopicSubscriber=" + result); + addConsumer(result); + return result; + } + finally + { + unlock(); + } + } - public QueueReceiver createReceiver(Queue queue) throws JMSException - { - lock(); - try - { - QueueSession session = getQueueSession(); - if (trace) - log.trace("createReceiver " + session + " queue=" + queue); - QueueReceiver result = session.createReceiver(queue); - result = new JmsQueueReceiver(result, this); - if (trace) - log.trace("createdReceiver " + session + " receiver=" + result); - addConsumer(result); - return result; - } - finally - { - unlock(); - } - } + public TopicSubscriber createSubscriber(Topic topic, String messageSelector, boolean noLocal) throws JMSException + { + lock(); + try + { + TopicSession session = getTopicSession(); + if (trace) + log.trace("createSubscriber " + session + " topic=" + topic + " selector=" + messageSelector + " noLocal=" + noLocal); + TopicSubscriber result = session.createSubscriber(topic, messageSelector, noLocal); + result = new JmsTopicSubscriber(result, this); + if (trace) + log.trace("createdSubscriber " + session + " JmsTopicSubscriber=" + result); + addConsumer(result); + return result; + } + finally + { + unlock(); + } + } - public QueueReceiver createReceiver(Queue queue, String messageSelector) throws JMSException - { - lock(); - try - { - QueueSession session = getQueueSession(); - if (trace) - log.trace("createReceiver " + session + " queue=" + queue + " selector=" + messageSelector); - QueueReceiver result = session.createReceiver(queue, messageSelector); - result = new JmsQueueReceiver(result, this); - if (trace) - log.trace("createdReceiver " + session + " receiver=" + result); - addConsumer(result); - return result; - } - finally - { - unlock(); - } - } + public TopicSubscriber createDurableSubscriber(Topic topic, String name) throws JMSException + { + if (info.getType() == JmsConnectionFactory.QUEUE) + { + throw new IllegalStateException("Cannot create durable subscriber from javax.jms.QueueSession"); + } - public QueueSender createSender(Queue queue) throws JMSException - { - lock(); - try - { - QueueSession session = getQueueSession(); - if (trace) - log.trace("createSender " + session + " queue=" + queue); - QueueSender result = session.createSender(queue); - result = new JmsQueueSender(result, this); - if (trace) - log.trace("createdSender " + session + " sender=" + result); - addProducer(result); - return result; - } - finally - { - unlock(); - } - } + lock(); + try + { + Session session = getSession(); + if (trace) + log.trace("createDurableSubscriber " + session + " topic=" + topic + " name=" + name); + TopicSubscriber result = session.createDurableSubscriber(topic, name); + result = new JmsTopicSubscriber(result, this); + if (trace) + log.trace("createdDurableSubscriber " + session + " JmsTopicSubscriber=" + result); + addConsumer(result); + return result; + } + finally + { + unlock(); + } + } - public TemporaryQueue createTemporaryQueue() throws JMSException - { - if(info.getType() == JmsConnectionFactory.TOPIC) - { - throw new IllegalStateException("Cannot create temporary queue for javax.jms.TopicSession"); - - } + public TopicSubscriber createDurableSubscriber(Topic topic, String name, String messageSelector, boolean noLocal) throws JMSException + { + lock(); + try + { + Session session = getSession(); + if (trace) + log.trace("createDurableSubscriber " + session + " topic=" + topic + " name=" + name + " selector=" + messageSelector + " noLocal=" + noLocal); + TopicSubscriber result = session.createDurableSubscriber(topic, name, messageSelector, noLocal); + result = new JmsTopicSubscriber(result, this); + if (trace) + log.trace("createdDurableSubscriber " + session + " JmsTopicSubscriber=" + result); + addConsumer(result); + return result; + } + finally + { + unlock(); + } + } - lock(); - try - { - Session session = getSession(); - if (trace) - log.trace("createTemporaryQueue " + session); - TemporaryQueue temp = session.createTemporaryQueue(); - if (trace) - log.trace("createdTemporaryQueue " + session + " temp=" + temp); - sf.addTemporaryQueue(temp); - return temp; - } - finally - { - unlock(); - } - } + public TopicPublisher createPublisher(Topic topic) throws JMSException + { + lock(); + try + { + TopicSession session = getTopicSession(); + if (trace) + log.trace("createPublisher " + session + " topic=" + topic); + TopicPublisher result = session.createPublisher(topic); + result = new JmsTopicPublisher(result, this); + if (trace) + log.trace("createdPublisher " + session + " publisher=" + result); + addProducer(result); + return result; + } + finally + { + unlock(); + } + } - // -- JMS 1.1 + public TemporaryTopic createTemporaryTopic() throws JMSException + { + if (info.getType() == JmsConnectionFactory.QUEUE) + { + throw new IllegalStateException("Cannot create temporary topic for javax.jms.QueueSession"); + } - public MessageConsumer createConsumer(Destination destination) throws JMSException - { - lock(); - try - { - Session session = getSession(); - if (trace) - log.trace("createConsumer " + session + " dest=" + destination); - MessageConsumer result = session.createConsumer(destination); - result = new JmsMessageConsumer(result, this); - if (trace) - log.trace("createdConsumer " + session + " consumer=" + result); - addConsumer(result); - return result; - } - finally - { - unlock(); - } - } + lock(); + try + { + Session session = getSession(); + if (trace) + log.trace("createTemporaryTopic " + session); + TemporaryTopic temp = session.createTemporaryTopic(); + if (trace) + log.trace("createdTemporaryTopic " + session + " temp=" + temp); + sf.addTemporaryTopic(temp); + return temp; + } + finally + { + unlock(); + } + } - public MessageConsumer createConsumer(Destination destination, String messageSelector) throws JMSException - { - lock(); - try - { - Session session = getSession(); - if (trace) - log.trace("createConsumer " + session + " dest=" + destination + " messageSelector=" + messageSelector); - MessageConsumer result = session.createConsumer(destination, messageSelector); - result = new JmsMessageConsumer(result, this); - if (trace) - log.trace("createdConsumer " + session + " consumer=" + result); - addConsumer(result); - return result; - } - finally - { - unlock(); - } - } + public void unsubscribe(String name) throws JMSException + { + if (info.getType() == JmsConnectionFactory.QUEUE) + { + throw new IllegalStateException("Cannot unsubscribe for javax.jms.QueueSession"); + } - public MessageConsumer createConsumer(Destination destination, String messageSelector, boolean noLocal) - throws JMSException - { - lock(); - try - { - Session session = getSession(); - if (trace) - log.trace("createConsumer " + session + " dest=" + destination + " messageSelector=" + messageSelector + " noLocal=" + noLocal); - MessageConsumer result = session.createConsumer(destination, messageSelector, noLocal); - result = new JmsMessageConsumer(result, this); - if (trace) - log.trace("createdConsumer " + session + " consumer=" + result); - addConsumer(result); - return result; - } - finally - { - unlock(); - } - } + lock(); + try + { + Session session = getSession(); + if (trace) + log.trace("unsubscribe " + session + " name=" + name); + session.unsubscribe(name); + } + finally + { + unlock(); + } + } - public MessageProducer createProducer(Destination destination) throws JMSException - { - lock(); - try - { - Session session = getSession(); - if (trace) - log.trace("createProducer " + session + " dest=" + destination); - MessageProducer result = getSession().createProducer(destination); - result = new JmsMessageProducer(result, this); - if (trace) - log.trace("createdProducer " + session + " producer=" + result); - addProducer(result); - return result; - } - finally - { - unlock(); - } - } + // --- QueueSession API - public int getAcknowledgeMode() throws JMSException - { - getSession(); // check closed - return info.getAcknowledgeMode(); - } + public QueueBrowser createBrowser(Queue queue) throws JMSException + { - // --- JmsManagedConnection api + if (info.getType() == JmsConnectionFactory.TOPIC) + { + throw new IllegalStateException("Cannot create browser for javax.jms.TopicSession"); - void setManagedConnection(final JmsManagedConnection mc) - { - if (this.mc != null) - this.mc.removeHandle(this); - this.mc = mc; - } + } - void destroy() - { - mc = null; - } + Session session = getSession(); + if (trace) + log.trace("createBrowser " + session + " queue=" + queue); + QueueBrowser result = session.createBrowser(queue); + if (trace) + log.trace("createdBrowser " + session + " browser=" + result); + return result; + } - void start() throws JMSException - { - if (mc != null) - mc.start(); - } + public QueueBrowser createBrowser(Queue queue, String messageSelector) throws JMSException + { + Session session = getSession(); + if (trace) + log.trace("createBrowser " + session + " queue=" + queue + " selector=" + messageSelector); + QueueBrowser result = session.createBrowser(queue, messageSelector); + if (trace) + log.trace("createdBrowser " + session + " browser=" + result); + return result; + } - void stop() throws JMSException - { - if (mc != null) - mc.stop(); - } + public Queue createQueue(String queueName) throws JMSException + { + if (info.getType() == JmsConnectionFactory.TOPIC) + { + throw new IllegalStateException("Cannot create browser or javax.jms.TopicSession"); - void checkStrict() throws JMSException - { - if (mc != null && mc.getManagedConnectionFactory().isStrict()) - throw new IllegalStateException(JmsSessionFactory.ISE); - } - - void closeSession() throws JMSException - { - if (mc != null) - { - log.trace("Closing session"); + } - try - { - mc.stop(); - } - catch (Throwable t) - { - log.trace("Error stopping managed connection", t); - } - - synchronized (consumers) - { - for (Iterator i = consumers.iterator(); i.hasNext();) - { - JmsMessageConsumer consumer = (JmsMessageConsumer) i.next(); - try - { - consumer.closeConsumer(); - } - catch (Throwable t) - { - log.trace("Error closing consumer", t); - } - i.remove(); - } - } + Session session = getSession(); + if (trace) + log.trace("createQueue " + session + " queueName=" + queueName); + Queue result = session.createQueue(queueName); + if (trace) + log.trace("createdQueue " + session + " queue=" + result); + return result; + } - synchronized (producers) - { - for (Iterator i = producers.iterator(); i.hasNext();) - { - JmsMessageProducer producer = (JmsMessageProducer) i.next(); - try - { - producer.closeProducer(); - } - catch (Throwable t) - { - log.trace("Error closing producer", t); - } - i.remove(); - } - } - - mc.removeHandle(this); - ConnectionEvent ev = new ConnectionEvent(mc, ConnectionEvent.CONNECTION_CLOSED); - ev.setConnectionHandle(this); - mc.sendEvent(ev); - mc = null; - } - } - - void addConsumer(MessageConsumer consumer) - { - synchronized (consumers) - { - consumers.add(consumer); - } - } - - void removeConsumer(MessageConsumer consumer) - { - synchronized (consumers) - { - consumers.remove(consumer); - } - } - - void addProducer(MessageProducer producer) - { - synchronized (producers) - { - producers.add(producer); - } - } - - void removeProducer(MessageProducer producer) - { - synchronized (producers) - { - producers.remove(producer); - } - } - - QueueSession getQueueSession() throws JMSException - { - Session s = getSession(); - if( !(s instanceof QueueSession) ) - throw new InvalidDestinationException("Attempting to use QueueSession methods on: "+this); - return (QueueSession) s; - } - - TopicSession getTopicSession() throws JMSException - { - Session s = getSession(); - if( !(s instanceof TopicSession) ) - throw new InvalidDestinationException("Attempting to use TopicSession methods on: "+this); - return (TopicSession) s; - } + public QueueReceiver createReceiver(Queue queue) throws JMSException + { + lock(); + try + { + QueueSession session = getQueueSession(); + if (trace) + log.trace("createReceiver " + session + " queue=" + queue); + QueueReceiver result = session.createReceiver(queue); + result = new JmsQueueReceiver(result, this); + if (trace) + log.trace("createdReceiver " + session + " receiver=" + result); + addConsumer(result); + return result; + } + finally + { + unlock(); + } + } + + public QueueReceiver createReceiver(Queue queue, String messageSelector) throws JMSException + { + lock(); + try + { + QueueSession session = getQueueSession(); + if (trace) + log.trace("createReceiver " + session + " queue=" + queue + " selector=" + messageSelector); + QueueReceiver result = session.createReceiver(queue, messageSelector); + result = new JmsQueueReceiver(result, this); + if (trace) + log.trace("createdReceiver " + session + " receiver=" + result); + addConsumer(result); + return result; + } + finally + { + unlock(); + } + } + + public QueueSender createSender(Queue queue) throws JMSException + { + lock(); + try + { + QueueSession session = getQueueSession(); + if (trace) + log.trace("createSender " + session + " queue=" + queue); + QueueSender result = session.createSender(queue); + result = new JmsQueueSender(result, this); + if (trace) + log.trace("createdSender " + session + " sender=" + result); + addProducer(result); + return result; + } + finally + { + unlock(); + } + } + + public TemporaryQueue createTemporaryQueue() throws JMSException + { + if (info.getType() == JmsConnectionFactory.TOPIC) + { + throw new IllegalStateException("Cannot create temporary queue for javax.jms.TopicSession"); + + } + + lock(); + try + { + Session session = getSession(); + if (trace) + log.trace("createTemporaryQueue " + session); + TemporaryQueue temp = session.createTemporaryQueue(); + if (trace) + log.trace("createdTemporaryQueue " + session + " temp=" + temp); + sf.addTemporaryQueue(temp); + return temp; + } + finally + { + unlock(); + } + } + + // -- JMS 1.1 + + public MessageConsumer createConsumer(Destination destination) throws JMSException + { + lock(); + try + { + Session session = getSession(); + if (trace) + log.trace("createConsumer " + session + " dest=" + destination); + MessageConsumer result = session.createConsumer(destination); + result = new JmsMessageConsumer(result, this); + if (trace) + log.trace("createdConsumer " + session + " consumer=" + result); + addConsumer(result); + return result; + } + finally + { + unlock(); + } + } + + public MessageConsumer createConsumer(Destination destination, String messageSelector) throws JMSException + { + lock(); + try + { + Session session = getSession(); + if (trace) + log.trace("createConsumer " + session + " dest=" + destination + " messageSelector=" + messageSelector); + MessageConsumer result = session.createConsumer(destination, messageSelector); + result = new JmsMessageConsumer(result, this); + if (trace) + log.trace("createdConsumer " + session + " consumer=" + result); + addConsumer(result); + return result; + } + finally + { + unlock(); + } + } + + public MessageConsumer createConsumer(Destination destination, String messageSelector, boolean noLocal) throws JMSException + { + lock(); + try + { + Session session = getSession(); + if (trace) + log.trace("createConsumer " + session + " dest=" + destination + " messageSelector=" + messageSelector + " noLocal=" + noLocal); + MessageConsumer result = session.createConsumer(destination, messageSelector, noLocal); + result = new JmsMessageConsumer(result, this); + if (trace) + log.trace("createdConsumer " + session + " consumer=" + result); + addConsumer(result); + return result; + } + finally + { + unlock(); + } + } + + public MessageProducer createProducer(Destination destination) throws JMSException + { + lock(); + try + { + Session session = getSession(); + if (trace) + log.trace("createProducer " + session + " dest=" + destination); + MessageProducer result = getSession().createProducer(destination); + result = new JmsMessageProducer(result, this); + if (trace) + log.trace("createdProducer " + session + " producer=" + result); + addProducer(result); + return result; + } + finally + { + unlock(); + } + } + + public int getAcknowledgeMode() throws JMSException + { + getSession(); // check closed + return info.getAcknowledgeMode(); + } + + // --- JmsManagedConnection api + + void setManagedConnection(final JmsManagedConnection mc) + { + if (this.mc != null) + this.mc.removeHandle(this); + this.mc = mc; + } + + void destroy() + { + mc = null; + lockedMC = null; + lockCount = 0; + } + + void start() throws JMSException + { + if (mc != null) + mc.start(); + } + + void stop() throws JMSException + { + if (mc != null) + mc.stop(); + } + + void checkStrict() throws JMSException + { + if (mc != null && mc.getManagedConnectionFactory().isStrict()) + throw new IllegalStateException(JmsSessionFactory.ISE); + } + + void closeSession() throws JMSException + { + if (mc != null) + { + log.trace("Closing session"); + + try + { + mc.stop(); + } + catch (Throwable t) + { + log.trace("Error stopping managed connection", t); + } + + synchronized (consumers) + { + for (Iterator i = consumers.iterator(); i.hasNext();) + { + JmsMessageConsumer consumer = (JmsMessageConsumer) i.next(); + try + { + consumer.closeConsumer(); + } + catch (Throwable t) + { + log.trace("Error closing consumer", t); + } + i.remove(); + } + } + + synchronized (producers) + { + for (Iterator i = producers.iterator(); i.hasNext();) + { + JmsMessageProducer producer = (JmsMessageProducer) i.next(); + try + { + producer.closeProducer(); + } + catch (Throwable t) + { + log.trace("Error closing producer", t); + } + i.remove(); + } + } + + mc.removeHandle(this); + ConnectionEvent ev = new ConnectionEvent(mc, ConnectionEvent.CONNECTION_CLOSED); + ev.setConnectionHandle(this); + mc.sendEvent(ev); + mc = null; + } + } + + void addConsumer(MessageConsumer consumer) + { + synchronized (consumers) + { + consumers.add(consumer); + } + } + + void removeConsumer(MessageConsumer consumer) + { + synchronized (consumers) + { + consumers.remove(consumer); + } + } + + void addProducer(MessageProducer producer) + { + synchronized (producers) + { + producers.add(producer); + } + } + + void removeProducer(MessageProducer producer) + { + synchronized (producers) + { + producers.remove(producer); + } + } + + QueueSession getQueueSession() throws JMSException + { + Session s = getSession(); + if (!(s instanceof QueueSession)) + throw new InvalidDestinationException("Attempting to use QueueSession methods on: " + this); + return (QueueSession) s; + } + + TopicSession getTopicSession() throws JMSException + { + Session s = getSession(); + if (!(s instanceof TopicSession)) + throw new InvalidDestinationException("Attempting to use TopicSession methods on: " + this); + return (TopicSession) s; + } } Added: branches/JBPAPP_5_0_1_GA_JBPAPP-11214/connector/src/main/org/jboss/resource/adapter/jms/ReentrantLock.java =================================================================== --- branches/JBPAPP_5_0_1_GA_JBPAPP-11214/connector/src/main/org/jboss/resource/adapter/jms/ReentrantLock.java (rev 0) +++ branches/JBPAPP_5_0_1_GA_JBPAPP-11214/connector/src/main/org/jboss/resource/adapter/jms/ReentrantLock.java 2015-02-13 05:36:48 UTC (rev 114834) @@ -0,0 +1,59 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2006, Red Hat Middleware LLC, and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.jboss.resource.adapter.jms; + +import java.util.Collection; + +/** + * ReentrantLock override + * @author Jesper Pedersen + */ +public class ReentrantLock extends java.util.concurrent.locks.ReentrantLock +{ + /** Serial version uid */ + private static final long serialVersionUID = 1L; + + /** + * Constructor + * @param fair Fair locking + */ + public ReentrantLock(boolean fair) + { + super(fair); + } + + /** + * {@inheritDoc} + */ + public Thread getOwner() + { + return super.getOwner(); + } + + /** + * {@inheritDoc} + */ + public Collection getQueuedThreads() + { + return super.getQueuedThreads(); + } +} \ No newline at end of file