001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jboss.resource.adapter.jdbc.xa;
023:
024: import java.sql.SQLException;
025: import java.util.Properties;
026:
027: import javax.resource.ResourceException;
028: import javax.resource.spi.LocalTransaction;
029: import javax.sql.XAConnection;
030: import javax.transaction.xa.XAException;
031: import javax.transaction.xa.XAResource;
032: import javax.transaction.xa.Xid;
033:
034: import org.jboss.resource.JBossResourceException;
035: import org.jboss.resource.adapter.jdbc.BaseWrapperManagedConnection;
036:
037: /**
038: * XAManagedConnection
039: *
040: * @author <a href="mailto:d_jencks@users.sourceforge.net">David Jencks </a>
041: * @author <a href="mailto:adrian@jboss.com">Adrian Brock</a>
042: * @author <a href="mailto:weston.price@jboss.com">Weston Price</a>
043: *
044: * @version $Revision: 59811 $
045: */
046: public class XAManagedConnection extends BaseWrapperManagedConnection
047: implements XAResource, LocalTransaction {
048: protected final XAConnection xaConnection;
049:
050: protected final XAResource xaResource;
051:
052: protected Xid currentXid;
053:
054: public XAManagedConnection(XAManagedConnectionFactory mcf,
055: XAConnection xaConnection, Properties props,
056: int transactionIsolation, int psCacheSize)
057: throws SQLException {
058: super (mcf, xaConnection.getConnection(), props,
059: transactionIsolation, psCacheSize);
060: this .xaConnection = xaConnection;
061: xaConnection
062: .addConnectionEventListener(new javax.sql.ConnectionEventListener() {
063: public void connectionClosed(
064: javax.sql.ConnectionEvent ce) {
065: //only we can do this, ignore
066: }
067:
068: public void connectionErrorOccurred(
069: javax.sql.ConnectionEvent ce) {
070: SQLException ex = ce.getSQLException();
071: broadcastConnectionError(ex);
072: }
073: });
074: this .xaResource = xaConnection.getXAResource();
075: }
076:
077: protected void broadcastConnectionError(SQLException e) {
078: super .broadcastConnectionError(e);
079: }
080:
081: public LocalTransaction getLocalTransaction()
082: throws ResourceException {
083: return this ;
084: }
085:
086: public XAResource getXAResource() throws ResourceException {
087: return this ;
088: }
089:
090: public void destroy() throws ResourceException {
091: try {
092: super .destroy();
093: } finally {
094: try {
095: xaConnection.close();
096: } catch (SQLException e) {
097: checkException(e);
098: }
099: }
100: }
101:
102: public void start(Xid xid, int flags) throws XAException {
103: try {
104: checkState();
105: } catch (SQLException e) {
106: getLog().warn("Error setting state ", e);
107: }
108: try {
109: xaResource.start(xid, flags);
110:
111: } catch (XAException e) {
112: //JBAS-3336 Connections that fail in enlistment should not be returned
113: //to the pool
114: if (isFailedXA(e.errorCode)) {
115: getLog().error("Start transaction failed for " + this );
116: broadcastConnectionError(e);
117: }
118:
119: throw e;
120: }
121:
122: synchronized (stateLock) {
123: currentXid = xid;
124: inManagedTransaction = true;
125: }
126: }
127:
128: public void end(Xid xid, int flags) throws XAException {
129: try {
130: xaResource.end(xid, flags);
131:
132: } catch (XAException e) {
133: getLog().error("End transaction failed for XAResource", e);
134: broadcastConnectionError(e);
135: throw e;
136: }
137:
138: //we want to allow ending transactions that are not the current
139: //one. When one does this, inManagedTransaction is still true.
140: synchronized (stateLock) {
141: if (currentXid != null && currentXid.equals(xid)) {
142: inManagedTransaction = false;
143: currentXid = null;
144: }
145: }
146: }
147:
148: public int prepare(Xid xid) throws XAException {
149: return xaResource.prepare(xid);
150: }
151:
152: public void commit(Xid xid, boolean onePhase) throws XAException {
153: xaResource.commit(xid, onePhase);
154: }
155:
156: public void rollback(Xid xid) throws XAException {
157: xaResource.rollback(xid);
158: }
159:
160: public void forget(Xid xid) throws XAException {
161: xaResource.forget(xid);
162: }
163:
164: public Xid[] recover(int flag) throws XAException {
165: return xaResource.recover(flag);
166: }
167:
168: public boolean isSameRM(XAResource other) throws XAException {
169:
170: // compare apples to apples
171: return (other instanceof XAManagedConnection) ? xaResource
172: .isSameRM(((XAManagedConnection) other).xaResource)
173: : xaResource.isSameRM(other);
174: }
175:
176: public int getTransactionTimeout() throws XAException {
177: return xaResource.getTransactionTimeout();
178: }
179:
180: public boolean setTransactionTimeout(int seconds)
181: throws XAException {
182: return xaResource.setTransactionTimeout(seconds);
183: }
184:
185: private boolean isFailedXA(int errorCode) {
186:
187: return (errorCode == XAException.XAER_RMERR || errorCode == XAException.XAER_RMFAIL);
188: }
189:
190: Properties getProps() {
191: return props;
192: }
193:
194: public void begin() throws ResourceException {
195: synchronized (stateLock) {
196: if (inManagedTransaction == false) {
197: try {
198: if (underlyingAutoCommit) {
199: underlyingAutoCommit = false;
200: con.setAutoCommit(false);
201: }
202: checkState();
203: inManagedTransaction = true;
204: } catch (SQLException e) {
205: checkException(e);
206: }
207: } else
208: throw new JBossResourceException(
209: "Trying to begin a nested local tx");
210: }
211: }
212:
213: public void commit() throws ResourceException {
214: synchronized (stateLock) {
215: if (inManagedTransaction)
216: inManagedTransaction = false;
217: }
218: try {
219: con.commit();
220: } catch (SQLException e) {
221: checkException(e);
222: }
223: }
224:
225: public void rollback() throws ResourceException {
226: synchronized (stateLock) {
227: if (inManagedTransaction)
228: inManagedTransaction = false;
229: }
230: try {
231: con.rollback();
232: } catch (SQLException e) {
233: try {
234: checkException(e);
235: } catch (Exception e2) {
236: }
237: }
238: }
239:
240: }
|