📄 managedconnectionimpl.java
字号:
// $Id: ManagedConnectionImpl.java,v 1.5.2.2 2003/10/28 03:19:54 oneovthafew Exp $package net.sf.hibernate.jca;import java.io.PrintWriter;import java.sql.Connection;import java.sql.SQLException;import java.util.ArrayList;import java.util.Collection;import java.util.Iterator;import java.util.LinkedList;import javax.resource.NotSupportedException;import javax.resource.ResourceException;import javax.resource.spi.ConnectionEvent;import javax.resource.spi.ConnectionEventListener;import javax.resource.spi.ConnectionRequestInfo;import javax.resource.spi.LocalTransaction;import javax.resource.spi.ManagedConnection;import javax.resource.spi.ManagedConnectionFactory;import javax.resource.spi.ManagedConnectionMetaData;import javax.security.auth.Subject;import javax.transaction.xa.XAException;import javax.transaction.xa.XAResource;import javax.transaction.xa.Xid;import net.sf.hibernate.HibernateException;import net.sf.hibernate.Session;import net.sf.hibernate.engine.SessionImplementor;import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;/** * Implementation of JCA Managed Connection. */public class ManagedConnectionImpl implements ManagedConnection, XAResource { /* * @todo JCA 1.0, 5.10.1 * A resource adapter is required to provide support for basic error * logging and tracing by implementing the following methods: * - ManagedConnectionFactory.set/getLogWriter * - ManagedConnection.set/getLogWriter */ private static final Log log = LogFactory.getLog(ManagedConnectionImpl.class); // the factory that created this managed connection private ManagedConnectionFactoryImpl mcf; // as per JCA 1.0 spec 5.6 when this is not null then logging has been // enabled by the application server and we log to this writer private PrintWriter logWriter; // registered listeners from the application server private final Collection listeners = new ArrayList(); /** * A set (actually a linked list) of JCASessionImpl handles associated with * this managed connection. First element of the list is the currect active * handle. * * <p>It is necessary to synchronize access to this list becase * <code>dissociateConnection</code> can be called asynchronously * from a context of a different transaction.</p> */ private final LinkedList handles = new LinkedList(); // a (logical handle to) database connection private Connection connection; // Hibernate session private SessionImplementor session; ManagedConnectionImpl(final ManagedConnectionFactoryImpl mcf) { log.trace("Constructor called"); this.mcf = mcf; } /** * Creates and returns a new Hibernate Session. * * Will throw a ResourceException if the session factory * fails to create a session */ public Object getConnection( final Subject subject, final ConnectionRequestInfo connectionRequestInfo ) throws ResourceException { log.trace( "getConnection called with subject[" + subject + " ] connection request info[" + connectionRequestInfo + "]"); // make sure we have a session initializeSession(); final JCASessionImpl active = new JCASessionImpl(this); // add the session handle to the collection of handles // on this connection synchronized (handles) { handles.addFirst(active); } if ( log.isDebugEnabled() ) { log.debug( "Added session handle - " + active + " to handles now at size " + handles.size() ); } return active; } /** * Creates a session from the session factory */ private void initializeSession() throws ResourceException { // single threaded, no need to synchronize if (session == null) { initializeConnection(); session = (SessionImplementor) mcf.getSessionFactory().openSession(connection); } } /** * JDBC connection is lazy-inilialized during this call. A caller must * ensure proper thread context, i.e. context of original component * called into Hibernate session. */ private void initializeConnection() throws ResourceException { // single threaded, no need to synchronize if (connection == null) { try { connection = mcf.getDatasource().getConnection(); } catch (SQLException e) { final String message = "Cannot allocate database connection!"; throw newResourceException(message, e); } } } /** * Returns new ResourceException. */ private static ResourceException newResourceException( final String message, final Exception e ) { final ResourceException re = new ResourceException(message); re.setLinkedException(e); return re; } /** * Closes the connection to the database * * @throws ResourceException cannot close connection (with the linked exception) */ public void destroy() throws ResourceException { if ( log.isTraceEnabled() ) { log.trace("destroy called on " + this); } } /** * Cleans up connection handles so they can't be used again * But the physical connection is kept open */ public void cleanup() throws ResourceException { if ( log.isTraceEnabled() ) { log.trace("cleanup called on " + this); } // JCA 1.0, 5.5.4 // The cleanup is required to invalidate all connection // handles created using this ManagedConnection instance. synchronized (handles) { for (Iterator i = handles.iterator(); i.hasNext();) { JCASessionImpl lc = (JCASessionImpl) i.next(); lc.setManagedConnection(null); } handles.clear(); } ResourceException re = null; try { //if session is closed before transaction end it is null here if( session != null) session.close(); } catch (HibernateException e) { final String message = "Exception closing Hibernate session " + session; re = newResourceException(message, e); } finally { session = null; } try { if( connection != null) connection.close(); } catch (SQLException e) { final String message = "Exception closing database connection " + connection; re = newResourceException(message, e); } finally { connection = null; } if (re != null) { throw re; } } /** * Associates the session handle with this managed connection */ public void associateConnection(final Object object) throws ResourceException { if ( !(object instanceof JCASessionImpl) ) { throw new ResourceException( "Wrong kind of connection handle to associate " + object); } final JCASessionImpl handle = (JCASessionImpl) object; if (handle.getManagedConnextion() != this) { handle.getManagedConnextion().dissociateConnection(handle); handle.setManagedConnection(this); synchronized (handles) { handles.addFirst(handle); } } } private void dissociateConnection(final JCASessionImpl handle) { synchronized (handles) { handles.remove(handle); } } public void addConnectionEventListener(ConnectionEventListener listener) { listeners.add(listener); } public void removeConnectionEventListener(ConnectionEventListener listener) { listeners.remove(listener); } public XAResource getXAResource() throws ResourceException { return this; } public LocalTransaction getLocalTransaction() throws ResourceException { // JCA 1.0, section 6.1.10 // both LocalTransaction and XATransaction resource adapters // support local transactions // At the same time all transactions will enlist at least Hibernate // session and database connection, so support for local transactions // is really redundant. throw new NotSupportedException("LocalTransaction is not supported!"); } public ManagedConnectionMetaData getMetaData() throws ResourceException { return new MetaDataImpl(this); } public void setLogWriter(PrintWriter out) throws ResourceException { this.logWriter = out; } public PrintWriter getLogWriter() throws ResourceException { return logWriter; } // // XAResource implementation // // @todo // Currently, XAResource implementation does nothing. In the future, // in order to support JCS read-write cache it will be necessary // to implement prepare/commit/rollback protocol. // @todo JCA 6.6.2 // RM must ensure that TM invokes XAResource calls in the legal sequence, // and must return XAER_PROTO or other suitable error if the caller TM // violates the state tables (as defined in Chapter 6 of the XA // specification (refer [4]). public void commit(Xid arg0, boolean arg1) throws XAException { } public void end(Xid arg0, int arg1) throws XAException { } public void forget(Xid arg0) throws XAException { } public int getTransactionTimeout() throws XAException { return 0; } public boolean isSameRM(XAResource arg0) throws XAException { return false; } public int prepare(Xid arg0) throws XAException { return XAResource.XA_RDONLY; } public Xid[] recover(int arg0) throws XAException { return new Xid[0]; } public void rollback(Xid arg0) throws XAException { } public boolean setTransactionTimeout(int arg0) throws XAException { return false; } public void start(Xid arg0, int arg1) throws XAException { } // // package private level methods // ManagedConnectionFactory getManagedConnectionFactory() { return mcf; } void closeHandle(Session handle) { // remove the handle from the collection safely synchronized (handles) { handles.remove(handle); } // create a connection closed event and send ConnectionEvent ce = new ConnectionEvent(this, ConnectionEvent.CONNECTION_CLOSED); ce.setConnectionHandle(handle); sendEvent(ce); } void sendEvent(final ConnectionEvent event) { int type = event.getId(); if ( log.isDebugEnabled() ) { log.debug("Sending connection event: " + type); } // convert to an array to avoid concurrent modification exceptions ConnectionEventListener[] list = (ConnectionEventListener[]) listeners.toArray( new ConnectionEventListener[listeners.size()]); for (int i = 0; i < list.length; i++) { switch (type) { case ConnectionEvent.CONNECTION_CLOSED : list[i].connectionClosed(event); break; case ConnectionEvent.LOCAL_TRANSACTION_STARTED : list[i].localTransactionStarted(event); break; case ConnectionEvent.LOCAL_TRANSACTION_COMMITTED : list[i].localTransactionCommitted(event); break; case ConnectionEvent.LOCAL_TRANSACTION_ROLLEDBACK : list[i].localTransactionRolledback(event); break; case ConnectionEvent.CONNECTION_ERROR_OCCURRED : list[i].connectionErrorOccurred(event); break; default : throw new IllegalArgumentException( "Illegal eventType: " + type); } } } Session getSession(JCASessionImpl handle) { // JCA 1.0, 5.5.4 // Ensure that there is at most one connection handle associated // actively with a ManagedConnection instance. [skiped] Any operations // on the ManagedConnection from any previously created connection // handles should result in an application level exception. // this might be pretty bad for performance, profile and find a // better way if it is really bad synchronized (handles) { if ( handles.size() > 0 && handles.get(0) == handle) { return session; } else { final String message = "Inactive logical session handle called"; // cannot throw HibernateException because not all Session // methods throws it. This is incompatible with the spec! throw new IllegalStateException(message); } } } Connection getConnection() { return connection; } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -