KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > jonas_ejb > container > JMessageDrivenBean


1 /**
2  * JOnAS: Java(TM) Open Application Server
3  * Copyright (C) 1999 Bull S.A.
4  * Contact: jonas-team@objectweb.org
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19  * USA
20  *
21  * --------------------------------------------------------------------------
22  * $Id: JMessageDrivenBean.java,v 1.20 2005/04/28 16:52:59 benoitf Exp $
23  * --------------------------------------------------------------------------
24  */

25
26 package org.objectweb.jonas_ejb.container;
27
28 import java.security.Identity JavaDoc;
29 import java.security.Principal JavaDoc;
30 import java.util.Properties JavaDoc;
31
32 import javax.ejb.EJBException JavaDoc;
33 import javax.ejb.EJBHome JavaDoc;
34 import javax.ejb.EJBLocalHome JavaDoc;
35 import javax.ejb.MessageDrivenBean JavaDoc;
36 import javax.ejb.MessageDrivenContext JavaDoc;
37 import javax.ejb.TimedObject JavaDoc;
38 import javax.ejb.Timer JavaDoc;
39 import javax.ejb.TimerService JavaDoc;
40 import javax.jms.JMSException JavaDoc;
41 import javax.jms.Message JavaDoc;
42 import javax.jms.MessageListener JavaDoc;
43 import javax.jms.ServerSession JavaDoc;
44 import javax.jms.Session JavaDoc;
45 import javax.jms.XASession JavaDoc;
46 import javax.resource.spi.work.Work JavaDoc;
47 import javax.resource.spi.work.WorkException JavaDoc;
48 import javax.resource.spi.work.WorkManager JavaDoc;
49 import javax.transaction.Status JavaDoc;
50 import javax.transaction.SystemException JavaDoc;
51 import javax.transaction.UserTransaction JavaDoc;
52 import javax.transaction.xa.XAResource JavaDoc;
53
54 import org.objectweb.transaction.jta.TransactionManager;
55
56 import org.objectweb.util.monolog.api.BasicLevel;
57
58 /**
59  * Generic interposed class for Message Driven Beans This class presents these
60  * interfaces, depending on object reached: ServerSession interface to the
61  * ServerSessionPool MessageDrivenContext interface to the bean instance
62  * MessageListener interface to the JMS Session Runnable interface to the
63  * ThreadPool
64  * @author Philippe Coq, Philippe Durieux
65  * @author Christophe Ney (Easier Enhydra integration)
66  */

67 public class JMessageDrivenBean implements MessageListener JavaDoc, ServerSession JavaDoc, Work JavaDoc, MessageDrivenContext JavaDoc {
68
69     protected Session JavaDoc sess = null;
70
71     protected JMdbFactory bf = null;
72
73     protected MessageDrivenBean JavaDoc mdb = null;
74
75     /**
76      * Transactional attribute for onMessage method.
77      * TX_NOT_SUPPORTED, TX_REQUIRED or TX_NOT_SET (= bean managed)
78      */

79     protected int txattr;
80
81     /**
82      * Transactional attribute for ejbTimeout method.
83      * default is TX_REQUIRES_NEW
84      */

85     protected int timerTxAttr;
86
87     protected TransactionManager tm = null;
88
89     protected WorkManager JavaDoc wm = null;
90
91     /**
92      * constructor
93      * @param bf The MDB Factory
94      * @param sess The JMS Session
95      * @param mdb The Message Driven Bean
96      * @param wm The Work Manager
97      */

98     public JMessageDrivenBean(JMdbFactory bf, Session JavaDoc sess, MessageDrivenBean JavaDoc mdb, WorkManager JavaDoc wm) {
99         this.bf = bf;
100         this.sess = sess;
101         this.mdb = mdb;
102         this.wm = wm;
103         // keep these locally for efficiency.
104
txattr = bf.getTransactionAttribute();
105         timerTxAttr = bf.getTimerTxAttribute();
106         tm = bf.getTransactionManager();
107     }
108
109     // ------------------------------------------------------------------
110
// EJBContext implementation
111
// ------------------------------------------------------------------
112

113     /**
114      * Get access to the EJB Timer Service.
115      * @return the EJB Timer Service
116      * @throws IllegalStateException Thrown if the instance is not allowed to
117      * use this method
118      */

119     public TimerService JavaDoc getTimerService() throws IllegalStateException JavaDoc {
120         if (TraceEjb.isDebugIc()) {
121             TraceEjb.interp.log(BasicLevel.DEBUG, "");
122         }
123         return bf.getTimerService();
124     }
125
126     // ----------------------------------------------------------------------
127
// javax.jms.MessageListener implementation
128
// ----------------------------------------------------------------------
129

130     /**
131      * A message has been received by the Session. Basically, we have to do:
132      * preInvoke + onMessage + postInvoke. No exception should be returned to
133      * the caller.
134      * @param message The received message to handle.
135      */

136     public synchronized void onMessage(Message JavaDoc message) {
137         if (TraceEjb.isDebugJms()) {
138             TraceEjb.mdb.log(BasicLevel.DEBUG, "");
139         }
140
141         RequestCtx rctx = null;
142         try {
143
144             if (tm.getTransaction() != null) {
145                 // This should not occur (DEBUG)
146
TraceEjb.logger.log(BasicLevel.ERROR, "Transaction already OPENED");
147                 TraceEjb.logger.log(BasicLevel.ERROR, "Transaction = " + tm.getTransaction());
148                 Thread.dumpStack();
149                 return;
150             }
151
152             rctx = bf.preInvoke(txattr);
153             bf.checkSecurity(null);
154             if (rctx.mustCommit) {
155                 if (TraceEjb.isDebugTx()) {
156                     TraceEjb.tx.log(BasicLevel.DEBUG, "enlistResource");
157                 }
158                 rctx.currTx.enlistResource(((XASession JavaDoc) sess).getXAResource());
159             }
160         } catch (Exception JavaDoc e) {
161             TraceEjb.logger.log(BasicLevel.ERROR, "preInvoke failed: ", e);
162             return;
163         }
164         try {
165             if (TraceEjb.isDebugJms()) {
166                 TraceEjb.mdb.log(BasicLevel.DEBUG, "Call MDB");
167             }
168             ((MessageListener JavaDoc) mdb).onMessage(message);
169             if (TraceEjb.isDebugJms()) {
170                 TraceEjb.mdb.log(BasicLevel.DEBUG, "Return from MDB");
171             }
172         } catch (RuntimeException JavaDoc e) {
173             rctx.sysExc = e;
174             TraceEjb.logger.log(BasicLevel.ERROR, "runtime exception thrown by an enterprise Bean", e);
175         } catch (Error JavaDoc e) {
176             rctx.sysExc = e;
177             TraceEjb.logger.log(BasicLevel.ERROR, "error thrown by an enterprise Bean", e);
178         } finally {
179             try {
180                 if (rctx.mustCommit) {
181                     if (TraceEjb.isDebugTx()) {
182                         TraceEjb.tx.log(BasicLevel.DEBUG, "delistResource");
183                     }
184                     rctx.currTx.delistResource(((XASession JavaDoc) sess).getXAResource(), XAResource.TMSUCCESS);
185                 }
186                 bf.postInvoke(rctx);
187             } catch (Exception JavaDoc e) {
188                 TraceEjb.logger.log(BasicLevel.ERROR, "exception on postInvoke: ", e);
189             }
190         }
191     }
192
193     // ----------------------------------------------------------------------
194
// javax.jms.ServerSession implementation
195
// ----------------------------------------------------------------------
196

197     /**
198      * Return the ServerSession's Session. This must be a Session created by the
199      * same Connection which will be dispatching messages to it. The provider
200      * will assign one or more messages to the Session and then call start on
201      * the ServerSession.
202      * @return the server session's session.
203      * @exception JMSException - if a JMS fails to get associated session for
204      * this serverSession due to some internal error.
205      */

206     public Session JavaDoc getSession() throws JMSException JavaDoc {
207         if (TraceEjb.isDebugJms()) {
208             TraceEjb.mdb.log(BasicLevel.DEBUG, "");
209         }
210         return sess;
211     }
212
213     /**
214      * Cause the session's run method to be called to process messages that were
215      * just assigned to it.
216      * @exception JMSException - if a JMS fails to start the server session to
217      * process messages.
218      */

219     public void start() throws JMSException JavaDoc {
220         if (TraceEjb.isDebugJms()) {
221             TraceEjb.mdb.log(BasicLevel.DEBUG, "");
222         }
223         try {
224             wm.scheduleWork(this);
225         } catch (WorkException JavaDoc e) {
226             JMSException JavaDoc jmsE = new JMSException JavaDoc("Cannot schedule work");
227             jmsE.initCause(e);
228             throw jmsE;
229         }
230     }
231
232     // ----------------------------------------------------------------------
233
// Work implementation
234
// ----------------------------------------------------------------------
235

236     /**
237      * Process messages by calling run method on Session. When finished, return
238      * the object in the pool.
239      */

240     public void run() {
241         if (TraceEjb.isDebugJms()) {
242             TraceEjb.mdb.log(BasicLevel.DEBUG, "");
243         }
244
245         // this thread must have the classloader of this container to
246
// be able to retrieve beans called from a MDB.
247
Thread.currentThread().setContextClassLoader(bf.myClassLoader());
248
249         sess.run();
250         bf.releaseServerSession(this);
251     }
252
253     public void release() {
254         TraceEjb.mdb.log(BasicLevel.WARN, "Ignored");
255     }
256
257     // ----------------------------------------------------------------------
258
// javax.ejb.MessageDrivenContext implementation
259
// ----------------------------------------------------------------------
260

261     private static final String JavaDoc DISALLOWED_MSG = " is disallowed in a message driven bean";
262
263     /**
264      * Obtains the java.security.Identity of the caller. disallowed in
265      * messagedriven bean method because there is no security context
266      * @deprecated @exception java.lang.IllegalStateException always
267      */

268     public Identity JavaDoc getCallerIdentity() {
269         TraceEjb.logger.log(BasicLevel.ERROR, DISALLOWED_MSG);
270         throw new IllegalStateException JavaDoc("getCallerIdentity()" + DISALLOWED_MSG);
271     }
272
273     /**
274      * Obtain the java.security.Principal that identifies the caller. throws a
275      * java.lang.IllegalStateException for message driven bean because there is
276      * no security context available (EJB v2.0, chapter 14.5.1)
277      * @exception java.lang.IllegalStateException always
278      */

279     public Principal JavaDoc getCallerPrincipal() {
280         TraceEjb.logger.log(BasicLevel.ERROR, DISALLOWED_MSG);
281         throw new IllegalStateException JavaDoc("getCallerPrincipal()" + DISALLOWED_MSG);
282     }
283
284     /**
285      * Test if the caller has a given role.
286      * @deprecated @throws java.lang.IllegalStateException for message driven
287      * bean because there is no security context available
288      */

289     public boolean isCallerInRole(Identity JavaDoc role) {
290         TraceEjb.logger.log(BasicLevel.ERROR, DISALLOWED_MSG);
291         throw new IllegalStateException JavaDoc("isCallerInRole()" + DISALLOWED_MSG);
292     }
293
294     /**
295      * Test if the caller has a given role.
296      * @throws java.lang.IllegalStateException for message driven bean because
297      * there is no security context available
298      */

299     public boolean isCallerInRole(java.lang.String JavaDoc roleLink) {
300         TraceEjb.logger.log(BasicLevel.ERROR, DISALLOWED_MSG);
301         throw new IllegalStateException JavaDoc("isCallerInRole()" + DISALLOWED_MSG);
302     }
303
304     /**
305      * Marks the current transaction for rollback. Should be used only if the
306      * instance is associated with a transaction
307      * @throws java.lang.IllegalStateException if the instance is not associated
308      * with a transaction
309      */

310     public void setRollbackOnly() {
311
312         if (TraceEjb.isDebugJms()) {
313             TraceEjb.mdb.log(BasicLevel.DEBUG, "");
314         }
315         try {
316             tm.setRollbackOnly();
317         } catch (IllegalStateException JavaDoc e) {
318             TraceEjb.logger.log(BasicLevel.ERROR, "current thread not associated with transaction");
319             throw e;
320         } catch (SystemException JavaDoc e) {
321             TraceEjb.logger.log(BasicLevel.ERROR, "unexpected exception:", e);
322         }
323     }
324
325     /**
326      * Tests if the transaction has been marked for rollback only.
327      * @return True if transaction has been marked for rollback.
328      */

329     public boolean getRollbackOnly() {
330         if (TraceEjb.isDebugJms()) {
331             TraceEjb.mdb.log(BasicLevel.DEBUG, "");
332         }
333
334         try {
335             if (tm.getTransaction() != null) {
336                 switch (tm.getStatus()) {
337                 case Status.STATUS_MARKED_ROLLBACK:
338                 case Status.STATUS_ROLLEDBACK:
339                 case Status.STATUS_ROLLING_BACK:
340                     return true;
341                 case Status.STATUS_NO_TRANSACTION:
342                     throw new IllegalStateException JavaDoc("No transaction");
343                 default:
344                     return false;
345                 }
346             } else {
347                 TraceEjb.logger.log(BasicLevel.ERROR, "the bean is not associated in a transaction");
348                 throw new IllegalStateException JavaDoc("the message driven bean is not associated in a transaction");
349             }
350         } catch (SystemException JavaDoc e) {
351             TraceEjb.logger.log(BasicLevel.ERROR, "cannot get status:", e);
352             return false;
353         }
354     }
355
356     /**
357      * Is disallowed. There is no home for message driven bean.
358      * @throws IllegalStateException Always.
359      */

360     public EJBHome JavaDoc getEJBHome() {
361         TraceEjb.logger.log(BasicLevel.ERROR, DISALLOWED_MSG);
362         throw new IllegalStateException JavaDoc("getEJBHome()" + DISALLOWED_MSG);
363     }
364
365     /**
366      * Is disallowed. There is no local home for message driven bean.
367      * @throws IllegalStateException Always.
368      */

369     public EJBLocalHome JavaDoc getEJBLocalHome() {
370         TraceEjb.logger.log(BasicLevel.ERROR, DISALLOWED_MSG);
371         throw new IllegalStateException JavaDoc("getEJBLocalHome()" + DISALLOWED_MSG);
372     }
373
374     /**
375      * @deprecated Use the JNDI naming context java:comp/env instead.
376      * @return properties for the bean.
377      */

378     public Properties JavaDoc getEnvironment() {
379         TraceEjb.logger.log(BasicLevel.ERROR, "deprecated use : Use the JNDI naming context java:comp/env");
380         return new java.util.Properties JavaDoc();
381     }
382
383     /**
384      * Obtains the transaction demarcation interface.
385      * @return The UserTransaction interface that the enterprise bean instance
386      * can use for transaction demarcation.
387      * @exception IllegalStateException: Thrown if the instance container does
388      * not make the UserTransaction interface available to the
389      * instance.
390      */

391     public UserTransaction JavaDoc getUserTransaction() throws IllegalStateException JavaDoc {
392
393         if (TraceEjb.isDebugJms()) {
394             TraceEjb.mdb.log(BasicLevel.DEBUG, "");
395         }
396
397         if (!bf.isTxBeanManaged()) {
398             throw new IllegalStateException JavaDoc("This bean is not allowed to use UserTransaction interface");
399         }
400         return (UserTransaction JavaDoc) tm;
401     }
402
403     // -----------------------------------------------------------------------
404
// other public methods
405
// -----------------------------------------------------------------------
406

407     /**
408      * Deliver a timeout to the bean
409      * @param timer timer whose expiration caused this notification.
410      */

411     public void deliverTimeout(Timer JavaDoc timer) {
412         if (TraceEjb.isDebugJms()) {
413             TraceEjb.mdb.log(BasicLevel.DEBUG, "");
414         }
415
416         RequestCtx rctx = null;
417         try {
418             rctx = bf.preInvoke(timerTxAttr);
419         } catch (Exception JavaDoc e) {
420             TraceEjb.logger.log(BasicLevel.ERROR, "preInvoke failed: ", e);
421             return;
422         }
423         try {
424             bf.checkSecurity(null);
425             if (mdb instanceof TimedObject JavaDoc) {
426                 ((TimedObject JavaDoc) mdb).ejbTimeout(timer);
427             } else {
428                 throw new EJBException JavaDoc("The bean does not implement the `TimedObject` interface");
429             }
430         } catch (EJBException JavaDoc e) {
431             rctx.sysExc = e;
432             TraceEjb.logger.log(BasicLevel.ERROR, "EJB exception thrown by an enterprise Bean", e);
433         } catch (RuntimeException JavaDoc e) {
434             rctx.sysExc = e;
435             TraceEjb.logger.log(BasicLevel.ERROR, "runtime exception thrown by an enterprise Bean", e);
436         } catch (Error JavaDoc e) {
437             rctx.sysExc = e;
438             TraceEjb.logger.log(BasicLevel.ERROR, "error thrown by an enterprise Bean", e);
439         } finally {
440             try {
441                 bf.postInvoke(rctx);
442             } catch (Exception JavaDoc e) {
443                 TraceEjb.logger.log(BasicLevel.ERROR, "exception on postInvoke: ", e);
444             }
445         }
446     }
447
448 }
449
Popular Tags