KickJava   Java API By Example, From Geeks To Geeks.

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


1 /**
2  * JOnAS: Java(TM) Open Application Server
3  * Copyright (C) 1999-2005 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: JFactory.java,v 1.57 2005/07/13 06:29:45 durieuxp Exp $
23  * --------------------------------------------------------------------------
24  */

25
26 package org.objectweb.jonas_ejb.container;
27
28 import java.io.File JavaDoc;
29 import java.io.IOException JavaDoc;
30 import java.lang.reflect.Field JavaDoc;
31 import java.net.URLClassLoader JavaDoc;
32 import java.rmi.RemoteException JavaDoc;
33 import java.util.Enumeration JavaDoc;
34 import java.util.Hashtable JavaDoc;
35 import java.util.Properties JavaDoc;
36
37 import javax.ejb.EJBException JavaDoc;
38 import javax.ejb.TimerService JavaDoc;
39 import javax.ejb.TransactionRequiredLocalException JavaDoc;
40 import javax.ejb.TransactionRolledbackLocalException JavaDoc;
41 import javax.naming.Context JavaDoc;
42 import javax.naming.InitialContext JavaDoc;
43 import javax.naming.NamingException JavaDoc;
44 import javax.resource.spi.work.WorkManager JavaDoc;
45 import javax.transaction.NotSupportedException JavaDoc;
46 import javax.transaction.RollbackException JavaDoc;
47 import javax.transaction.Status JavaDoc;
48 import javax.transaction.SystemException JavaDoc;
49 import javax.transaction.Transaction JavaDoc;
50 import javax.transaction.TransactionRequiredException JavaDoc;
51 import javax.transaction.TransactionRolledbackException JavaDoc;
52
53 import org.objectweb.jotm.TransactionContext;
54 import org.objectweb.transaction.jta.TransactionManager;
55
56 import org.objectweb.carol.rmi.exception.NoSuchObjectExceptionHelper;
57 import org.objectweb.carol.util.configuration.ConfigurationRepository;
58
59 import org.objectweb.jonas_ejb.deployment.api.BeanDesc;
60 import org.objectweb.jonas_ejb.deployment.api.MethodDesc;
61 import org.objectweb.jonas_ejb.lib.EJBInvocation;
62
63 import org.objectweb.jonas_lib.naming.ContainerNaming;
64 import org.objectweb.jonas_lib.version.Version;
65
66 import org.objectweb.security.context.SecurityContext;
67 import org.objectweb.security.context.SecurityCurrent;
68
69 import org.objectweb.util.monolog.api.BasicLevel;
70
71 /**
72  * This class is a factory for beans.
73  * @author Philippe Durieux
74  * @author Florent Benoit (JACC security)
75  */

76 public abstract class JFactory implements BeanFactory {
77
78     protected JContainer cont;
79
80     protected ContainerNaming naming = null;
81
82     protected TransactionManager tm = null;
83
84     protected WorkManager JavaDoc wm = null;
85
86     protected Context JavaDoc JNDICtx = null; // JNDI Context for this component
87

88     protected String JavaDoc ejbname = null;
89
90     protected BeanDesc dd;
91
92     protected Properties JavaDoc ejb10Env = null;
93
94     protected TimerService JavaDoc myTimerService = null;
95
96     protected boolean txbeanmanaged = false; // always false if entity bean
97

98     protected Class JavaDoc beanclass = null; // class of the bean instance
99

100     protected File JavaDoc passivationDir;
101
102     /**
103      * initial value for pool size
104      */

105     protected int minPoolSize;
106
107     protected int maxCacheSize;
108     
109     /**
110      * Need for checking transaction interoperability which is only needs when
111      * using iiop
112      */

113     private boolean iiopProtocolAvailable = false;
114
115     /**
116      * Transational attribute for ejbTimeout method.
117      * default is TX_REQUIRES_NEW
118      */

119     protected int timerTxAttr;
120
121     /**
122      * Signature for ejbTimeout
123      */

124     protected String JavaDoc ejbTimeoutSignature;
125
126     /**
127      * constructor (for entity) must be without parameters (required by Jorm)
128      */

129     public JFactory() {
130         if (TraceEjb.isDebugIc()) {
131             TraceEjb.interp.log(BasicLevel.DEBUG, ejbname);
132         }
133     }
134
135     /**
136      * constructor (for session)
137      * @param dd The bean deployment descriptor
138      * @param cont the container for this bean
139      */

140     public JFactory(BeanDesc dd, JContainer cont) {
141         if (TraceEjb.isDebugIc()) {
142             TraceEjb.interp.log(BasicLevel.DEBUG, "");
143         }
144         init(dd, cont);
145     }
146
147     /**
148      * Init this object
149      * @param dd the deployment descriptor
150      * @param cont the Container
151      */

152     public void init(BeanDesc dd, JContainer cont) {
153         this.cont = cont;
154         this.dd = dd;
155         naming = cont.getContainerNaming();
156         tm = cont.getTransactionManager();
157         wm = cont.getWorkManager();
158         ejbname = dd.getEjbName();
159         ejb10Env = dd.getEjb10Environment();
160         maxCacheSize = dd.getCacheMax();
161         minPoolSize = dd.getPoolMin();
162
163         // Check the JOnAS version used for deployment in case of Session or
164
// Entity
165
String JavaDoc cln = dd.getFullWrpHomeName() != null ? dd.getFullWrpHomeName() : dd.getFullWrpLocalHomeName();
166         if (cln != null) {
167             checkJonasVersion(cln);
168         }
169
170         // Create a JNDI context for this bean component
171
try {
172             JNDICtx = naming.createEnvironmentContext(ejbname);
173             cont.setBeanEnvironment(JNDICtx, dd);
174         } catch (NamingException JavaDoc e) {
175             TraceEjb.logger.log(BasicLevel.ERROR, "cannot build naming for this component", e);
176             throw new EJBException JavaDoc("Cannot build naming for this component", e);
177         }
178
179         // Get the class of the bean instance (for ejbCreate, ejbRemove, ...)
180
String JavaDoc cn = null;
181         try {
182             cn = dd.getFullDerivedBeanName();
183             beanclass = cont.getClassLoader().loadClass(cn);
184             /*
185              * This is currently being commented out. The spec doesn't exclude
186              * having the same class multiple times, just that the first class
187              * will be the one that is loaded. With this code included, this
188              * precludes a user from using the same bean classes but with
189              * different transactional attributes for example within the same
190              * ear file. // prevent from generated class name collision in a
191              * J2EE application if (!isClassAvailable(cn, true)) { throw new
192              * EJBException("Container has detected duplicated class " + cn); }
193              */

194         } catch (ClassNotFoundException JavaDoc e) {
195             TraceEjb.logger.log(BasicLevel.ERROR, "failed to find class " + cn + e);
196             throw new EJBException JavaDoc("Container failed to find class " + cn, e);
197         }
198
199         timerTxAttr = dd.getTimerTxAttribute();
200         ejbTimeoutSignature = dd.getEjbTimeoutSignature();
201
202         // check TX interop if using iiop.
203
String JavaDoc protocol = ConfigurationRepository.getCurrentConfiguration().getProtocol().getName();
204         if (protocol.equals("iiop")) {
205             iiopProtocolAvailable = true;
206         }
207
208         // mkdir a passivation directory
209
String JavaDoc pds = cont.getTmpDirName() + File.separator + dd.getIdentifier();
210         passivationDir = new File JavaDoc(pds);
211         passivationDir.mkdir();
212         if (TraceEjb.isDebugFactory()) {
213             TraceEjb.factory.log(BasicLevel.DEBUG, pds);
214         }
215     }
216
217     /**
218      * Return the WorkManager
219      */

220     public WorkManager JavaDoc getWorkManager() {
221         return wm;
222     }
223
224     /**
225      * Init the pool of instances. Not used for stateful beans
226      */

227     public abstract void initInstancePool();
228
229     /**
230      * Assess availability of a class in a given class loader
231      * @param className the name of the class without the .class extension
232      * @param unique flag indicating if the class should be found only once in
233      * the classloader
234      * @return True if class is available in the current class loader.
235      */

236     protected boolean isClassAvailable(String JavaDoc className, boolean unique) {
237         className = className.replace('.', '/') + ".class";
238         Enumeration JavaDoc e = null;
239         try {
240             e = ((URLClassLoader JavaDoc) cont.getClassLoader()).findResources(className);
241         } catch (IOException JavaDoc e1) {
242             return false;
243         }
244         if (e.hasMoreElements()) {
245             e.nextElement();
246             return unique ? !e.hasMoreElements() : true;
247         } else {
248             return false;
249         }
250     }
251
252     // ---------------------------------------------------------------
253
// BeanFactory implementation
254
// ---------------------------------------------------------------
255

256     /**
257      * @return the bean name
258      */

259     public String JavaDoc getEJBName() {
260         return ejbname;
261     }
262
263     /**
264      * @return the Instance pool size for this Ejb
265      */

266     public abstract int getPoolSize();
267
268     /**
269      * Get the Deployement descriptor of this Ejb
270      * @return BeanDesc The bean deployment descriptor
271      */

272     public BeanDesc getDeploymentDescriptor() {
273         return dd;
274     }
275
276     /**
277      * @return the TransactionManager
278      */

279     public TransactionManager getTransactionManager() {
280         return tm;
281     }
282
283     /**
284      * @return the JContainer object
285      */

286     public JContainer getContainer() {
287         return cont;
288     }
289
290     /**
291      * @return A Hashtable containing the JNDI Environment
292      */

293     public Hashtable JavaDoc getEnv() {
294         return naming.getEnv();
295     }
296
297     /**
298      * @return the InitialContext
299      */

300     public InitialContext JavaDoc getInitialContext() {
301         return naming.getInitialContext();
302     }
303
304     // ---------------------------------------------------------------
305
// other public methods
306
// ---------------------------------------------------------------
307

308     /**
309      * @return the TimerService for this bean.
310      * This works only for stateless or message driven beans.
311      */

312     public abstract TimerService JavaDoc getTimerService();
313
314     /**
315      * @return the EJB 1.0 style environment associated with the Bean
316      */

317     public Properties JavaDoc getEjb10Environment() {
318         return ejb10Env;
319     }
320
321     /**
322      * @return true if transactions are managed inside the bean false if
323      * transactions are managed by the container
324      */

325     public boolean isTxBeanManaged() {
326         return txbeanmanaged;
327     }
328
329     /**
330      * set the Component Context for JNDI environment
331      * @return previous Context
332      */

333     public Context JavaDoc setComponentContext() {
334         Context JavaDoc oldctx = naming.setComponentContext(JNDICtx);
335         if (TraceEjb.isDebugLoaderLog() && oldctx == null) {
336             TraceEjb.loaderlog.log(BasicLevel.DEBUG, "previous ctx was null");
337         }
338         return oldctx;
339     }
340
341     /**
342      * reset old Component Context for JNDI environment
343      * @param oldctx previous Component Context to restore.
344      */

345     public void resetComponentContext(Context JavaDoc oldctx) {
346         if (TraceEjb.isDebugLoaderLog() && oldctx == null) {
347             TraceEjb.loaderlog.log(BasicLevel.DEBUG, "to null");
348         }
349         naming.resetComponentContext(oldctx);
350     }
351
352     /**
353      * @return the transaction attribute for ejbTimeout method
354      */

355     public int getTimerTxAttribute() {
356         return timerTxAttr;
357     }
358
359     /**
360      * @return the security signature for ejbTimeout method.
361      */

362     public String JavaDoc getEjbTimeoutSignature() {
363         return ejbTimeoutSignature;
364     }
365
366     /**
367      * @return min pool size for Jmx
368      */

369     public int getMinPoolSize() {
370         return minPoolSize;
371     }
372
373     /**
374      * @return max cache size for Jmx
375      */

376     public int getMaxCacheSize() {
377         return maxCacheSize;
378     }
379
380     /**
381     * Check if the access to the bean is authorized
382     * @param ejbInv object containing security signature of the method, args of
383     * method, etc
384     */

385     public void checkSecurity(EJBInvocation ejbInv) {
386
387         String JavaDoc runAsRoleDD = null;
388
389         try {
390             // security controls (except for Message Driven Beans)
391
if (ejbInv != null && ejbInv.methodPermissionSignature != null) {
392                 // Check the security with the identities of the callers
393
// Establishing a run-as identity for an enterprise bean does
394
// not affect the
395
// identities of its callers, which are the identities tested
396
// for the permission
397
// to access the methods of the enterprise bean.
398
// The run-as identity establishes the identity the enterprise
399
// bean will
400
// use when it makes calls
401
// see 21.3.4.1 EJB 2.0 (Security Management / Run-as)
402
if (ejbInv.methodPermissionSignature.length() != 0) {
403                     cont.checkSecurity(ejbname, ejbInv, (dd.getRunAsRole() != null));
404                 }
405             }
406
407             runAsRoleDD = dd.getRunAsRole();
408             // And now, push the run-as role if any
409
// This role will be used for the calls of the bean
410
if (runAsRoleDD != null) {
411                 SecurityCurrent current = SecurityCurrent.getCurrent();
412                 if (current != null) {
413                     SecurityContext sctx = current.getSecurityContext();
414                     if (sctx == null) {
415                         if (TraceEjb.isDebugSecurity()) {
416                             TraceEjb.security.log(BasicLevel.DEBUG, "runas : Security context is null, create a new one"
417                                     + " in ejb " + ejbname);
418                         }
419                         sctx = new SecurityContext();
420                         current.setSecurityContext(sctx);
421                     }
422                     String JavaDoc principalName = dd.getRunAsPrincipalName();
423                     String JavaDoc[] runAsRoles = dd.getDeploymentDesc().getRolesForRunAsPrincipal(principalName);
424                     if (runAsRoles == null) {
425                         runAsRoles = new String JavaDoc[] {runAsRoleDD};
426                     }
427                     if (TraceEjb.isDebugSecurity()) {
428                         TraceEjb.security.log(BasicLevel.DEBUG, "runAs roles are ");
429                         for (int r = 0; r < runAsRoles.length; r++) {
430                             TraceEjb.security.log(BasicLevel.DEBUG, "Role[" + r + "] = " + runAsRoles[r]);
431                         }
432                         TraceEjb.security.log(BasicLevel.DEBUG, "RunAs principal name = " + principalName);
433                     }
434                     sctx.pushRunAsPrincipal(principalName, runAsRoles);
435                     sctx.pushRunAsRole(runAsRoleDD);
436                 } else {
437                     TraceEjb.security.log(BasicLevel.ERROR, "Can't push runas role as security current is null"
438                             + " in ejb " + ejbname);
439                 }
440             }
441         } catch (RuntimeException JavaDoc re) {
442             // pop run-as role
443
if (runAsRoleDD != null) {
444                 SecurityCurrent current = SecurityCurrent.getCurrent();
445                 if (current != null) {
446                     SecurityContext sctx = current.getSecurityContext();
447                     if (sctx == null) {
448                         if (TraceEjb.isDebugSecurity()) {
449                             TraceEjb.security.log(BasicLevel.DEBUG, "runas : Security context is null " + " in ejb "
450                                 + ejbname);
451                         }
452                     } else {
453                         sctx.popRunAs();
454                     }
455                 } else {
456                     if (TraceEjb.isDebugSecurity()) {
457                         TraceEjb.security.log(BasicLevel.DEBUG, "Can't pop runas role as security current is null"
458                             + " in ejb " + ejbname);
459                     }
460                 }
461             }
462             if (TraceEjb.isDebugSecurity()) {
463                 TraceEjb.logger.log(BasicLevel.DEBUG, "Security Runtime Exception", re);
464             }
465             throw re;
466         }
467
468
469     }
470
471     /**
472      * Common preInvoke
473      * @param txa Transaction Attribute (Supports, Required, ...)
474      * @return A RequestCtx object
475      * @throws EJBException
476      */

477     public RequestCtx preInvoke(int txa) {
478
479         if (TraceEjb.isDebugIc()) {
480             TraceEjb.interp.log(BasicLevel.DEBUG, "");
481         }
482         RequestCtx rctx = null;
483
484
485         try {
486             // Build a RequestCtx to save information about this request
487
// until the postInvoke time.
488
rctx = new RequestCtx(txa);
489
490             // Set classLoader to the correct value and save the previous one
491
// in the RequestCtx to restore it at the end of the Request.
492
rctx.cloader = Thread.currentThread().getContextClassLoader();
493             Thread.currentThread().setContextClassLoader(myClassLoader());
494
495             // Set bean context for JNDI and save the previous one in the
496
// RequestCtx to restore it at the end of the Request.
497
rctx.jndiCtx = setComponentContext();
498
499             // Check Transaction conformance to bean settings
500
checkTransaction(rctx);
501
502         } catch (RuntimeException JavaDoc e) {
503             // Log RuntimeException before rethrowing it
504
// -> Print Stack Trace to see where the problem is.
505
TraceEjb.logger.log(BasicLevel.ERROR, "unexpected Runtime Exception", e);
506             throw e;
507         }
508         return rctx;
509     }
510
511     /**
512      * Common postInvoke
513      * @param rctx The RequestCtx that was returned at preInvoke()
514      * @throws EJBException
515      */

516     public void postInvoke(RequestCtx rctx) {
517
518         if (TraceEjb.isDebugIc()) {
519             TraceEjb.interp.log(BasicLevel.DEBUG, "");
520         }
521
522         // WARNING: All exceptions raised here will overload those raised
523
// in the caller. (postInvoke is usually in a "finally" block)
524
try {
525             String JavaDoc runAsRoleDD = dd.getRunAsRole();
526             // Pop the run-as role if any
527
if (runAsRoleDD != null) {
528                 // Pop run-as role
529
SecurityCurrent current = SecurityCurrent.getCurrent();
530                 if (current != null) {
531                     SecurityContext sctx = current.getSecurityContext();
532                     if (sctx == null) {
533                         TraceEjb.security.log(BasicLevel.ERROR, "runas: Security context is null " + " in ejb "
534                                 + ejbname);
535                     } else {
536                         sctx.popRunAs();
537                     }
538                 } else {
539                     TraceEjb.security.log(BasicLevel.ERROR, "Can't pop runas role as security current is null"
540                             + " in ejb " + ejbname);
541                 }
542             }
543
544             // Commit the transaction started in preInvoke
545
if (rctx.mustCommit) {
546                 // Sanity check : transaction should be the same
547
try {
548                     Transaction JavaDoc t = tm.getTransaction();
549                     if (t == null) {
550                         TraceEjb.logger.log(BasicLevel.ERROR, "Transaction disappeared: " + rctx.currTx);
551                         Thread.dumpStack();
552                         throw new EJBException JavaDoc("null transaction");
553                     }
554                     if (rctx.currTx != t) {
555                         TraceEjb.logger.log(BasicLevel.ERROR, "Transaction changed: " + rctx.currTx);
556                         Thread.dumpStack();
557                         throw new EJBException JavaDoc("bad transaction :" + t);
558                     }
559                 } catch (Exception JavaDoc e) {
560                     throw new EJBException JavaDoc("Cannot get current transaction:", e);
561                 }
562
563                 if (rctx.sysExc != null) {
564                     TraceEjb.logger.log(BasicLevel.ERROR, "system exception raised by request:", rctx.sysExc);
565                     // rollback the transaction
566
try {
567                         tm.rollback();
568                     } catch (Exception JavaDoc e) {
569                         TraceEjb.logger.log(BasicLevel.ERROR, "exception during rollback:", e);
570                     }
571                 } else {
572                     try {
573                         // Check status to avoid returning RollbackException to
574
// the client
575
// instead of the application exception
576
switch (tm.getStatus()) {
577                             case Status.STATUS_ACTIVE:
578                                 if (TraceEjb.isDebugTx()) {
579                                     TraceEjb.tx.log(BasicLevel.DEBUG, "committing transaction: " + rctx.currTx);
580                                 }
581                                 tm.commit();
582                                 break;
583                             case Status.STATUS_MARKED_ROLLBACK:
584                                 if (TraceEjb.isDebugTx()) {
585                                     TraceEjb.tx.log(BasicLevel.DEBUG, "rolling back transaction: " + rctx.currTx);
586                                 }
587                                 tm.rollback();
588                                 break;
589                             default:
590                                 TraceEjb.logger.log(BasicLevel.ERROR, "unexpected transaction status " + tm.getStatus());
591                                 TraceEjb.logger.log(BasicLevel.ERROR, "transaction: " + rctx.currTx);
592                                 Thread.dumpStack();
593                                 throw new EJBException JavaDoc("unexpected transaction status :" + tm.getStatus());
594                         }
595                     } catch (RollbackException JavaDoc e) {
596                         TraceEjb.logger.log(BasicLevel.WARN, "Could not commit transaction (rolled back)");
597                         throw new TransactionRolledbackLocalException JavaDoc("Could not commit transaction", e);
598                     } catch (Exception JavaDoc e) {
599                         TraceEjb.logger.log(BasicLevel.WARN, "Could not commit transaction:" + e);
600                         throw new EJBException JavaDoc("Container exception", e);
601                     }
602                 }
603             }
604
605             // Reset class loader to the original value
606
Thread.currentThread().setContextClassLoader(rctx.cloader);
607
608             // Resume client transaction suspended in preInvoke
609
Transaction JavaDoc tx = rctx.clientTx;
610             if (tx != null) {
611                 try {
612                     if (TraceEjb.isDebugTx()) {
613                         TraceEjb.tx.log(BasicLevel.DEBUG, "resuming transaction");
614                     }
615                     tm.resume(tx);
616                 } catch (Exception JavaDoc e) {
617                     TraceEjb.logger.log(BasicLevel.ERROR, "cannot resume transaction", e);
618                 }
619             }
620
621             // We got a system Exception in business method:
622
// - log exception
623
// - discard instance
624
// - set client transaction rollback only
625
// - throw EJBException
626
if (rctx.sysExc != null) {
627                 // Log system exception
628
TraceEjb.logger.log(BasicLevel.ERROR, "system exception in business method:", rctx.sysExc);
629
630                 // If client transaction: set it rollback only and throw
631
// TransactionRolledBackLocalException
632
Transaction JavaDoc currentTx = null;
633                 try {
634                     currentTx = tm.getTransaction();
635                     if (currentTx != null) {
636                         TraceEjb.logger.log(BasicLevel.WARN, "Client transaction will rollback");
637                         currentTx.setRollbackOnly();
638                         // See spec EJB 18.3.1 + 18.4.2.3
639
if (rctx.bmcalled) {
640                             throw new TransactionRolledbackLocalException JavaDoc(rctx.sysExc.getMessage());
641                         }
642                     }
643                 } catch (SystemException JavaDoc e) {
644                     TraceEjb.logger.log(BasicLevel.ERROR, "cannot set rollback only current tx:", e);
645                 }
646                 return;
647             }
648
649             // Reset bean context for JNDI
650
resetComponentContext(rctx.jndiCtx);
651
652
653         } catch (TransactionRolledbackLocalException JavaDoc e) {
654             throw e;
655         } catch (EJBException JavaDoc e) {
656             TraceEjb.logger.log(BasicLevel.ERROR, "ejbexception: ", e);
657             throw e;
658         } catch (RuntimeException JavaDoc e) {
659             // Log RuntimeException before rethrowing it
660
// -> Print Stack Trace to see where the problem is.
661
TraceEjb.logger.log(BasicLevel.ERROR, "unexpected runtime exception: ", e);
662             throw e;
663         }
664     }
665
666     /**
667      * preInvoke for Remote access
668      * @param txa Transaction Attribute (Supports, Required, ...)
669      * @return A RequestCtx object
670      * @throws java.rmi.TransactionRequiredException
671      * @throws java.rmi.TransactionRolledbackException
672      * @throws java.rmi.NoSuchObjectException
673      * @throws RemoteException preinvoke raised an EJBException
674      */

675     public RequestCtx preInvokeRemote(int txa) throws RemoteException JavaDoc {
676         if (TraceEjb.isDebugIc()) {
677             TraceEjb.interp.log(BasicLevel.DEBUG, "");
678         }
679         try {
680             return preInvoke(txa);
681         } catch (javax.ejb.TransactionRequiredLocalException JavaDoc e) {
682             TransactionRequiredException JavaDoc tr = new TransactionRequiredException JavaDoc(e.getMessage());
683             tr.detail = e;
684             throw tr;
685         } catch (javax.ejb.TransactionRolledbackLocalException JavaDoc e) {
686             TransactionRolledbackException JavaDoc tr = new TransactionRolledbackException JavaDoc(e.getMessage());
687             tr.detail = e;
688             throw tr;
689         } catch (javax.ejb.NoSuchObjectLocalException JavaDoc e) {
690             throw NoSuchObjectExceptionHelper.create(e);
691         } catch (javax.ejb.EJBException JavaDoc e) {
692             RemoteException JavaDoc re = new RemoteException JavaDoc(e.getMessage());
693             re.detail = e;
694             throw re;
695         }
696     }
697
698     /**
699      * postInvoke for Remote access
700      * @param rctx The RequestCtx that was returne t preInvoke()
701      * @throws TransactionRequiredException
702      * @throws TransactionRolledbackException
703      * @throws NoSuchObjectException
704      * @throws RemoteException postinvoke failed
705      */

706     public void postInvokeRemote(RequestCtx rctx) throws RemoteException JavaDoc {
707         if (TraceEjb.isDebugIc()) {
708             TraceEjb.interp.log(BasicLevel.DEBUG, "");
709         }
710         try {
711             postInvoke(rctx);
712         } catch (javax.ejb.TransactionRequiredLocalException JavaDoc e) {
713             throw new javax.transaction.TransactionRequiredException JavaDoc(e.getMessage());
714         } catch (javax.ejb.TransactionRolledbackLocalException JavaDoc e) {
715             throw new javax.transaction.TransactionRolledbackException JavaDoc(e.getMessage());
716         } catch (javax.ejb.NoSuchObjectLocalException JavaDoc e) {
717             throw new java.rmi.NoSuchObjectException JavaDoc(e.getMessage());
718         } catch (javax.ejb.EJBException JavaDoc e) {
719             throw new java.rmi.RemoteException JavaDoc(e.getMessage(), e);
720         }
721     }
722
723     /**
724      * check Transaction attribute
725      * @param rctx the Request Context
726      */

727     abstract void checkTransaction(RequestCtx rctx);
728
729     // ---------------------------------------------------------------
730
// private methods
731
// ---------------------------------------------------------------
732
/**
733      * Check Transaction Interoperability requirements if the Tx comes
734      * from another vendor.
735      * For the moment JOnAS doesn't support tx interop.
736      * See EJB 2.1 ?19.6.2.2.2
737      *
738      * @param txa transaction attribute
739      *
740      */

741     private void checkTransactionInteroperability(int txa) {
742
743         // tm is never null.
744
TransactionContext transContext = ((org.objectweb.jotm.Current) tm).getPropagationContext(false);
745         if (transContext == null) {
746             return;
747         }
748
749         boolean isNullTxCtx = !transContext.isJotmCtx();
750
751         if (isNullTxCtx) {
752             switch(txa) {
753                 // in the cases below, an exception is returned to the client side in order
754
// to rollback the tx
755
case MethodDesc.TX_MANDATORY:
756                     TraceEjb.logger.log(BasicLevel.WARN, "mandatory and tx from another vendor");
757                     throw new EJBException JavaDoc("Doesn't support transaction interoperability");
758
759                 case MethodDesc.TX_REQUIRED:
760                     TraceEjb.logger.log(BasicLevel.WARN, "required and tx from another vendor");
761                     throw new EJBException JavaDoc("Doesn't support transaction interoperability");
762
763                 case MethodDesc.TX_SUPPORTS:
764                     TraceEjb.logger.log(BasicLevel.WARN, "supports and tx from another vendor");
765                     throw new EJBException JavaDoc("Doesn't support transaction interoperability");
766                 default:
767                     // nothing to do in particular for interop requirement
768
break;
769             }
770         }
771     }
772
773     /**
774      * Process Transaction Attribute before calling a business method
775      * @param rctx the Request Context
776      * @throws EJBException
777      * @throws TransactionRequiredLocalException
778      */

779     protected void checkTransactionContainer(RequestCtx rctx) {
780
781         int txa = rctx.txAttr;
782         if (TraceEjb.isDebugTx()) {
783             TraceEjb.tx.log(BasicLevel.DEBUG, "transaction attribute = " + MethodDesc.getTxAttributeName(txa));
784         }
785
786         if (txa == MethodDesc.TX_NOT_SET) {
787             // No check to do (for example: session home)
788
return;
789         }
790
791         rctx.mustCommit = false;
792         Transaction JavaDoc cltx = null;
793
794         // First of all, get the current transaction
795
Transaction JavaDoc currtx = null;
796         try {
797             currtx = tm.getTransaction();
798             if (TraceEjb.isDebugTx()) {
799                 TraceEjb.tx.log(BasicLevel.DEBUG, "currtx=" + currtx);
800             }
801         } catch (SystemException JavaDoc e) {
802             TraceEjb.logger.log(BasicLevel.ERROR, "system exception while getting transaction:", e);
803         }
804
805         // Check requirements for transaction interoperability (iiop)
806
if (iiopProtocolAvailable) {
807             checkTransactionInteroperability(txa);
808         }
809
810         // Raises exception if "Never" and we are in a transaction
811
if (txa == MethodDesc.TX_NEVER && currtx != null) {
812             TraceEjb.logger.log(BasicLevel.WARN, "never and transaction not null");
813             throw new EJBException JavaDoc("Never attribute = caller must not be in a transaction");
814         }
815
816         // Raises exception if "Mandatory" and we are not in a transaction
817
if (txa == MethodDesc.TX_MANDATORY && currtx == null) {
818             TraceEjb.logger.log(BasicLevel.WARN, "mandatory and not in transaction");
819             throw new TransactionRequiredLocalException JavaDoc("Mandatory attribute = caller must be in a transaction");
820         }
821
822         // Suspend transaction if "NotSupported" or "RequiresNew"
823
if (currtx != null && (txa == MethodDesc.TX_REQUIRES_NEW || txa == MethodDesc.TX_NOT_SUPPORTED)) {
824             try {
825                 cltx = tm.suspend();
826                 if (cltx != null && TraceEjb.isDebugTx()) {
827                     TraceEjb.tx.log(BasicLevel.DEBUG, "Suspending client tx:" + cltx);
828                 }
829                 currtx = null;
830             } catch (SystemException JavaDoc e) {
831                 TraceEjb.logger.log(BasicLevel.ERROR, "cannot suspend transaction:\n", e);
832                 throw new EJBException JavaDoc("Cannot suspend transaction", e);
833             }
834         }
835
836         // Start a new transaction in 2 cases:
837
// - "RequiresNew" attribute
838
// - "Required" and no current transaction
839
// this transaction will be closed at postInvoke.
840
if (txa == MethodDesc.TX_REQUIRES_NEW || (txa == MethodDesc.TX_REQUIRED && currtx == null)) {
841             try {
842                 tm.begin();
843                 rctx.mustCommit = true;
844                 currtx = tm.getTransaction();
845             } catch (NotSupportedException JavaDoc e) {
846                 TraceEjb.logger.log(BasicLevel.ERROR, "cannot start a transaction: NotSupportedException");
847                 throw new EJBException JavaDoc("Nested Transactions Not Supported", e);
848             } catch (SystemException JavaDoc e) {
849                 TraceEjb.logger.log(BasicLevel.ERROR, "cannot start a transaction:\n", e);
850                 throw new EJBException JavaDoc("Cannot start a transaction: SystemException", e);
851             }
852         }
853
854         // update RequestCtx
855
rctx.currTx = currtx;
856         rctx.clientTx = cltx;
857     }
858
859     /**
860      * Check if the given class have been generated by GenIC tool with a correct
861      * version. Trace an error message, if not.
862      * @param clName class name
863      */

864     protected void checkJonasVersion(String JavaDoc clName) {
865         /*
866          * Check if the static 'JONAS_VERSION' variable defined in the given
867          * class (ie GenIC's Version used to deploy the bean), has the same
868          * value as the JOnAS Version.NUMBER variable.
869          */

870         String JavaDoc fdName = "JONAS_VERSION";
871         String JavaDoc gVersion = null;
872         try {
873             // The name of the resource ends with .class and the '.' are replace
874
// with '/'
875
String JavaDoc resourceName = clName.replace('.', '/') + ".class";
876
877             // get the list of the resources for this class
878
Enumeration JavaDoc e = null;
879             try {
880                 e = cont.getClassLoader().getResources(resourceName);
881             } catch (IOException JavaDoc ioe) {
882                 TraceEjb.logger.log(BasicLevel.ERROR, "failed to find class " + clName + ioe);
883                 throw new EJBException JavaDoc("Container failed to find class " + clName, ioe);
884             }
885
886             // Count the resources
887
int nbCls = 0;
888             String JavaDoc urls = "";
889             while (e.hasMoreElements()) {
890                 nbCls++;
891                 urls += e.nextElement() + "\n";
892             }
893
894             // More than one resource.
895
if (nbCls > 1) {
896                 TraceEjb.logger
897                         .log(
898                                 BasicLevel.WARN,
899                                 "there are "
900                                         + nbCls
901                                         + " resources for the class "
902                                         + clName
903                                         + ". Some problems can occur because it's the first resource which will be loaded. The list of resources is : \n"
904                                         + urls);
905             }
906
907             // Get the class and get the value of the "JONAS_VERSION" static
908
// field
909
Class JavaDoc cl = cont.getClassLoader().loadClass(clName);
910             Field JavaDoc fd = cl.getDeclaredField("JONAS_VERSION");
911             gVersion = (String JavaDoc) fd.get(null);
912         } catch (ClassNotFoundException JavaDoc e) {
913             TraceEjb.logger.log(BasicLevel.ERROR, "failed to find class " + clName, e);
914             return;
915         } catch (NoSuchFieldException JavaDoc e) {
916             TraceEjb.logger.log(BasicLevel.ERROR, "failed to find field " + fdName + " of class " + clName, e);
917             return;
918         } catch (IllegalAccessException JavaDoc e) {
919             TraceEjb.logger.log(BasicLevel.ERROR, "failed to get the value of the field " + fdName + " of class "
920                     + clName, e);
921             return;
922         }
923         // Compare the current JOnAS version to the GenIC's Version used to
924
// deploy the bean
925
if (!Version.NUMBER.equals(gVersion)) {
926             TraceEjb.logger.log(BasicLevel.WARN, ejbname + "(Ver. " + gVersion
927                     + ") bean not deployed with the same JOnAS version(" + Version.NUMBER + "). You have to redeploy "
928                     + cont.getFileName() + ".");
929         }
930     }
931
932     /**
933      * @return the classloader for this container.
934      */

935     public ClassLoader JavaDoc myClassLoader() {
936         return cont.getClassLoader();
937     }
938 }
939
Popular Tags