KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > ejb > plugins > AbstractTxInterceptorBMT


1 /*
2 * JBoss, Home of Professional Open Source
3 * Copyright 2005, JBoss Inc., and individual contributors as indicated
4 * by the @authors tag. See the copyright.txt in the distribution for a
5 * full listing of individual contributors.
6 *
7 * This is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as
9 * published by the Free Software Foundation; either version 2.1 of
10 * the License, or (at your option) any later version.
11 *
12 * This software is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this software; if not, write to the Free
19 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21 */

22 package org.jboss.ejb.plugins;
23
24 import java.util.Hashtable JavaDoc;
25
26 import java.rmi.RemoteException JavaDoc;
27
28 import javax.transaction.Transaction JavaDoc;
29 import javax.transaction.Status JavaDoc;
30 import javax.transaction.SystemException JavaDoc;
31
32 import javax.naming.Context JavaDoc;
33 import javax.naming.InitialContext JavaDoc;
34 import javax.naming.Name JavaDoc;
35 import javax.naming.Reference JavaDoc;
36 import javax.naming.RefAddr JavaDoc;
37 import javax.naming.spi.ObjectFactory JavaDoc;
38
39 import org.jboss.ejb.EnterpriseContext;
40 import org.jboss.ejb.AllowedOperationsAssociation;
41 import org.jboss.invocation.Invocation;
42 import org.jboss.tm.TxUtils;
43
44 /**
45  * A common superclass for the BMT transaction interceptors.
46  *
47  * @author <a HREF="mailto:osh@sparre.dk">Ole Husgaard</a>
48  * @version $Revision: 37459 $
49  */

50 abstract class AbstractTxInterceptorBMT extends AbstractTxInterceptor
51 {
52    // Attributes ----------------------------------------------------
53

54    /**
55     * This associates the thread to the UserTransaction.
56     *
57     * It is used to redirect lookups on java:comp/UserTransaction to
58     * the <code>getUserTransaction()</code> method of the context.
59     */

60    private ThreadLocal JavaDoc userTransaction = new ThreadLocal JavaDoc();
61
62    /**
63     * If <code>false</code>, transactions may live across bean instance
64     * invocations, otherwise the bean instance should terminate any
65     * transaction before returning from the invocation.
66     * This attribute defaults to <code>true</code>.
67     */

68    protected boolean stateless = true;
69
70    // Static --------------------------------------------------------
71

72    // Constructors --------------------------------------------------
73

74    // Public --------------------------------------------------------
75

76    // Interceptor implementation --------------------------------------
77

78    public void create() throws Exception JavaDoc
79    {
80       // Do initialization in superclass.
81
super.create();
82
83       // bind java:comp/UserTransaction
84
RefAddr JavaDoc refAddr = new RefAddr JavaDoc("userTransaction")
85       {
86          /** This is never really serialized */
87          private static final long serialVersionUID = 1L;
88
89          public Object JavaDoc getContent()
90          {
91             return userTransaction;
92          }
93       };
94
95       Reference JavaDoc ref = new Reference JavaDoc("javax.transaction.UserTransaction", refAddr, new UserTxFactory().getClass()
96             .getName(), null);
97       ((Context JavaDoc) new InitialContext JavaDoc().lookup("java:comp/")).bind("UserTransaction", ref);
98    }
99
100    public void stop()
101    {
102       // bind java:comp/UserTransaction
103
try
104       {
105          ((Context JavaDoc) new InitialContext JavaDoc().lookup("java:comp/")).unbind("UserTransaction");
106       }
107       catch (Exception JavaDoc e)
108       {
109          //ignore
110
}
111    }
112
113    // Protected ----------------------------------------------------
114

115    /*
116     * This method calls the next interceptor in the chain.
117     *
118     * It handles the suspension of any client transaction, and the
119     * association of the calling thread with the instance transaction.
120     * And it takes care that any lookup of
121     * <code>java:comp/UserTransaction</code> will return the right
122     * UserTransaction for the bean instance.
123     *
124     * @param remoteInvocation If <code>true</code> this is an invocation
125     * of a method in the remote interface, otherwise
126     * it is an invocation of a method in the home
127     * interface.
128     * @param mi The <code>Invocation</code> of this call.
129     */

130    protected Object JavaDoc invokeNext(Invocation mi) throws Exception JavaDoc
131    {
132       // Save the transaction that comes with the MI
133
Transaction JavaDoc oldTransaction = mi.getTransaction();
134
135       // Get old threadlocal: It may be non-null if one BMT bean does a local
136
// call to another.
137
Object JavaDoc oldUserTx = userTransaction.get();
138
139       // Suspend any transaction associated with the thread: It may be
140
// non-null on optimized local calls.
141
Transaction JavaDoc threadTx = tm.suspend();
142
143       try
144       {
145          EnterpriseContext ctx = ((EnterpriseContext) mi.getEnterpriseContext());
146
147          // Set the threadlocal to the userTransaction of the instance
148
try
149          {
150             AllowedOperationsAssociation.pushInMethodFlag(IN_INTERCEPTOR_METHOD);
151             userTransaction.set(ctx.getEJBContext().getUserTransaction());
152          }
153          finally
154          {
155             AllowedOperationsAssociation.popInMethodFlag();
156          }
157
158          // Get the bean instance transaction
159
Transaction JavaDoc beanTx = ctx.getTransaction();
160
161          // Resume the bean instance transaction
162
// only if it not null, some TMs can't resume(null), e.g. Tyrex
163
if (beanTx != null)
164             tm.resume(beanTx);
165
166          // Let the MI know about our new transaction
167
mi.setTransaction(beanTx);
168
169          try
170          {
171             // Let the superclass call next interceptor and do the exception
172
// handling
173
return super.invokeNext(mi, false);
174          }
175          finally
176          {
177             try
178             {
179                if (stateless)
180                   checkStatelessDone();
181                else
182                   checkBadStateful();
183             }
184             finally
185             {
186                tm.suspend();
187             }
188          }
189       }
190       finally
191       {
192          // Reset threadlocal to its old value
193
userTransaction.set(oldUserTx);
194
195          // Restore old MI transaction
196
// OSH: Why ???
197
mi.setTransaction(oldTransaction);
198
199          // If we had a Tx associated with the thread reassociate
200
if (threadTx != null)
201             tm.resume(threadTx);
202       }
203    }
204
205    private void checkStatelessDone() throws RemoteException JavaDoc
206    {
207       int status = Status.STATUS_NO_TRANSACTION;
208
209       try
210       {
211          status = tm.getStatus();
212       }
213       catch (SystemException JavaDoc ex)
214       {
215          log.error("Failed to get status", ex);
216       }
217
218       switch (status)
219       {
220          case Status.STATUS_ACTIVE :
221          case Status.STATUS_COMMITTING :
222          case Status.STATUS_MARKED_ROLLBACK :
223          case Status.STATUS_PREPARING :
224          case Status.STATUS_ROLLING_BACK :
225             try
226             {
227                tm.rollback();
228             }
229             catch (Exception JavaDoc ex)
230             {
231                log.error("Failed to rollback", ex);
232             }
233          // fall through...
234
case Status.STATUS_PREPARED :
235             String JavaDoc msg = "Application error: BMT stateless bean " + container.getBeanMetaData().getEjbName()
236                   + " should complete transactions before" + " returning (ejb1.1 spec, 11.6.1)";
237             log.error(msg);
238
239             // the instance interceptor will discard the instance
240
throw new RemoteException JavaDoc(msg);
241       }
242    }
243
244    private void checkBadStateful() throws RemoteException JavaDoc
245    {
246       int status = Status.STATUS_NO_TRANSACTION;
247
248       try
249       {
250          status = tm.getStatus();
251       }
252       catch (SystemException JavaDoc ex)
253       {
254          log.error("Failed to get status", ex);
255       }
256
257       switch (status)
258       {
259          case Status.STATUS_COMMITTING :
260          case Status.STATUS_MARKED_ROLLBACK :
261          case Status.STATUS_PREPARING :
262          case Status.STATUS_ROLLING_BACK :
263             try
264             {
265                tm.rollback();
266             }
267             catch (Exception JavaDoc ex)
268             {
269                log.error("Failed to rollback", ex);
270             }
271             String JavaDoc msg = "BMT stateful bean '" + container.getBeanMetaData().getEjbName()
272                   + "' did not complete user transaction properly status=" + TxUtils.getStatusAsString(status);
273             log.error(msg);
274       }
275    }
276
277    // Inner classes -------------------------------------------------
278

279    public static class UserTxFactory implements ObjectFactory JavaDoc
280    {
281       public Object JavaDoc getObjectInstance(Object JavaDoc ref, Name JavaDoc name, Context JavaDoc nameCtx, Hashtable JavaDoc environment) throws Exception JavaDoc
282       {
283          // The ref is a list with only one RefAddr ...
284
RefAddr JavaDoc refAddr = ((Reference JavaDoc) ref).get(0);
285          // ... whose content is the threadlocal
286
ThreadLocal JavaDoc threadLocal = (ThreadLocal JavaDoc) refAddr.getContent();
287
288          // The threadlocal holds the right UserTransaction
289
return threadLocal.get();
290       }
291    }
292
293 }
294
Popular Tags