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: BMTStatefulTransactionInterceptor.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: import static javax.transaction.Status.STATUS_ROLLEDBACK;
028:
029: import javax.ejb.EJBException;
030: import javax.transaction.InvalidTransactionException;
031: import javax.transaction.SystemException;
032: import javax.transaction.Transaction;
033:
034: import org.ow2.easybeans.api.EasyBeansInvocationContext;
035: import org.ow2.easybeans.api.bean.EasyBeansSFSB;
036: import org.ow2.easybeans.api.container.EZBSessionContext;
037: import org.ow2.util.log.Log;
038: import org.ow2.util.log.LogFactory;
039:
040: /**
041: * Defines an interceptor for method that are in Bean managed mode and then in
042: * Bean Managed Transaction : for a stateful bean.
043: * @author Florent Benoit
044: */
045: public class BMTStatefulTransactionInterceptor extends
046: AbsTransactionInterceptor {
047:
048: /**
049: * Logger.
050: */
051: private Log logger = LogFactory
052: .getLog(BMTStatefulTransactionInterceptor.class);
053:
054: /**
055: * Constructor.<br> Acquire the transaction manager.
056: */
057: public BMTStatefulTransactionInterceptor() {
058: super ();
059: }
060:
061: /**
062: * Execute transaction as specified for BMT.
063: * @param invocationContext context with useful attributes on the current
064: * invocation
065: * @return result of the next invocation (to chain interceptors)
066: * @throws Exception if interceptor fails
067: * @see <a href="http://www.jcp.org/en/jsr/detail?id=220">EJB 3.0
068: * specification ?12.6.1</a>
069: */
070: @Override
071: public Object intercept(
072: final EasyBeansInvocationContext invocationContext)
073: throws Exception {
074: logger.debug("Calling BMT TX interceptor");
075:
076: // Get current transaction
077: Transaction transaction;
078: try {
079: transaction = getTransactionManager().getTransaction();
080: } catch (SystemException se) {
081: throw new EJBException(
082: "Cannot get the current transaction on transaction manager.",
083: se);
084: }
085:
086: logger.debug("Transaction found = {0}", transaction);
087:
088: /*
089: * When a client invokes a business method via one of the enterprise
090: * bean's client view interfaces, the container suspends any transaction
091: * that may be associated with the client request. If there is a
092: * transaction associated with the instance (this would happen if a
093: * stateful session bean instance started the transaction in some
094: * previous business method), the container associates the method
095: * execution with this transaction. If there are interceptor methods
096: * associated with the bean instances, these actions are taken before
097: * the interceptor methods are invoked.
098: */
099:
100: Transaction suspendedTransaction = null;
101: if (transaction != null) {
102: try {
103: logger.debug("Suspending transaction {0}", transaction);
104: suspendedTransaction = getTransactionManager()
105: .suspend();
106: } catch (SystemException se) {
107: throw new EJBException(
108: "Cannot call suspend() on the transaction manager.",
109: se);
110: }
111: }
112:
113: /*
114: * In the case of a stateful session bean, it is possible that the
115: * business method that started a transaction completes without
116: * committing or rolling back the transaction. In such a case, the
117: * container must retain the association between the transaction and the
118: * instance across multiple client calls until the instance commits or
119: * rolls back the transaction. When the client invokes the next business
120: * method, the container must invoke the business method (and any
121: * applicable interceptor methods for the bean) in this transaction
122: * context.
123: */
124:
125: // Get Bean and context
126: EasyBeansSFSB statefulBean = (EasyBeansSFSB) invocationContext
127: .getTarget();
128: EZBSessionContext sessionContext = (EZBSessionContext) statefulBean
129: .getEasyBeansContext();
130: // Get bean transaction (if any)
131: Transaction beanTransaction = sessionContext
132: .getBeanTransaction();
133: // resume transaction for the call
134: if (beanTransaction != null) {
135: try {
136: getTransactionManager().resume(beanTransaction);
137: } catch (InvalidTransactionException ite) {
138: throw new EJBException(
139: "Cannot call resume() on the previous bean transaction. There is an invalid transaction",
140: ite);
141: } catch (IllegalStateException ise) {
142: throw new EJBException(
143: "Cannot call resume() on the previous bean transaction. There is another associated transaction",
144: ise);
145: } catch (SystemException se) {
146: throw new EJBException(
147: "Cannot call resume() on the previous bean transaction. Unexpected error condition",
148: se);
149: }
150: }
151:
152: try {
153: return invocationContext.proceed();
154: } catch (Exception e) {
155: handleBeanManagedException(invocationContext, e);
156: // Shouldn't come here
157: return null;
158: } finally {
159:
160: /*
161: * Saves the current bean transaction if the business method that
162: * started a transaction completes without committing or rolling
163: * back the transaction.
164: */
165: Transaction transactionAfter = null;
166: try {
167: transactionAfter = getTransactionManager()
168: .getTransaction();
169: } catch (SystemException se) {
170: throw new EJBException(
171: "Cannot get the current transaction on transaction manager.",
172: se);
173: }
174: if (transactionAfter != null) {
175: int transactionStatus = transactionAfter.getStatus();
176: // not yet committed or rollbacked --> save transaction for the next call.
177: if (transactionStatus != STATUS_COMMITTED
178: && transactionStatus != STATUS_ROLLEDBACK) {
179: sessionContext.setBeanTransaction(transactionAfter);
180: } else {
181: sessionContext.setBeanTransaction(null);
182: }
183: }
184:
185: /*
186: * The container resumes the suspended association when the business
187: * method has completed.
188: */
189: if (suspendedTransaction != null) {
190:
191: logger.debug("Resuming transaction {0}", transaction);
192:
193: try {
194: getTransactionManager()
195: .resume(suspendedTransaction);
196: } catch (InvalidTransactionException ite) {
197: throw new EJBException(
198: "Cannot call resume() on the given transaction. There is an invalid transaction",
199: ite);
200: } catch (IllegalStateException ise) {
201: throw new EJBException(
202: "Cannot call resume() on the given transaction. There is another associated transaction",
203: ise);
204: } catch (SystemException se) {
205: throw new EJBException(
206: "Cannot call resume() on the given transaction. Unexpected error condition",
207: se);
208: }
209: }
210: }
211: }
212: }
|