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.jms.recovery;
023:
024: import javax.jms.ExceptionListener;
025: import javax.jms.JMSException;
026: import javax.jms.XAConnection;
027: import javax.jms.XAConnectionFactory;
028: import javax.jms.XASession;
029: import javax.naming.Context;
030: import javax.naming.InitialContext;
031: import javax.transaction.xa.XAException;
032: import javax.transaction.xa.XAResource;
033: import javax.transaction.xa.Xid;
034:
035: import org.jboss.jms.jndi.JMSProviderAdapter;
036: import org.jboss.logging.Logger;
037: import org.jboss.util.naming.Util;
038:
039: /**
040: * XAResourceWrapper.
041: *
042: * @author <a href="adrian@jboss.com">Adrian Brock</a>
043: * @version $Revision: 57209 $
044: */
045: public class XAResourceWrapper implements XAResource, ExceptionListener {
046: /** The log */
047: private static final Logger log = Logger
048: .getLogger(XAResourceWrapper.class);
049:
050: /** The jms provider name */
051: private String providerName;
052:
053: /** The state lock */
054: private static final Object lock = new Object();
055:
056: /** The connection */
057: private XAConnection connection;
058:
059: /** The delegate XAResource */
060: private XAResource delegate;
061:
062: /**
063: * Get the providerName.
064: *
065: * @return the providerName.
066: */
067: public String getProviderName() {
068: return providerName;
069: }
070:
071: /**
072: * Set the providerName.
073: *
074: * @param providerName the providerName.
075: */
076: public void setProviderName(String providerName) {
077: this .providerName = providerName;
078: }
079:
080: public Xid[] recover(int flag) throws XAException {
081: log.debug("Recover " + providerName);
082: XAResource xaResource = getDelegate();
083: try {
084: return xaResource.recover(flag);
085: } catch (XAException e) {
086: throw check(e);
087: }
088: }
089:
090: public void commit(Xid xid, boolean onePhase) throws XAException {
091: log.debug("Commit " + providerName + " xid " + " onePhase="
092: + onePhase);
093: XAResource xaResource = getDelegate();
094: try {
095: xaResource.commit(xid, onePhase);
096: } catch (XAException e) {
097: throw check(e);
098: }
099: }
100:
101: public void rollback(Xid xid) throws XAException {
102: log.debug("Rollback " + providerName + " xid ");
103: XAResource xaResource = getDelegate();
104: try {
105: xaResource.rollback(xid);
106: } catch (XAException e) {
107: throw check(e);
108: }
109: }
110:
111: public void forget(Xid xid) throws XAException {
112: log.debug("Forget " + providerName + " xid ");
113: XAResource xaResource = getDelegate();
114: try {
115: xaResource.forget(xid);
116: } catch (XAException e) {
117: throw check(e);
118: }
119: }
120:
121: public boolean isSameRM(XAResource xaRes) throws XAException {
122: if (xaRes instanceof XAResourceWrapper)
123: xaRes = ((XAResourceWrapper) xaRes).getDelegate();
124:
125: XAResource xaResource = getDelegate();
126: try {
127: return xaResource.isSameRM(xaRes);
128: } catch (XAException e) {
129: throw check(e);
130: }
131: }
132:
133: public int prepare(Xid xid) throws XAException {
134: XAResource xaResource = getDelegate();
135: try {
136: return xaResource.prepare(xid);
137: } catch (XAException e) {
138: throw check(e);
139: }
140: }
141:
142: public void start(Xid xid, int flags) throws XAException {
143: XAResource xaResource = getDelegate();
144: try {
145: xaResource.start(xid, flags);
146: } catch (XAException e) {
147: throw check(e);
148: }
149: }
150:
151: public void end(Xid xid, int flags) throws XAException {
152: XAResource xaResource = getDelegate();
153: try {
154: xaResource.end(xid, flags);
155: } catch (XAException e) {
156: throw check(e);
157: }
158: }
159:
160: public int getTransactionTimeout() throws XAException {
161: XAResource xaResource = getDelegate();
162: try {
163: return xaResource.getTransactionTimeout();
164: } catch (XAException e) {
165: throw check(e);
166: }
167: }
168:
169: public boolean setTransactionTimeout(int seconds)
170: throws XAException {
171: XAResource xaResource = getDelegate();
172: try {
173: return xaResource.setTransactionTimeout(seconds);
174: } catch (XAException e) {
175: throw check(e);
176: }
177: }
178:
179: public void onException(JMSException exception) {
180: log.warn(
181: "Notified of connection failure in recovery delegate for provider "
182: + providerName, exception);
183: close();
184: }
185:
186: /**
187: * Get the delegate XAResource
188: *
189: * @return the delegate
190: * @throws XAException for any problem
191: */
192: public XAResource getDelegate() throws XAException {
193: XAResource result = null;
194: Exception error = null;
195: try {
196: result = connect();
197: } catch (Exception e) {
198: error = e;
199: }
200:
201: if (result == null) {
202: XAException xae = new XAException(
203: "Error trying to connect to provider "
204: + providerName);
205: xae.errorCode = XAException.XAER_RMERR;
206: if (error != null)
207: xae.initCause(error);
208: log.debug("Cannot get delegate XAResource", xae);
209: throw xae;
210: }
211:
212: return result;
213: }
214:
215: /**
216: * Connect to the server if not already done so
217: *
218: * @return the delegate XAResource
219: * @throws Exception for any problem
220: */
221: protected XAResource connect() throws Exception {
222: // Do we already have a valid delegate?
223: synchronized (lock) {
224: if (delegate != null)
225: return delegate;
226: }
227:
228: // Create the connection
229: XAConnection xaConnection = getConnectionFactory()
230: .createXAConnection();
231: synchronized (lock) {
232: connection = xaConnection;
233: }
234:
235: // Retrieve the delegate XAResource
236: try {
237: XASession session = connection.createXASession();
238: XAResource result = session.getXAResource();
239: synchronized (lock) {
240: delegate = result;
241: }
242: return delegate;
243: } catch (Exception e) {
244: close();
245: throw e;
246: }
247: }
248:
249: /**
250: * Get the XAConnectionFactory
251: *
252: * @return the connection
253: * @throws Exception for any problem
254: */
255: protected XAConnectionFactory getConnectionFactory()
256: throws Exception {
257: // Get the JMS Provider Adapter
258: if (providerName == null)
259: throw new IllegalArgumentException("Null provider name");
260: String providerAdapterJNDI = providerName;
261: if (providerAdapterJNDI.startsWith("java:") == false)
262: providerAdapterJNDI = "java:" + providerAdapterJNDI;
263: Context ctx = new InitialContext();
264: JMSProviderAdapter adapter = (JMSProviderAdapter) Util.lookup(
265: providerAdapterJNDI, JMSProviderAdapter.class);
266:
267: // Determine the XAConnectionFactory name
268: String connectionFactoryRef = adapter.getFactoryRef();
269: if (connectionFactoryRef == null)
270: throw new IllegalStateException("Provider '" + providerName
271: + "' has no FactoryRef");
272:
273: // Lookup the connection factory
274: ctx = adapter.getInitialContext();
275: try {
276: return (XAConnectionFactory) Util.lookup(ctx,
277: connectionFactoryRef, XAConnectionFactory.class);
278: } finally {
279: ctx.close();
280: }
281: }
282:
283: /**
284: * Close the connection
285: */
286: public void close() {
287: try {
288: XAConnection oldConnection = null;
289: synchronized (lock) {
290: oldConnection = connection;
291: connection = null;
292: delegate = null;
293: }
294: if (oldConnection != null)
295: oldConnection.close();
296: } catch (Exception ignored) {
297: log.trace("Ignored error during close", ignored);
298: }
299: }
300:
301: /**
302: * Check whether an XAException is fatal. If it is an RM problem
303: * we close the connection so the next call will reconnect.
304: *
305: * @param e the xa exception
306: * @return never
307: * @throws XAException always
308: */
309: protected XAException check(XAException e) throws XAException {
310: if (e.errorCode == XAException.XAER_RMERR
311: || e.errorCode == XAException.XAER_RMFAIL) {
312: log.debug("Fatal error in provider " + providerName, e);
313: close();
314: }
315: throw e;
316: }
317:
318: protected void finalize() throws Throwable {
319: close();
320: }
321: }
|