001: /**
002: * EasyBeans
003: * Copyright (C) 2006 Bull S.A.S.
004: * Contact: easybeans@ow2.org
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2.1 of the License, or any later version.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public
017: * License along with this library; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
019: * USA
020: *
021: * --------------------------------------------------------------------------
022: * $Id: BMTStatelessTransactionInterceptor.java 1970 2007-10-16 11:49:25Z benoitf $
023: * --------------------------------------------------------------------------
024: */package org.ow2.easybeans.transaction.interceptors;
025:
026: import static javax.transaction.Status.STATUS_COMMITTED;
027:
028: import javax.ejb.EJBException;
029: import javax.transaction.InvalidTransactionException;
030: import javax.transaction.SystemException;
031: import javax.transaction.Transaction;
032:
033: import org.ow2.easybeans.api.EasyBeansInvocationContext;
034: import org.ow2.util.log.Log;
035: import org.ow2.util.log.LogFactory;
036:
037: /**
038: * Defines an interceptor for method that are in Bean managed mode and then in Bean Managed Transaction.
039: * It is used by stateless session bean.
040: * @author Florent Benoit
041: */
042: public class BMTStatelessTransactionInterceptor extends
043: AbsTransactionInterceptor {
044:
045: /**
046: * Logger.
047: */
048: private Log logger = LogFactory
049: .getLog(BMTStatelessTransactionInterceptor.class);
050:
051: /**
052: * Constructor.<br>
053: * Acquire the transaction manager.
054: */
055: public BMTStatelessTransactionInterceptor() {
056: super ();
057: }
058:
059: /**
060: * Execute transaction as specified for BMT.
061: * @param invocationContext context with useful attributes on the current
062: * invocation
063: * @return result of the next invocation (to chain interceptors)
064: * @throws Exception if interceptor fails
065: * @see <a href="http://www.jcp.org/en/jsr/detail?id=220">EJB 3.0
066: * specification ?12.6.1</a>
067: */
068: @Override
069: public Object intercept(
070: final EasyBeansInvocationContext invocationContext)
071: throws Exception {
072: logger.debug("Calling BMT TX interceptor");
073:
074: // Get current transaction
075: Transaction transaction;
076: try {
077: transaction = getTransactionManager().getTransaction();
078: } catch (SystemException se) {
079: throw new EJBException(
080: "Cannot get the current transaction on transaction manager.",
081: se);
082: }
083:
084: logger.debug("Transaction found = {0}", transaction);
085:
086: /*
087: * When a client invokes a business method via one of the enterprise
088: * bean's client view interfaces, the container suspends any transaction
089: * that may be associated with the client request. If there is a
090: * transaction associated with the instance (this would happen if a
091: * stateful session bean instance started the transaction in some
092: * previous business method), the container associates the method
093: * execution with this transaction. If there are interceptor methods
094: * associated with the bean instances, these actions are taken before
095: * the interceptor methods are invoked.
096: */
097:
098: Transaction suspendedTransaction = null;
099: if (transaction != null) {
100: try {
101: logger.debug("Suspending transaction {0}", transaction);
102: suspendedTransaction = getTransactionManager()
103: .suspend();
104: } catch (SystemException se) {
105: throw new EJBException(
106: "Cannot call suspend() on the transaction manager.",
107: se);
108: }
109: }
110:
111: boolean gotBusinessException = false;
112: try {
113: return invocationContext.proceed();
114: } catch (Exception e) {
115: gotBusinessException = true;
116: handleBeanManagedException(invocationContext, e);
117: // Shouldn't come here
118: return null;
119: } finally {
120: if (!gotBusinessException) {
121: /**
122: * If a stateless session bean instance starts a transaction in a
123: * business method or interceptor method, it must commit the
124: * transaction before the business method (or all its interceptor
125: * methods) returns. The container must detect the case in which a
126: * transaction was started, but not completed, in the business
127: * method or interceptor method for the business method, and handle
128: * it as follows:
129: * <ul>
130: * <li>Log this as an application error to alert the System
131: * Administrator.</li>
132: * <li>Roll back the started transaction</li>
133: * <li>Discard the instance of the session bean</li>
134: * <li>Throw the javax.ejb.EJBException[53]. If the EJB 2.1 client
135: * view is used, the container should throw java.rmi.RemoteException
136: * if the client is a remote client, or throw the
137: * javax.ejb.EJBException if the client is a local client.</li>
138: */
139: Transaction transactionAfter = null;
140: try {
141: transactionAfter = getTransactionManager()
142: .getTransaction();
143: } catch (SystemException se) {
144: throw new EJBException(
145: "Cannot get the current transaction on transaction manager.",
146: se);
147: }
148: if (transactionAfter != null) {
149: int transactionStatus = transactionAfter
150: .getStatus();
151: // There is a transaction and it was not committed
152: if (transactionStatus != STATUS_COMMITTED) {
153: String errMsg = "Transaction started by the bean but not committed.";
154: // Log error
155: logger.error(errMsg);
156: // Rollback
157: transactionAfter.rollback();
158: //TODO: discard
159: // Throw Exception
160: throw new EJBException(errMsg);
161: }
162: }
163: }
164:
165: /*
166: * The container resumes the suspended association when the business
167: * method has completed.
168: */
169: if (suspendedTransaction != null) {
170:
171: logger.debug("Resuming transaction {0}", transaction);
172:
173: try {
174: getTransactionManager()
175: .resume(suspendedTransaction);
176: } catch (InvalidTransactionException ite) {
177: throw new EJBException(
178: "Cannot call resume() on the given transaction. There is an invalid transaction",
179: ite);
180: } catch (IllegalStateException ise) {
181: throw new EJBException(
182: "Cannot call resume() on the given transaction. There is another associated transaction",
183: ise);
184: } catch (SystemException se) {
185: throw new EJBException(
186: "Cannot call resume() on the given transaction. Unexpected error condition",
187: se);
188: }
189: }
190: }
191: }
192:
193: }
|