KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > ejb > containers > StatefulSessionContainer


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the License). You may not use this file except in
5  * compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * https://glassfish.dev.java.net/public/CDDLv1.0.html or
9  * glassfish/bootstrap/legal/CDDLv1.0.txt.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * Header Notice in each file and include the License file
15  * at glassfish/bootstrap/legal/CDDLv1.0.txt.
16  * If applicable, add the following below the CDDL Header,
17  * with the fields enclosed by brackets [] replaced by
18  * you own identifying information:
19  * "Portions Copyrighted [year] [name of copyright owner]"
20  *
21  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
22  */

23 package com.sun.ejb.containers;
24
25 import java.util.*;
26 import java.lang.reflect.Method JavaDoc;
27 import java.rmi.RemoteException JavaDoc;
28 import java.lang.reflect.Proxy JavaDoc;
29 import java.lang.reflect.InvocationHandler JavaDoc;
30
31 import javax.ejb.*;
32 import javax.transaction.*;
33 import javax.persistence.EntityManager;
34 import javax.persistence.EntityManagerFactory;
35 import javax.rmi.PortableRemoteObject JavaDoc;
36 import javax.ejb.ConcurrentAccessException JavaDoc;
37
38 import javax.persistence.PersistenceContextType;
39
40 import com.sun.ejb.*;
41 import com.sun.enterprise.util.Utility;
42 import com.sun.enterprise.deployment.*;
43
44 import static com.sun.enterprise.deployment.LifecycleCallbackDescriptor.CallbackType;
45 import com.sun.enterprise.*;
46 import com.sun.enterprise.util.EntityManagerFactoryWrapper;
47
48 import com.sun.enterprise.log.Log;
49 import com.sun.enterprise.appverification.factory.AppVerification;
50
51 import com.sun.enterprise.admin.monitor.*;
52 import com.sun.enterprise.util.io.FileUtils;
53
54 import java.util.logging.*;
55 import com.sun.logging.*;
56
57 import com.sun.ejb.containers.util.cache.*;
58
59 import com.sun.appserv.util.cache.CacheListener;
60
61 import com.sun.enterprise.util.threadpool.Servicable;
62
63 import com.sun.ejb.base.io.IOUtils;
64
65 import com.sun.ejb.base.stats.StatefulSessionStoreMonitor;
66
67 import com.sun.ejb.containers.interceptors.InterceptorManager;
68
69 import com.sun.ejb.containers.util.ContainerWorkPool;
70
71 import com.sun.ejb.containers.util.cache.LruSessionCache;
72
73 import com.sun.ejb.spi.container.ContainerService;
74 import com.sun.ejb.spi.container.EnterpriseBeanContext;
75 import com.sun.ejb.spi.container.SFSBContainerCallback;
76 import com.sun.ejb.spi.container.StatefulEJBContext;
77
78 import com.sun.ejb.spi.sfsb.initialization.SFSBContainerInitialization;
79
80 import com.sun.ejb.spi.sfsb.store.SFSBBeanState;
81 import com.sun.ejb.spi.sfsb.store.SFSBStoreManager;
82 import com.sun.ejb.spi.sfsb.store.SFSBStoreManagerException;
83
84 import com.sun.ejb.spi.sfsb.util.CheckpointPolicy;
85 import com.sun.ejb.spi.sfsb.util.SFSBUUIDUtil;
86
87 import com.sun.ejb.spi.stats.StatefulSessionBeanStatsProvider;
88
89 import com.sun.enterprise.deployment.runtime.IASEjbExtraDescriptors;
90 import com.sun.enterprise.deployment.runtime.CheckpointAtEndOfMethodDescriptor;
91 import com.sun.enterprise.admin.monitor.callflow.ComponentType;
92
93 /** This class provides container functionality specific to stateful
94  * SessionBeans.
95  * At deployment time, one instance of the StatefulSessionContainer is created
96  * for each stateful SessionBean type (i.e. deployment descriptor) in a JAR.
97  * <P>
98  * The 5 states of a Stateful EJB (an EJB can be in only 1 state at a time):
99  * 1. PASSIVE : has been passivated
100  * 2. READY : ready for invocations, no transaction in progress
101  * 3. INVOKING : processing an invocation
102  * 4. INCOMPLETE_TX : ready for invocations, transaction in progress
103  * 5. DESTROYED : does not exist
104  *
105  * @author Mahesh Kannan
106  */

107
108 public final class StatefulSessionContainer
109     extends BaseContainer
110     implements CacheListener, SFSBContainerCallback,
111     StatefulSessionBeanStatsProvider, SFSBContainerInitialization
112 {
113     
114     private static Logger _logger =
115         LogDomains.getLogger(LogDomains.EJB_LOGGER);
116     
117     static final int PASSIVE=1, READY=2, INVOKING=3;
118     static final int INCOMPLETE_TX=4, DESTROYED=5;
119     
120     // We do not want too many ORB task for passivation
121
public static final int MIN_PASSIVATION_BATCH_COUNT = 8;
122     
123     private long instanceCount = 1;
124     
125     protected ArrayList passivationCandidates = new ArrayList();
126     private Object JavaDoc asyncTaskSemaphore = new Object JavaDoc();
127     
128     
129     private int asyncTaskCount = 0;
130     private int asyncCummTaskCount = 0;
131     
132     private int passivationBatchCount
133                     = MIN_PASSIVATION_BATCH_COUNT;
134     
135     private int containerTrimCount=0;
136         
137     private LruSessionCache sessionBeanCache;
138     private SFSBStoreManager sfsbStoreManager;
139     private SFSBUUIDUtil uuidGenerator;
140     private ArrayList scheduledTimerTasks = new ArrayList();
141
142     protected int statMethodReadyCount = 0;
143
144     private Level TRACE_LEVEL = Level.FINE;
145
146     private String JavaDoc ejbName;
147
148     private CheckpointPolicy checkpointPolicy;
149     private int removalGracePeriodInSeconds;
150
151     private StatefulSessionStoreMonitor sfsbStoreMonitor;
152
153     private final String JavaDoc traceInfoPrefix;
154
155     /*
156      * Cache for keeping ref count for shared extended entity manager.
157      * The key in this map is the physical entity manager
158      */

159     private static Map<EntityManager, Integer JavaDoc> extendedEMReferenceCountMap
160         = new HashMap<EntityManager, Integer JavaDoc>();
161     
162     /**
163      * This constructor is called from the JarManager when a Jar is deployed.
164      * @exception Exception on error
165      */

166     public StatefulSessionContainer(EjbDescriptor desc,
167             ClassLoader JavaDoc loader)
168         throws Exception JavaDoc
169     {
170         super(desc, loader);
171         super.createCallFlowAgent(ComponentType.SFSB);
172     this.ejbName = desc.getName();
173     this.traceInfoPrefix = "sfsb-" + ejbName + ": ";
174     }
175     
176     protected void initializeHome()
177         throws Exception JavaDoc
178     {
179         super.initializeHome();
180
181     loadCheckpointInfo();
182
183     registerMonitorableComponents();
184
185     }
186
187     protected void loadCheckpointInfo() {
188     try {
189         if (checkpointPolicy.isHAEnabled()) {
190         Iterator iter = invocationInfoMap.values().iterator();
191         while (iter.hasNext()) {
192             InvocationInfo info = (InvocationInfo) iter.next();
193             info.checkpointEnabled = false;
194             MethodDescriptor md = new MethodDescriptor(
195                 info.method, info.methodIntf);
196             IASEjbExtraDescriptors extraDesc =
197             ejbDescriptor.getIASEjbExtraDescriptors();
198             if (extraDesc != null) {
199             CheckpointAtEndOfMethodDescriptor cpDesc =
200                 extraDesc.getCheckpointAtEndOfMethodDescriptor();
201             if (cpDesc != null) {
202                 info.checkpointEnabled =
203                 cpDesc.isCheckpointEnabledFor(md);
204             }
205             }
206
207             if (info.checkpointEnabled) {
208             if (_logger.isLoggable(Level.FINE)) {
209                 _logger.log(Level.FINE, "[SFSBContainer] "
210                 + info.method + " MARKED for "
211                 + "end-of-method-checkpoint");
212             }
213             }
214         }
215         }
216     } catch (Exception JavaDoc ex) {
217         _logger.log(Level.WARNING, "[SFSBContainer] Exception while "
218             + " loading checkpoint info", ex);
219     }
220     }
221
222     protected void registerMonitorableComponents() {
223     registryMediator.registerProvider(this);
224     registryMediator.registerProvider(sessionBeanCache);
225         super.registerMonitorableComponents();
226     super.populateMethodMonitorMap();
227     sfsbStoreMonitor = registryMediator.registerProvider(
228         sfsbStoreManager.getMonitorableSFSBStoreManager(),
229         checkpointPolicy.isHAEnabled());
230     sessionBeanCache.setStatefulSessionStoreMonitor(sfsbStoreMonitor);
231     _logger.log(Level.FINE, "[SFSBContainer] registered monitorable");
232     }
233
234     public String JavaDoc getMonitorAttributeValues() {
235         StringBuffer JavaDoc sbuf = new StringBuffer JavaDoc();
236     //sbuf.append(storeHelper.getMonitorAttributeValues());
237
sbuf.append(" { asyncTaskCount=").append(asyncTaskCount)
238         .append("; asyncCummTaskCount=").append(asyncCummTaskCount)
239         .append("; passivationBatchCount=").append(passivationBatchCount)
240         .append("; passivationQSz=").append(passivationCandidates.size())
241         .append("; trimEventCount=").append(containerTrimCount)
242         .append(" }");
243         return sbuf.toString();
244     }
245     
246     public void appendStats(StringBuffer JavaDoc sbuf) {
247     sbuf.append("\nStatefulContainer: ")
248         .append("CreateCount=").append(statCreateCount).append("; ")
249         .append("RemoveCount=").append(statRemoveCount).append("; ")
250         .append("Size=")
251         .append(sessionBeanCache.getNumBeansInCache()).append("; ")
252         .append("ReadyCount=")
253         .append(statMethodReadyCount).append("; ");
254     sbuf.append("]");
255     }
256
257     private static final String JavaDoc convertCtxStateToString(
258     SessionContextImpl sc)
259     {
260     switch (sc.getState()) {
261         case PASSIVE: return "PASSIVE";
262         case READY: return "READY";
263         case INVOKING: return "INVOKING";
264         case INCOMPLETE_TX: return "INCOMPLETE_TX";
265         case DESTROYED: return "DESTROYED";
266     }
267     return "UNKNOWN-STATE";
268     }
269
270     boolean isIdentical(EJBObjectImpl ejbo, EJBObject other)
271         throws RemoteException JavaDoc
272     {
273         if ( other == ejbo.getStub() )
274             return true;
275         else {
276             try {
277                 // other may be a stub for a remote object.
278
if ( protocolMgr.isIdentical(ejbo.getStub(), other) )
279                     return true;
280                 else
281                     return false;
282             } catch ( Exception JavaDoc ex ) {
283                 _logger.log(Level.FINE,
284                 "Exception while getting stub for ejb",ex);
285                 throw new RemoteException JavaDoc("Error during isIdentical.", ex);
286             }
287         }
288     }
289     
290     /**
291      * This is called from the generated "HelloEJBHomeImpl" create method
292      * via EJBHomeImpl.createEJBObject.
293      * Note: for stateful beans, the HelloEJBHomeImpl.create calls
294      * ejbCreate on the new bean after createEJBObject() returns.
295      * Return the EJBObject for the bean.
296      */

297     EJBObjectImpl createEJBObjectImpl()
298         throws CreateException, RemoteException JavaDoc
299     {
300         try {
301             SessionContextImpl context = createBeanInstance();
302             EJBObjectImpl ejbObjImpl = createEJBObjectImpl(context);
303             afterInstanceCreation(context);
304             return ejbObjImpl;
305         }
306         catch (Exception JavaDoc ex) {
307             
308             _logger.log(Level.WARNING, "ejb.create_ejbobject_exception",
309                         ejbDescriptor.getName());
310             _logger.log(Level.WARNING, "create object exception", ex);
311                         
312             if ( ex instanceof EJBException )
313                 throw (EJBException)ex;
314             else {
315                 CreateException ce =
316                     new CreateException("ERROR creating stateful SessionBean");
317                 ce.initCause(ex);
318                 throw ce;
319             }
320         }
321     }
322
323     EJBObjectImpl createRemoteBusinessObjectImpl()
324         throws CreateException, RemoteException JavaDoc
325     {
326         try {
327             SessionContextImpl context = createBeanInstance();
328             EJBObjectImpl ejbBusinessObjImpl =
329                 createRemoteBusinessObjectImpl(context);
330             afterInstanceCreation(context);
331             return ejbBusinessObjImpl;
332         }
333         catch (Exception JavaDoc ex) {
334             
335             _logger.log(Level.WARNING, "ejb.create_ejbobject_exception",
336                         ejbDescriptor.getName());
337             _logger.log(Level.WARNING, "create object exception", ex);
338                         
339             if ( ex instanceof EJBException )
340                 throw (EJBException)ex;
341             else {
342                 CreateException ce =
343                     new CreateException("ERROR creating stateful SessionBean");
344                 ce.initCause(ex);
345                 throw ce;
346             }
347         }
348     }
349     
350     
351     /**
352      * This is called from the generated "HelloEJBLocalHomeImpl" create method
353      * via EJBLocalHomeImpl.createEJBObject.
354      * Note: for stateful beans, the HelloEJBLocalHomeImpl.create calls
355      * ejbCreate on the new bean after createEJBLocalObjectImpl() returns.
356      * Return the EJBLocalObject for the bean.
357      */

358     EJBLocalObjectImpl createEJBLocalObjectImpl()
359         throws CreateException
360     {
361         try {
362             SessionContextImpl context = createBeanInstance();
363             
364             EJBLocalObjectImpl localObjImpl =
365                 createEJBLocalObjectImpl(context);
366
367             afterInstanceCreation(context);
368             
369             return localObjImpl;
370         }
371         catch (Exception JavaDoc ex) {
372
373             _logger.log(Level.WARNING, "ejb.create_ejblocalobject_exception",
374                         ejbDescriptor.getName());
375             _logger.log(Level.WARNING, "create ejblocal object exception", ex);
376
377             if ( ex instanceof EJBException )
378                 throw (EJBException)ex;
379             else {
380                 CreateException ce =
381                 new CreateException("ERROR creating stateful SessionBean");
382                 ce.initCause(ex);
383                 throw ce;
384             }
385         }
386     }
387
388     /**
389      * Internal creation event for Local Business view of SFSB
390      */

391     EJBLocalObjectImpl createEJBLocalBusinessObjectImpl()
392         throws CreateException
393     {
394         try {
395             SessionContextImpl context = createBeanInstance();
396             
397             EJBLocalObjectImpl localBusinessObjImpl =
398                 createEJBLocalBusinessObjectImpl(context);
399
400             afterInstanceCreation(context);
401             
402             return localBusinessObjImpl;
403         }
404         catch (Exception JavaDoc ex) {
405
406             _logger.log(Level.WARNING, "ejb.create_ejblocalobject_exception",
407                         ejbDescriptor.getName());
408             _logger.log(Level.WARNING, "create ejblocal object exception", ex);
409
410             if ( ex instanceof EJBException )
411                 throw (EJBException)ex;
412             else {
413                 CreateException ce =
414                 new CreateException("ERROR creating stateful SessionBean");
415                 ce.initCause(ex);
416                 throw ce;
417             }
418         }
419     }
420     
421     /**
422      * Create a new Session Bean and set Session Context.
423      */

424     private SessionContextImpl createBeanInstance()
425         throws Exception JavaDoc
426     {
427         Invocation i=null;
428         try {
429             // create new (stateful) EJB
430
Object JavaDoc ejb = ejbClass.newInstance();
431             
432             // create SessionContext and set it in the EJB
433
SessionContextImpl context = new SessionContextImpl(ejb, this);
434             context.setInterceptorInstances(
435                     interceptorManager.createInterceptorInstances());
436             
437             createExtendedEMs(context);
438             
439             // Need to do preInvoke because setSessionContext can access JNDI
440
i = new Invocation(ejb, this);
441             i.context = context;
442             invocationManager.preInvoke(i);
443             
444             // setSessionContext will be called without a Tx as required
445
// by the spec, because the EJBHome.create would have been called
446
// after the container suspended any client Tx.
447
// setSessionContext is also called before createEJBObject because
448
// the bean is not allowed to do EJBContext.getEJBObject here
449
if( ejb instanceof SessionBean ) {
450                 ((SessionBean)ejb).setSessionContext(context);
451             }
452
453             // Perform injection right after where setSessionContext
454
// would be called. This is important since injection methods
455
// have the same "operations allowed" permissions as
456
// setSessionContext.
457
injectionManager.injectInstance(ejb, ejbDescriptor, false);
458             for (Object JavaDoc interceptorInstance : context.getInterceptorInstances()) {
459                 injectionManager.injectInstance(interceptorInstance,
460                         ejbDescriptor, false);
461             }
462             // Set the timestamp before inserting into bean store, else
463
// Recycler might go crazy and remove this bean!
464
context.touch();
465             
466             // Add the EJB into the session store
467
// and get the instanceKey for this EJB instance.
468
// XXX The store operation could be avoided for local-only beans.
469
Object JavaDoc sessionKey = uuidGenerator.createSessionKey();
470             sessionBeanCache.put(sessionKey, context);
471             context.setInstanceKey(sessionKey);
472
473
474
475         if (_logger.isLoggable(TRACE_LEVEL)) {
476         _logger.log(TRACE_LEVEL, "[SFSBContainer] Created "
477             + "session: " + sessionKey);
478         }
479             
480             return context;
481         } catch (Exception JavaDoc ex) {
482             throw ex;
483         } catch (Throwable JavaDoc t) {
484             EJBException ejbEx = new EJBException();
485             ejbEx.initCause(t);
486             throw ejbEx;
487         } finally {
488             if ( i != null ) {
489                 invocationManager.postInvoke(i);
490             }
491         }
492     }
493
494     private void createExtendedEMs(SessionContextImpl ctx) {
495         Set<EntityManagerReferenceDescriptor> emRefs
496             = ejbDescriptor.getEntityManagerReferenceDescriptors();
497         Iterator<EntityManagerReferenceDescriptor> iter = emRefs.iterator();
498         while (iter.hasNext()) {
499             EntityManagerReferenceDescriptor refDesc = iter.next();
500             if (refDesc.getPersistenceContextType() ==
501                 PersistenceContextType.EXTENDED) {
502                 String JavaDoc unitName = refDesc.getUnitName();
503                 EntityManagerFactory emf =
504                     EntityManagerFactoryWrapper.lookupEntityManagerFactory(
505                         ComponentInvocation.EJB_INVOCATION,
506                         unitName, ejbDescriptor);
507                 if (emf != null) {
508                     EntityManager em = findExtendedEMFromInvList(emf);
509
510                     if (em == null) {
511                         try {
512                             Map properties = refDesc.getProperties();
513                             em = emf.createEntityManager(properties);
514                             if (em == null) {
515                                 throw new EJBException
516                                     ("Couldn't create EntityManager for"
517                                         + " refName: " + refDesc.getName()
518                                         + "; unitname: " + unitName);
519                             }
520                         } catch (Throwable JavaDoc th) {
521                             throw new EJBException
522                                 ("Couldn't create EntityManager for"
523                                     + " refName: " + refDesc.getName()
524                                     + "; unitname: " + unitName);
525                         }
526                     }
527                 
528                     ctx.addExtendedEntityManagerMapping(emf, em);
529                     synchronized (extendedEMReferenceCountMap) {
530                         int refCount =
531                             (extendedEMReferenceCountMap.get(em) == null)
532                             ? 0 : extendedEMReferenceCountMap.get(em);
533                         extendedEMReferenceCountMap.put(em, refCount+1);
534                     }
535                 } else {
536                     throw new EJBException("Couldn't get extended EntityManager for"
537                             + " refName: " + refDesc.getName()
538                             + "; unitname: " + unitName);
539                 }
540             }
541         }
542     }
543     
544     private EntityManager findExtendedEMFromInvList(EntityManagerFactory emf) {
545         EntityManager em = null;
546
547         ComponentInvocation compInv = (ComponentInvocation)
548             invocationManager.getCurrentInvocation();
549         if (compInv != null) {
550             if (compInv.getInvocationType() == ComponentInvocation.EJB_INVOCATION) {
551                 if (compInv.context instanceof SessionContextImpl) {
552                     SessionContextImpl ctxImpl = (SessionContextImpl) compInv.context;
553                     if (ctxImpl.container instanceof StatefulSessionContainer) {
554                         em = ctxImpl.getExtendedEntityManager(emf);
555                     }
556                 }
557             }
558         }
559
560         return em;
561     }
562    
563     private void afterInstanceCreation(SessionContextImpl context)
564         throws Exception JavaDoc {
565
566         context.setState(READY);
567
568         Invocation i = null;
569         try {
570             // Need to do preInvoke because setSessionContext can access JNDI
571
i = new Invocation(context.getEJB(), this);
572             i.context = context;
573             invocationManager.preInvoke(i);
574             // PostConstruct must be called after state set to something
575
// other than NOT_INITIALIZED
576
interceptorManager.intercept(CallbackType.POST_CONSTRUCT, context);
577         } catch(Throwable JavaDoc t) {
578             EJBException ejbEx = new EJBException();
579             ejbEx.initCause(t);
580             throw ejbEx;
581         } finally {
582             if ( i != null ) {
583                 invocationManager.postInvoke(i);
584             }
585         }
586
587         statCreateCount++;
588         incrementMethodReadyStat();
589
590
591     }
592     
593         
594     // called from createEJBObject and activateEJB and createEJBLocalObjectImpl
595
private EJBLocalObjectImpl createEJBLocalObjectImpl
596         (SessionContextImpl context) throws Exception JavaDoc
597     {
598         if ( context.getEJBLocalObjectImpl() != null )
599             return context.getEJBLocalObjectImpl();
600         
601         // create EJBLocalObject
602
EJBLocalObjectImpl localObjImpl = instantiateEJBLocalObjectImpl();
603         
604         // introduce context and EJBLocalObject to each other
605
context.setEJBLocalObjectImpl(localObjImpl);
606         localObjImpl.setContext(context);
607         localObjImpl.setKey(context.getInstanceKey());
608         
609         if ( hasLocalBusinessView ) {
610             createEJBLocalBusinessObjectImpl(context);
611         }
612
613         if ( hasRemoteHomeView ) {
614             createEJBObjectImpl(context); // enable remote invocations too
615
}
616
617         if( hasRemoteBusinessView ) {
618             createRemoteBusinessObjectImpl(context);
619         }
620         
621         return localObjImpl;
622     }
623
624     private EJBLocalObjectImpl createEJBLocalBusinessObjectImpl
625         (SessionContextImpl context) throws Exception JavaDoc
626     {
627         if ( context.getEJBLocalBusinessObjectImpl() != null )
628             return context.getEJBLocalBusinessObjectImpl();
629         
630         EJBLocalObjectImpl localBusinessObjImpl =
631             instantiateEJBLocalBusinessObjectImpl();
632         
633         context.setEJBLocalBusinessObjectImpl(localBusinessObjImpl);
634         localBusinessObjImpl.setContext(context);
635         localBusinessObjImpl.setKey(context.getInstanceKey());
636         
637         if( hasLocalHomeView ) {
638             createEJBLocalObjectImpl(context);
639         }
640
641         if ( hasRemoteHomeView ) {
642             createEJBObjectImpl(context); // enable remote invocations too
643
}
644
645         if( hasRemoteBusinessView ) {
646             createRemoteBusinessObjectImpl(context);
647         }
648         
649         return localBusinessObjImpl;
650     }
651
652     // called from createEJBObject and activateEJB and createEJBLocalObjectImpl
653
private EJBObjectImpl createEJBObjectImpl(SessionContextImpl context)
654         throws Exception JavaDoc
655     {
656         if ( context.getEJBObjectImpl() != null )
657             return context.getEJBObjectImpl();
658         
659         // create EJBObject
660
EJBObjectImpl ejbObjImpl = instantiateEJBObjectImpl();
661         
662         // introduce context and EJBObject to each other
663
context.setEJBObjectImpl(ejbObjImpl);
664         ejbObjImpl.setContext(context);
665         Object JavaDoc sessionKey = context.getInstanceKey();
666         ejbObjImpl.setKey(sessionKey);
667         
668         // connect the EJBObject to the ProtocolManager
669
// (creates the client-side stub too)
670
byte[] sessionOID = uuidGenerator.keyToByteArray(sessionKey);
671         EJBObject ejbStub = (EJBObject)
672             remoteHomeRefFactory.createRemoteReference(sessionOID);
673
674         context.setEJBStub(ejbStub);
675         ejbObjImpl.setStub(ejbStub);
676
677         if (hasRemoteBusinessView ) {
678             createRemoteBusinessObjectImpl(context);
679         }
680         
681         if ( isLocal ) {
682             if( hasLocalHomeView ) {
683                 // enable local home invocations too
684
createEJBLocalObjectImpl(context);
685             }
686             if( hasLocalBusinessView ) {
687                 // enable local business invocations too
688
createEJBLocalBusinessObjectImpl(context);
689             }
690         }
691
692         return ejbObjImpl;
693     }
694
695     private EJBObjectImpl createRemoteBusinessObjectImpl
696         (SessionContextImpl context) throws Exception JavaDoc
697     {
698         if ( context.getEJBRemoteBusinessObjectImpl() != null )
699             return context.getEJBRemoteBusinessObjectImpl();
700         
701         // create EJBObject
702
EJBObjectImpl ejbBusinessObjImpl =
703             instantiateRemoteBusinessObjectImpl();
704         
705         context.setEJBRemoteBusinessObjectImpl(ejbBusinessObjImpl);
706         ejbBusinessObjImpl.setContext(context);
707         Object JavaDoc sessionKey = context.getInstanceKey();
708         ejbBusinessObjImpl.setKey(sessionKey);
709         
710         // connect the Remote object to the ProtocolManager
711
// (creates the client-side stub too)
712
byte[] sessionOID = uuidGenerator.keyToByteArray(sessionKey);
713         for(RemoteBusinessIntfInfo next : remoteBusinessIntfInfo.values()) {
714
715             java.rmi.Remote JavaDoc stub = next.referenceFactory.
716                 createRemoteReference(sessionOID);
717                 
718             ejbBusinessObjImpl.setStub(next.generatedRemoteIntf.getName(),
719                                        stub);
720         }
721
722         if (hasRemoteHomeView ) {
723             createEJBObjectImpl(context);
724         }
725         
726         if ( isLocal ) {
727             if( hasLocalHomeView ) {
728                 // enable local home invocations too
729
createEJBLocalObjectImpl(context);
730             }
731             if( hasLocalBusinessView ) {
732                 // enable local business invocations too
733
createEJBLocalBusinessObjectImpl(context);
734             }
735         }
736
737         return ejbBusinessObjImpl;
738     }
739     
740     
741     
742     // Called from EJBObjectImpl.remove, EJBLocalObjectImpl.remove,
743
// EJBHomeImpl.remove(Handle).
744
void removeBean(EJBLocalRemoteObject ejbo, Method JavaDoc removeMethod,
745             boolean local)
746         throws RemoveException, EJBException
747     {
748         Invocation i = new Invocation();
749         i.ejbObject = ejbo;
750         i.isLocal = local;
751         i.method = removeMethod;
752
753         // Method must be a remove method defined on one of :
754
// javax.ejb.EJBHome, javax.ejb.EJBObject, javax.ejb.EJBLocalHome,
755
// javax.ejb.EJBLocalObject
756
Class JavaDoc declaringClass = removeMethod.getDeclaringClass();
757         i.isHome = ( (declaringClass == javax.ejb.EJBHome JavaDoc.class) ||
758                      (declaringClass == javax.ejb.EJBLocalHome JavaDoc.class) );
759
760         try {
761             preInvoke(i);
762             removeBean(i);
763         } catch(Exception JavaDoc e) {
764             _logger.log(Level.FINE,"ejb.preinvoke_exception",e);
765             i.exception = e;
766         } finally {
767             if ( AppVerification.doInstrument() ) {
768                 AppVerification.getInstrumentLogger().doInstrumentForEjb
769                 (ejbDescriptor, removeMethod, i.exception);
770             }
771             
772             postInvoke(i);
773         }
774         
775         if(i.exception != null) {
776             if(i.exception instanceof RemoveException) {
777                 throw (RemoveException)i.exception;
778             }
779             else if(i.exception instanceof RuntimeException JavaDoc) {
780                 throw (RuntimeException JavaDoc)i.exception;
781             }
782             else if(i.exception instanceof Exception JavaDoc) {
783                 throw new EJBException((Exception JavaDoc)i.exception);
784             }
785             else {
786                 EJBException ejbEx = new EJBException();
787                 ejbEx.initCause(i.exception);
788                 throw ejbEx;
789             }
790         }
791     }
792     
793     
794     /**
795      * Called from EJBObjectImpl.remove().
796      * Note: preInvoke and postInvoke are called for remove().
797      */

798     private void removeBean(Invocation inv)
799         throws RemoveException
800     {
801         // At this point the EJB's state is always INVOKING
802
// because EJBObjectImpl.remove() called preInvoke().
803

804         try {
805         statRemoveCount++;
806             SessionContextImpl sc = (SessionContextImpl)inv.context;
807             Transaction tc = sc.getTransaction();
808             
809             if ( tc != null && tc.getStatus() !=
810             Status.STATUS_NO_TRANSACTION ) {
811                 // EJB2.0 section 7.6.4: remove must always be called without
812
// a transaction.
813
throw new RemoveException
814                 ("Cannot remove EJB: transaction in progress");
815             }
816             
817             // call ejbRemove on the EJB
818
if (_logger.isLoggable(TRACE_LEVEL)) {
819         _logger.log(TRACE_LEVEL, "[SFSBContainer] Removing "
820             + "session: " + sc.getInstanceKey());
821         }
822             sc.setInEjbRemove(true);
823             try {
824                 interceptorManager.intercept(
825                     CallbackType.PRE_DESTROY, sc);
826             } catch(Throwable JavaDoc t) {
827                 _logger.log(Level.FINE,
828                             "exception thrown from SFSB PRE_DESTROY", t);
829             } finally {
830                 sc.setInEjbRemove(false);
831             }
832             forceDestroyBean(sc);
833         }
834         catch ( EJBException ex ) {
835             _logger.log(Level.FINE,"EJBException in removing bean",ex);
836             throw ex;
837         }
838         catch ( RemoveException ex ) {
839             _logger.log(Level.FINE,"Remove exception while removing bean",ex);
840             throw ex;
841         }
842         catch (Exception JavaDoc ex) {
843             _logger.log(Level.FINE,"Some exception while removing bean",ex);
844             throw new EJBException(ex);
845         }
846     }
847     
848     
849     /**
850      * Force destroy the EJB and rollback any Tx it was associated with
851      * Called from removeBean, timeoutBean and BaseContainer.postInvokeTx.
852      * Note: EJB2.0 section 18.3.1 says that discarding an EJB
853      * means that no methods other than finalize() should be invoked on it.
854      */

855     void forceDestroyBean(EJBContextImpl ctx) {
856         SessionContextImpl sc = (SessionContextImpl)ctx;
857         
858         synchronized ( sc ) {
859             if ( sc.getState() == DESTROYED )
860                 return;
861             
862             // mark context as destroyed so no more invocations happen on it
863
sc.setState(DESTROYED);
864             if (_logger.isLoggable(TRACE_LEVEL)) {
865         _logger.log(TRACE_LEVEL, "[SFSBContainer] (Force)Destroying "
866             + "session: " + sc.getInstanceKey());
867         }
868
869             Transaction prevTx = sc.getTransaction();
870             try {
871                 if ( prevTx != null && prevTx.getStatus() !=
872                 Status.STATUS_NO_TRANSACTION ) {
873                     prevTx.setRollbackOnly();
874                 }
875             } catch (SystemException ex) {
876                 throw new EJBException(ex);
877             } catch (IllegalStateException JavaDoc ex) {
878                 throw new EJBException(ex);
879             }
880             
881             // remove the bean from the session store
882
Object JavaDoc sessionKey = sc.getInstanceKey();
883             sessionBeanCache.remove(sessionKey, sc.existsInStore());
884             
885             if ( isRemote ) {
886
887                 if( hasRemoteHomeView ) {
888                     // disconnect the EJBObject from the context and vice versa
889
EJBObjectImpl ejbObjImpl = sc.getEJBObjectImpl();
890                     ejbObjImpl.clearContext();
891                     ejbObjImpl.setRemoved(true);
892                     sc.setEJBObjectImpl(null);
893                     
894                     // disconnect the EJBObject from the ProtocolManager
895
// so that no remote invocations can reach the EJBObject
896
remoteHomeRefFactory.destroyReference
897                         (ejbObjImpl.getStub(), ejbObjImpl.getEJBObject());
898                 }
899
900                 if( hasRemoteBusinessView ) {
901
902                     EJBObjectImpl ejbBusinessObjImpl =
903                         sc.getEJBRemoteBusinessObjectImpl();
904                     ejbBusinessObjImpl.clearContext();
905                     ejbBusinessObjImpl.setRemoved(true);
906                     sc.setEJBRemoteBusinessObjectImpl(null);
907                     
908                     for(RemoteBusinessIntfInfo next :
909                             remoteBusinessIntfInfo.values()) {
910                         // disconnect from the ProtocolManager
911
// so that no remote invocations can get through
912
next.referenceFactory.destroyReference
913                             (ejbBusinessObjImpl.getStub
914                                 (next.generatedRemoteIntf.getName()),
915                              ejbBusinessObjImpl.getEJBObject
916                                 (next.generatedRemoteIntf.getName()));
917                     }
918                 }
919             }
920
921             if ( isLocal ) {
922                 if( hasLocalHomeView ) {
923                     // disconnect the EJBLocalObject from the context
924
// and vice versa
925
EJBLocalObjectImpl localObjImpl =
926                         (EJBLocalObjectImpl)sc.getEJBLocalObjectImpl();
927                     localObjImpl.clearContext();
928                     localObjImpl.setRemoved(true);
929                     sc.setEJBLocalObjectImpl(null);
930                 }
931                 if( hasLocalBusinessView ) {
932                     // disconnect the EJBLocalObject from the context
933
// and vice versa
934
EJBLocalObjectImpl localBusinessObjImpl =
935                         (EJBLocalObjectImpl)sc.getEJBLocalBusinessObjectImpl();
936                     localBusinessObjImpl.clearContext();
937                     localBusinessObjImpl.setRemoved(true);
938                     sc.setEJBLocalBusinessObjectImpl(null);
939                 }
940             }
941             
942             destroyExtendedEMsForContext(sc);
943             
944             // tell the TM to release resources held by the bean
945
transactionManager.ejbDestroyed(sc);
946             
947         }
948     }
949
950     private void destroyExtendedEMsForContext(SessionContextImpl sc) {
951         for (EntityManager em : sc.getExtendedEntityManagers()) {
952             synchronized (extendedEMReferenceCountMap) {
953                 if (extendedEMReferenceCountMap.containsKey(em)) {
954                     int count = extendedEMReferenceCountMap.get(em);
955                     if (count > 1) {
956                         extendedEMReferenceCountMap.put(em, count - 1);
957                         _logger.log(Level.FINE,
958                                 "Decremented RefCount ExtendedEM em: " + em);
959                     } else {
960                         _logger.log(Level.FINE, "DESTROYED ExtendedEM em: "
961                                 + em);
962                         extendedEMReferenceCountMap.remove(em);
963                         try {
964                             em.close();
965                         } catch (Throwable JavaDoc th) {
966                             _logger.log(Level.FINE,
967                                     "Exception during em.close()", th);
968                         }
969                     }
970                 }
971             }
972         }
973     }
974     
975     public boolean userTransactionMethodsAllowed(ComponentInvocation inv) {
976         boolean utMethodsAllowed = false;
977         
978         if( isBeanManagedTran ) {
979             if( inv instanceof Invocation ) {
980                 Invocation i = (Invocation) inv;
981                 SessionContextImpl sc = (SessionContextImpl) i.context;
982                 // This will prevent setSessionContext access to
983
// UserTransaction methods.
984
utMethodsAllowed = (sc.getInstanceKey() != null);
985             } else {
986                 utMethodsAllowed = true;
987             }
988         }
989         
990         return utMethodsAllowed;
991     }
992     
993     
994     public void removeTimedoutBean(EJBContextImpl ctx) {
995         // check if there is an invocation in progress for
996
// this instance.
997
synchronized (ctx) {
998             if (ctx.getState() != INVOKING) {
999                 try {
1000                    // call ejbRemove on the bean
1001
Object JavaDoc ejb = ctx.getEJB();
1002                    ctx.setInEjbRemove(true);
1003                    interceptorManager.intercept(
1004                        CallbackType.PRE_DESTROY, ctx);
1005                } catch ( Throwable JavaDoc t ) {
1006                    _logger.log(Level.FINE, "ejbRemove exception", t);
1007                } finally {
1008                    ctx.setInEjbRemove(false);
1009                }
1010        
1011        if (_logger.isLoggable(TRACE_LEVEL)) {
1012            SessionContextImpl sc = (SessionContextImpl) ctx;
1013            _logger.log(TRACE_LEVEL, "[SFSBContainer] Removing TIMEDOUT "
1014            + "session: " + sc.getInstanceKey());
1015        }
1016                
1017                forceDestroyBean(ctx);
1018            }
1019        }
1020    }
1021    
1022    
1023    /**
1024     * Called when a remote invocation arrives for an EJB.
1025     * @exception NoSuchObjectLocalException if the target object does not exist
1026     */

1027    private SessionContextImpl _getContextForInstance(byte[] instanceKey) {
1028
1029        Object JavaDoc sessionKey = uuidGenerator.byteArrayToKey(instanceKey, 0, -1);
1030
1031    if (_logger.isLoggable(TRACE_LEVEL)) {
1032        _logger.log(TRACE_LEVEL, "[SFSBContainer] Got request for: "
1033        + sessionKey);
1034    }
1035        while (true) {
1036            SessionContextImpl sc = (SessionContextImpl)
1037                sessionBeanCache.lookupEJB(sessionKey, this, null);
1038
1039            if ( sc == null ) {
1040                // EJB2.0 section 7.6
1041
// Note: the NoSuchObjectLocalException gets converted to a
1042
// remote exception by the protocol manager.
1043
throw new NoSuchObjectLocalException(
1044                    "Invalid Session Key ( " + sessionKey + ")");
1045            }
1046    
1047            synchronized (sc) {
1048                switch (sc.getState()) {
1049                    case PASSIVE: //Next cache.lookup() == different_ctx
1050
case DESTROYED: //Next cache.lookup() == null
1051
break;
1052                    default:
1053                        return sc;
1054                }
1055            }
1056        }
1057    }
1058    
1059    EJBObjectImpl getEJBObjectImpl(byte[] instanceKey) {
1060        SessionContextImpl sc = _getContextForInstance(instanceKey);
1061        return (sc != null) ? sc.getEJBObjectImpl() : null;
1062    }
1063
1064    EJBObjectImpl getEJBRemoteBusinessObjectImpl(byte[] instanceKey) {
1065        SessionContextImpl sc = _getContextForInstance(instanceKey);
1066        return (sc != null) ? sc.getEJBRemoteBusinessObjectImpl() : null;
1067    }
1068
1069    /**
1070     * Called from EJBLocalObjectImpl.getLocalObject() while deserializing
1071     * a local object reference.
1072     */

1073    EJBLocalObjectImpl getEJBLocalObjectImpl(Object JavaDoc sessionKey) {
1074
1075        // Create an EJBLocalObject reference which
1076
// is *not* associated with a SessionContext. That way, the
1077
// session bean context lookup will be done lazily whenever
1078
// the reference is actually accessed. This avoids I/O in the
1079
// case that the reference points to a passivated session bean.
1080
// It's also consistent with the deserialization approach used
1081
// throughout the container. e.g. a timer reference is deserialized
1082
// from its handle without checking it against the timer database.
1083

1084        EJBLocalObjectImpl localObjImpl;
1085
1086        try {
1087            localObjImpl = instantiateEJBLocalObjectImpl();
1088
1089            localObjImpl.setKey(sessionKey);
1090                            
1091        } catch ( Exception JavaDoc ex ) {
1092            EJBException ejbEx = new EJBException();
1093            ejbEx.initCause(ex);
1094            throw ejbEx;
1095        }
1096                
1097        return localObjImpl;
1098    }
1099    
1100    EJBLocalObjectImpl getEJBLocalBusinessObjectImpl(Object JavaDoc sessionKey) {
1101
1102        // Create an EJBLocalObject reference which
1103
// is *not* associated with a SessionContext. That way, the
1104
// session bean context lookup will be done lazily whenever
1105
// the reference is actually accessed. This avoids I/O in the
1106
// case that the reference points to a passivated session bean.
1107
// It's also consistent with the deserialization approach used
1108
// throughout the container. e.g. a timer reference is deserialized
1109
// from its handle without checking it against the timer database.
1110

1111        EJBLocalObjectImpl localBusinessObjImpl;
1112
1113        try {
1114            localBusinessObjImpl = instantiateEJBLocalBusinessObjectImpl();
1115
1116            localBusinessObjImpl.setKey(sessionKey);
1117                            
1118        } catch ( Exception JavaDoc ex ) {
1119            EJBException ejbEx = new EJBException();
1120            ejbEx.initCause(ex);
1121            throw ejbEx;
1122        }
1123                
1124        return localBusinessObjImpl;
1125    }
1126    
1127    /**
1128     * Check if the given EJBObject/LocalObject has been removed.
1129     * @exception NoSuchObjectLocalException if the object has been removed.
1130     */

1131    void checkExists(EJBLocalRemoteObject ejbObj) {
1132        if ( ejbObj.isRemoved() )
1133            throw new NoSuchObjectLocalException("Bean has been removed");
1134    }
1135    
1136    private final void logTraceInfo(Invocation inv, Object JavaDoc key, String JavaDoc message) {
1137    _logger.log(TRACE_LEVEL, traceInfoPrefix + message
1138        + " for " + inv.method.getName() + "; key: " + key);
1139    }
1140    
1141    private final void logTraceInfo(SessionContextImpl sc, String JavaDoc message) {
1142    _logger.log(TRACE_LEVEL, traceInfoPrefix + message
1143        + " for key: " + sc.getInstanceKey()
1144        + "; " + System.identityHashCode(sc));
1145    }
1146
1147    /**
1148     * Called from preInvoke which is called from the EJBObject
1149     * for local and remote invocations.
1150     */

1151    public ComponentContext _getContext(Invocation inv) {
1152        EJBLocalRemoteObject ejbo = inv.ejbObject;
1153        SessionContextImpl sc = ejbo.getContext();
1154        Object JavaDoc sessionKey = ejbo.getKey();
1155        
1156    if (_logger.isLoggable(TRACE_LEVEL)) {
1157        logTraceInfo(inv, sessionKey, "Trying to get context");
1158    }
1159
1160        if (sc == null) {
1161            // This is possible if the EJB was destroyed or passivated.
1162
// Try to activate it again.
1163
sc = (SessionContextImpl) sessionBeanCache.lookupEJB(
1164            sessionKey, this, ejbo);
1165        }
1166        
1167        if ((sc == null) || (sc.getState()==DESTROYED)) {
1168        if (_logger.isLoggable(TRACE_LEVEL)) {
1169        logTraceInfo(inv, sessionKey, "Context already destroyed");
1170        }
1171        // EJB2.0 section 7.6
1172
throw new NoSuchObjectLocalException("The EJB does not exist."
1173            + " session-key: " + sessionKey);
1174        }
1175        
1176    SessionContextImpl context = null;
1177        synchronized (sc) {
1178        SessionContextImpl newSC = sc;
1179            if ( sc.getState() == PASSIVE ) {
1180                // This is possible if the EJB was passivated after
1181
// the last lookupEJB. Try to activate it again.
1182
newSC = (SessionContextImpl) sessionBeanCache.lookupEJB(
1183            sessionKey, this, ejbo);
1184        if (newSC == null) {
1185            if (_logger.isLoggable(TRACE_LEVEL)) {
1186            logTraceInfo(inv, sessionKey, "Context does not exist");
1187            }
1188            // EJB2.0 section 7.6
1189
throw new NoSuchObjectLocalException(
1190                "The EJB does not exist. key: " + sessionKey);
1191        }
1192            }
1193            // acquire the lock again, in case a new sc was returned.
1194
synchronized (newSC) { //newSC could be same as sc
1195
// Check & set the state of the EJB
1196
if (newSC.getState()==DESTROYED ) {
1197            if (_logger.isLoggable(TRACE_LEVEL)) {
1198            logTraceInfo(inv, sessionKey, "Got destroyed context");
1199            }
1200                    throw new NoSuchObjectLocalException
1201                    ("The EJB does not exist. session-key: " + sessionKey);
1202                } else if (newSC.getState() == INVOKING ) {
1203                    handleConcurrentInvocation(inv, sessionKey);
1204                }
1205        if (newSC.getState() == READY) {
1206            decrementMethodReadyStat();
1207                }
1208        newSC.setState(INVOKING);
1209        context = newSC;
1210            }
1211        }
1212
1213        // touch the context here so timestamp is set & timeout is prevented
1214
context.touch();
1215
1216    if ((context.existsInStore()) && (removalGracePeriodInSeconds > 0)) {
1217        long now = System.currentTimeMillis();
1218        long threshold = now - (removalGracePeriodInSeconds * 1000);
1219        if (context.getLastPersistedAt() <= threshold) {
1220        try {
1221            sfsbStoreManager.updateLastAccessTime(sessionKey, now);
1222            context.setLastPersistedAt(System.currentTimeMillis());
1223        } catch (SFSBStoreManagerException sfsbEx) {
1224            _logger.log(Level.WARNING,
1225            "Couldn't update timestamp for: " + sessionKey
1226            + "; Exception: " + sfsbEx);
1227            _logger.log(Level.FINE,
1228            "Couldn't update timestamp for: " + sessionKey, sfsbEx);
1229        }
1230        }
1231    }
1232
1233    if (_logger.isLoggable(TRACE_LEVEL)) {
1234        logTraceInfo(inv, context, "Got Context!!");
1235    }
1236
1237        return context;
1238    }
1239
1240    private void handleConcurrentInvocation(Invocation inv, Object JavaDoc sessionKey) {
1241        if (_logger.isLoggable(TRACE_LEVEL)) {
1242            logTraceInfo(inv, sessionKey, "Another invocation in progress");
1243        }
1244
1245        String JavaDoc errMsg = "SessionBean is executing another request. "
1246            + "[session-key: " + sessionKey + "]";
1247        ConcurrentAccessException JavaDoc conEx = new ConcurrentAccessException JavaDoc(errMsg);
1248
1249        if (inv.isBusinessInterface) {
1250            throw conEx;
1251        } else {
1252            // there is an invocation in progress for this instance
1253
// throw an exception (EJB2.0 section 7.5.6).
1254
throw new EJBException(conEx);
1255        }
1256    }
1257
1258    public void postInvokeTx(Invocation inv) throws Exception JavaDoc {
1259        
1260        // Intercept postInvokeTx call to perform any @Remove logic
1261
// before tx commits. super.postInvokeTx() must *always*
1262
// be called.
1263

1264        // If this was an invocation of a remove-method
1265
if( inv.invocationInfo.removalInfo != null ) {
1266                
1267            InvocationInfo invInfo = inv.invocationInfo;
1268            EjbRemovalInfo removeInfo = invInfo.removalInfo;
1269                
1270            if( retainAfterRemoveMethod(inv, removeInfo) ) {
1271                // Do nothing
1272
} else {
1273                
1274                // If there is a tx, remove bean from ContainerSynch so it
1275
// won't receive any SessionSynchronization callbacks.
1276
// We delay the PreDestroy callback and instance destruction
1277
// until releaseContext so that PreDestroy won't run within
1278
// the business method's tx.
1279

1280                SessionContextImpl sc = (SessionContextImpl)inv.context;
1281                Transaction tx = sc.getTransaction();
1282
1283                if( tx != null ) {
1284                    ContainerSynchronization sync =
1285                        containerFactory.getContainerSync(tx);
1286                    sync.removeBean(sc);
1287                }
1288                
1289            }
1290        }
1291
1292        super.postInvokeTx(inv);
1293
1294    }
1295
1296    /**
1297     * Should only be called when a method is known to be a remove method.
1298     * @return true if the removal should be skipped, false otherwise.
1299     */

1300    private boolean retainAfterRemoveMethod(Invocation inv,
1301                                            EjbRemovalInfo rInfo) {
1302
1303        boolean retain =
1304            ( rInfo.getRetainIfException() &&
1305              (inv.exceptionFromBeanMethod != null) &&
1306              (isApplicationException(inv.exceptionFromBeanMethod)) );
1307
1308        return retain;
1309
1310    }
1311
1312    /**
1313     * Called from preInvoke which is called from the EJBObject
1314     * for local and remote invocations.
1315     */

1316    public void releaseContext(Invocation inv) {
1317        SessionContextImpl sc = (SessionContextImpl)inv.context;
1318        
1319        // check if the bean was destroyed
1320
if ( sc.getState()==DESTROYED )
1321            return;
1322        
1323        // we're sure that no concurrent thread can be using this
1324
// context, so no need to synchronize.
1325
Transaction tx = sc.getTransaction();
1326        try {
1327
1328            // If this was an invocation of a remove-method
1329
if( inv.invocationInfo.removalInfo != null ) {
1330                
1331                InvocationInfo invInfo = inv.invocationInfo;
1332                EjbRemovalInfo removeInfo = invInfo.removalInfo;
1333                
1334                if( retainAfterRemoveMethod(inv, removeInfo) ) {
1335                    _logger.log(Level.INFO, "Skipping destruction of SFSB " +
1336                                invInfo.ejbName + " after @Remove method " +
1337                                invInfo.method + " due to (retainIfException" +
1338                                " == true) and exception " + inv.exception);
1339                } else {
1340                    try {
1341                        // PRE-DESTROY runs in an unspecified tx context, so
1342
// we call it here in releaseContext, after
1343
// postInvokeTx has completed.
1344
interceptorManager.intercept(CallbackType.PRE_DESTROY,
1345                                                     sc);
1346                                                     
1347                    } catch(Throwable JavaDoc t) {
1348                        _logger.log(Level.FINE, "@Remove.preDestroy exception",
1349                                    t);
1350                    }
1351                    
1352                    forceDestroyBean(sc);
1353                }
1354            }
1355            
1356
1357            if ( tx==null || tx.getStatus()==Status.STATUS_NO_TRANSACTION ) {
1358                // The Bean executed with no tx, or with a tx and
1359
// container.afterCompletion() was already called.
1360
if ( sc.getState() != READY ) {
1361
1362                    if ( sc.isAfterCompletionDelayed() ) {
1363                        // ejb.afterCompletion was not called yet
1364
// because of container.afterCompletion may have
1365
// been called concurrently with this invocation.
1366
if (_logger.isLoggable(TRACE_LEVEL)) {
1367                logTraceInfo(inv, sc, "Calling delayed afterCompletion");
1368            }
1369                        callEjbAfterCompletion(sc, sc.getCompletedTxStatus());
1370                    }
1371
1372                    if (sc.getState() != DESTROYED) {
1373            //callEjbAfterCompletion could make state as DESTROYED
1374
sc.setState(READY);
1375            handleEndOfMethodCheckpoint(sc, inv);
1376            }
1377                }
1378            } else {
1379                sc.setState(INCOMPLETE_TX);
1380        if (_logger.isLoggable(TRACE_LEVEL)) {
1381            logTraceInfo(inv, sc, "Marking state == INCOMPLETE_TX");
1382        }
1383            }
1384        } catch (SystemException ex) {
1385            throw new EJBException(ex);
1386        }
1387    }
1388    
1389    
1390    void afterBegin(EJBContextImpl context) {
1391        // TX_BEAN_MANAGED EJBs cannot implement SessionSynchronization
1392
if ( isBeanManagedTran )
1393            return;
1394        // Note: this is only called for business methods.
1395
// For SessionBeans non-business methods are never called with a Tx.
1396
Object JavaDoc ejb = context.getEJB();
1397        if ( ejb instanceof SessionSynchronization ) {
1398            SessionSynchronization sync = (SessionSynchronization)ejb;
1399            try {
1400                sync.afterBegin();
1401            } catch ( Exception JavaDoc ex ) {
1402                // Error during afterBegin, so discard bean: EJB2.0 18.3.3
1403
forceDestroyBean(context);
1404                throw new EJBException("Error during SessionSynchronization." +
1405                ".afterBegin(), EJB instance discarded",
1406                ex);
1407            }
1408        }
1409
1410    //Register CMT Beans for end of Tx Checkpointing
1411
//Note:- We will never reach here for TX_BEAN_MANAGED
1412
if (checkpointPolicy.isHAEnabled()) {
1413        ContainerSynchronization cSync = null;
1414        try {
1415        cSync = containerFactory.
1416            getContainerSync(context.getTransaction());
1417        cSync.registerForTxCheckpoint(
1418            (SessionContextImpl) context);
1419        } catch (javax.transaction.RollbackException JavaDoc rollEx) {
1420                _logger.log(Level.WARNING, "Cannot register bean for "
1421            + "checkpointing", rollEx);
1422        } catch (javax.transaction.SystemException JavaDoc sysEx) {
1423                _logger.log(Level.WARNING, "Cannot register bean for "
1424            + "checkpointing", sysEx);
1425        }
1426    }
1427    }
1428    
1429    
1430    void beforeCompletion(EJBContextImpl context) {
1431        // SessionSync calls on TX_BEAN_MANAGED SessionBeans
1432
// are not allowed
1433
if ( isBeanManagedTran )
1434            return;
1435        
1436        Object JavaDoc ejb = context.getEJB();
1437        if ( !(ejb instanceof SessionSynchronization) )
1438            return;
1439        
1440        // No need to check for a concurrent invocation
1441
// because beforeCompletion can only be called after
1442
// all business methods are completed.
1443

1444        Invocation inv = new Invocation(ejb, this);
1445        inv.context = context;
1446        invocationManager.preInvoke(inv);
1447        try {
1448            transactionManager.enlistComponentResources();
1449            
1450            ((SessionSynchronization)ejb).beforeCompletion();
1451            
1452        } catch ( Exception JavaDoc ex ) {
1453            // Error during beforeCompletion, so discard bean: EJB2.0 18.3.3
1454
try {
1455                forceDestroyBean(context);
1456            } catch ( Exception JavaDoc e ) {
1457                _logger.log(Level.FINE, "error destroying bean", e);
1458            }
1459            throw new EJBException("Error during SessionSynchronization." +
1460            "beforeCompletion, EJB instance discarded",
1461            ex);
1462        } finally {
1463            invocationManager.postInvoke(inv);
1464        }
1465    }
1466    
1467    
1468    // Called from SyncImpl.afterCompletion
1469
// May be called asynchronously during tx timeout
1470
// or on the same thread as tx.commit
1471
void afterCompletion(EJBContextImpl context, int status) {
1472        if (context.getState() == DESTROYED) {
1473            return;
1474    }
1475        
1476        SessionContextImpl sc = (SessionContextImpl)context;
1477        Object JavaDoc ejb = sc.getEJB();
1478        boolean committed = (status == Status.STATUS_COMMITTED)
1479        || (status == Status.STATUS_NO_TRANSACTION);
1480        
1481        sc.setTransaction(null);
1482        
1483        // SessionSync calls on TX_BEAN_MANAGED SessionBeans
1484
// are not allowed.
1485
if ( !isBeanManagedTran && (ejb instanceof SessionSynchronization) ) {
1486            
1487            // Check for a concurrent invocation
1488
// because afterCompletion can be called asynchronously
1489
// during rollback because of transaction timeout
1490
if ((sc.getState() == INVOKING) && (!sc.isTxCompleting())) {
1491                // Cant invoke ejb.afterCompletion now because there is
1492
// already some invocation in progress on the ejb.
1493
sc.setAfterCompletionDelayed(true);
1494                sc.setCompletedTxStatus(committed);
1495        if (_logger.isLoggable(TRACE_LEVEL)) {
1496            logTraceInfo(sc, "AfterCompletion delayed");
1497        }
1498        return;
1499            }
1500            
1501            callEjbAfterCompletion(sc, committed);
1502        }
1503        
1504    //callEjbAfterCompletion can set state as DESTROYED
1505
if (sc.getState() != DESTROYED) {
1506        if (checkpointPolicy.isHAEnabled()) {
1507        if (isBeanManagedTran) {
1508            sc.setTxCheckpointDelayed(true);
1509            if (_logger.isLoggable(TRACE_LEVEL)) {
1510            logTraceInfo(sc, "(BMT)Checkpoint delayed");
1511            }
1512        }
1513        } else {
1514        if (! isBeanManagedTran) {
1515            if (_logger.isLoggable(TRACE_LEVEL)) {
1516            logTraceInfo(sc, "Released context");
1517            }
1518            sc.setState(READY);
1519            incrementMethodReadyStat();
1520        }
1521        }
1522    }
1523    }
1524
1525    SFSBBeanState getSFSBBeanState(SessionContextImpl sc) {
1526    //No need to synchronize
1527
SFSBBeanState sfsbBeanState = null;
1528    try {
1529            
1530            if ((containerState != CONTAINER_STARTED) && (containerState != CONTAINER_STOPPED)) {
1531        _logger.log(Level.FINE, "getSFSBBeanState() returning because "
1532            + "containerState: " + containerState);
1533                return null;
1534            }
1535
1536            if (sc.getState() == DESTROYED) {
1537                return null;
1538        }
1539            
1540            Object JavaDoc ejb = sc.getEJB();
1541            
1542            ComponentInvocation ci = new ComponentInvocation(ejb, this, sc);
1543            invocationManager.preInvoke(ci);
1544
1545            synchronized (sc) {
1546                try {
1547                    interceptorManager.intercept(
1548                            CallbackType.PRE_PASSIVATE, sc);
1549            sc.setLastPersistedAt(System.currentTimeMillis());
1550            byte[] serializedState = IOUtils.serializeObject(sc, true);
1551            sfsbBeanState = sfsbStoreManager.createSFSBBeanState(
1552            sc.getInstanceKey(), System.currentTimeMillis(),
1553            !sc.existsInStore(), serializedState);
1554
1555                    interceptorManager.intercept(
1556                            CallbackType.POST_ACTIVATE, sc);
1557            //Do not set sc.setExistsInStore() here
1558
} catch (java.io.NotSerializableException JavaDoc serEx) {
1559                    _logger.log(Level.WARNING, "Error during checkpoint ("
1560                                + ejbDescriptor.getName() + ". Key: "
1561                                        + sc.getInstanceKey() + ") " + serEx);
1562                    _logger.log(Level.FINE, "sfsb checkpoint error. Key: "
1563                             + sc.getInstanceKey(), serEx);
1564                    try {
1565                        forceDestroyBean(sc);
1566                    } catch ( Exception JavaDoc e ) {
1567                        _logger.log(Level.FINE, "error destroying bean", e);
1568                    }
1569                } catch (Throwable JavaDoc ex) {
1570                    _logger.log(Level.WARNING, "ejb.sfsb_checkpoint_error",
1571                                new Object JavaDoc[] { ejbDescriptor.getName() });
1572                    _logger.log(Level.WARNING, "sfsb checkpoint error. key: "
1573                             + sc.getInstanceKey(), ex);
1574                    try {
1575                        forceDestroyBean(sc);
1576                    } catch ( Exception JavaDoc e ) {
1577                        _logger.log(Level.FINE, "error destroying bean", e);
1578                    }
1579                } finally {
1580                    invocationManager.postInvoke(ci);
1581                }
1582            } //synchronized
1583

1584        } catch (Throwable JavaDoc th) {
1585        _logger.log(Level.WARNING, "ejb.sfsb_checkpoint_error",
1586        new Object JavaDoc[] { ejbDescriptor.getName() });
1587        _logger.log(Level.WARNING, "sfsb checkpoint error", th);
1588    }
1589
1590    return sfsbBeanState;
1591    }
1592
1593    void txCheckpointCompleted(SessionContextImpl sc) {
1594    if (sc.getState() != DESTROYED) {
1595            //We did persist this ctx in the store
1596
sc.setExistsInStore(true);
1597        sc.setState(READY);
1598        incrementMethodReadyStat();
1599    }
1600    }
1601
1602    private void callEjbAfterCompletion(SessionContextImpl context,
1603            boolean status)
1604    {
1605        Object JavaDoc ejb = context.getEJB();
1606        ComponentInvocation ci = new ComponentInvocation(ejb, this, context);
1607        invocationManager.preInvoke(ci);
1608        try {
1609            context.setInAfterCompletion(true);
1610            ((SessionSynchronization)ejb).afterCompletion(status);
1611            
1612            // reset flags
1613
context.setAfterCompletionDelayed(false);
1614            context.setTxCompleting(false);
1615        }
1616        catch (Exception JavaDoc ex) {
1617            // Error during afterCompletion, so discard bean: EJB2.0 18.3.3
1618
try {
1619                forceDestroyBean(context);
1620            } catch ( Exception JavaDoc e ) {
1621                _logger.log(Level.FINE, "error removing bean", e);
1622            }
1623            
1624            _logger.log(Level.INFO, "ejb.aftercompletion_exception",ex);
1625            
1626            // No use throwing an exception here, since the tx has already
1627
// completed, and afterCompletion may be called asynchronously
1628
// when there is no client to receive the exception.
1629
}
1630        finally {
1631            context.setInAfterCompletion(false);
1632            invocationManager.postInvoke(ci);
1633        }
1634    }
1635    
1636    public final boolean canPassivateEJB(ComponentContext context) {
1637        SessionContextImpl sc = (SessionContextImpl)context;
1638        return (sc.getState() == READY);
1639    }
1640    
1641    // called asynchronously from the Recycler
1642
public final boolean passivateEJB(ComponentContext context) {
1643        SessionContextImpl sc = (SessionContextImpl)context;
1644        
1645        boolean success = false;
1646        try {
1647            
1648            if ((containerState != CONTAINER_STARTED) && (containerState != CONTAINER_STOPPED)) {
1649        _logger.log(TRACE_LEVEL, "passivateEJB() returning because "
1650            + "containerState: " + containerState);
1651                return false;
1652            }
1653
1654            if ( sc.getState() == DESTROYED )
1655                return false;
1656            
1657        if (_logger.isLoggable(TRACE_LEVEL)) {
1658        _logger.log(TRACE_LEVEL, traceInfoPrefix + "Passivating context "
1659            + sc.getInstanceKey() + "; current-state = "
1660            + convertCtxStateToString(sc));
1661        }
1662
1663            Object JavaDoc ejb = sc.getEJB();
1664
1665        long passStartTime = -1;
1666        if (sfsbStoreMonitor.isMonitoringOn()) {
1667            passStartTime = System.currentTimeMillis();
1668        }
1669            
1670            ComponentInvocation ci = new ComponentInvocation(ejb, this, sc);
1671            invocationManager.preInvoke(ci);
1672
1673            boolean failed = false;
1674            
1675            success = false;
1676            synchronized (sc) {
1677                try {
1678                    // dont passivate if there is a Tx/invocation in progress
1679
// for this instance.
1680
if (! sc.canBePassivated()) {
1681                        return false;
1682                    }
1683
1684                    // passivate the EJB
1685
sc.setState(PASSIVE);
1686                    decrementMethodReadyStat();
1687                    interceptorManager.intercept(
1688                            CallbackType.PRE_PASSIVATE, sc);
1689            sc.setLastPersistedAt(System.currentTimeMillis());
1690                    boolean saved = sessionBeanCache.passivateEJB
1691                        (sc, sc.getInstanceKey());
1692                    if (! saved) {
1693                        interceptorManager.intercept(
1694                                CallbackType.POST_ACTIVATE, sc);
1695                        sc.setState(READY);
1696                        incrementMethodReadyStat();
1697                        return false;
1698                    }
1699            sfsbStoreMonitor.incrementPassivationCount(true);
1700            transactionManager.ejbDestroyed( sc );
1701                        
1702                    if ( isRemote ) {
1703
1704                        if( hasRemoteHomeView ) {
1705                            // disconnect the EJBObject from the EJB
1706
EJBObjectImpl ejbObjImpl = sc.getEJBObjectImpl();
1707                            ejbObjImpl.clearContext();
1708                            sc.setEJBObjectImpl(null);
1709                            
1710                            // disconnect the EJBObject from ProtocolManager
1711
// so that no state is held by ProtocolManager
1712
remoteHomeRefFactory.destroyReference
1713                                (ejbObjImpl.getStub(),
1714                                 ejbObjImpl.getEJBObject());
1715                        }
1716                        if( hasRemoteBusinessView ) {
1717                            // disconnect the EJBObject from the EJB
1718
EJBObjectImpl ejbBusinessObjImpl =
1719                                sc.getEJBRemoteBusinessObjectImpl();
1720                            ejbBusinessObjImpl.clearContext();
1721                            sc.setEJBRemoteBusinessObjectImpl(null);
1722                            
1723                            for(RemoteBusinessIntfInfo next :
1724                                    remoteBusinessIntfInfo.values()) {
1725                                next.referenceFactory.destroyReference
1726                                (ejbBusinessObjImpl.getStub(),
1727                                 ejbBusinessObjImpl.getEJBObject
1728                                     (next.generatedRemoteIntf.getName()));
1729                            }
1730                        }
1731                    }
1732                    if ( isLocal ) {
1733                        if( hasLocalHomeView ) {
1734                            // disconnect the EJBLocalObject from the EJB
1735
EJBLocalObjectImpl localObjImpl =
1736                                sc.getEJBLocalObjectImpl();
1737                            localObjImpl.clearContext();
1738                            sc.setEJBLocalObjectImpl(null);
1739                        }
1740                        if( hasLocalBusinessView ) {
1741                            EJBLocalObjectImpl localBusinessObjImpl =
1742                                sc.getEJBLocalBusinessObjectImpl();
1743                            localBusinessObjImpl.clearContext();
1744                            sc.setEJBLocalBusinessObjectImpl(null);
1745                        }
1746                    }
1747            if (_logger.isLoggable(TRACE_LEVEL)) {
1748            logTraceInfo(sc, "Successfully passivated");
1749            }
1750                } catch (java.io.NotSerializableException JavaDoc nsEx) {
1751                    sfsbStoreMonitor.incrementPassivationCount(false);
1752                    _logger.log(Level.WARNING, "Error during passivation: "
1753                + sc + "; " + nsEx);
1754                    _logger.log(Level.FINE, "sfsb passivation error", nsEx);
1755                    // Error during passivate, so discard bean: EJB2.0 18.3.3
1756
try {
1757                        forceDestroyBean(sc);
1758                    } catch ( Exception JavaDoc e ) {
1759                        _logger.log(Level.FINE, "error destroying bean", e);
1760                    }
1761                } catch (Throwable JavaDoc ex) {
1762                    sfsbStoreMonitor.incrementPassivationCount(false);
1763                    _logger.log(Level.WARNING, "ejb.sfsb_passivation_error",
1764                                new Object JavaDoc[] { ejbDescriptor.getName() + " <==> " + sc });
1765                    _logger.log(Level.WARNING, "sfsb passivation error. Key: "
1766                            + sc.getInstanceKey(), ex);
1767                    // Error during passivate, so discard bean: EJB2.0 18.3.3
1768
try {
1769                        forceDestroyBean(sc);
1770                    } catch ( Exception JavaDoc e ) {
1771                        _logger.log(Level.FINE, "error destroying bean", e);
1772                    }
1773                } finally {
1774                    invocationManager.postInvoke(ci);
1775            if (passStartTime != -1) {
1776            long timeSpent = System.currentTimeMillis()
1777                - passStartTime;
1778            sfsbStoreMonitor.setPassivationTime(timeSpent);
1779            }
1780                }
1781            } //synchronized
1782

1783        } catch (Exception JavaDoc ex) {
1784            _logger.log(Level.WARNING, "ejb.sfsb_passivation_error",
1785                        new Object JavaDoc[] { ejbDescriptor.getName() });
1786            _logger.log(Level.WARNING, "sfsb passivation error", ex);
1787        }
1788        return success;
1789    }
1790
1791    public final int getPassivationBatchCount() {
1792        return this.passivationBatchCount;
1793    }
1794    
1795    public final void setPassivationBatchCount(int count) {
1796        this.passivationBatchCount = count;
1797    }
1798    
1799    // called asynchronously from the Recycler
1800
public final boolean passivateEJB(StatefulEJBContext sfsbCtx) {
1801        return passivateEJB((ComponentContext) sfsbCtx.getSessionContext());
1802    }
1803
1804    public long getMethodReadyCount() {
1805    return statMethodReadyCount;
1806    }
1807
1808    public long getPassiveCount() {
1809    return (sfsbStoreMonitor == null)
1810        ? 0 : sfsbStoreMonitor.getNumPassivations();
1811    }
1812
1813    // called from StatefulSessionStore
1814
public void activateEJB(Object JavaDoc sessionKey, StatefulEJBContext sfsbCtx,
1815            Object JavaDoc cookie)
1816    {
1817        SessionContextImpl context = (SessionContextImpl)
1818            sfsbCtx.getSessionContext();
1819
1820    if (_logger.isLoggable(TRACE_LEVEL)) {
1821        logTraceInfo(context, "Attempting to activate");
1822    }
1823
1824        EJBLocalRemoteObject ejbObject = (EJBLocalRemoteObject) cookie;
1825        Object JavaDoc ejb = context.getEJB();
1826        
1827        ComponentInvocation ci = new ComponentInvocation(ejb, this, context);
1828        invocationManager.preInvoke(ci);
1829        try {
1830            // we're sure that no concurrent thread can be using this bean
1831
// so no need to synchronize.
1832

1833            // No need to call enlistComponentResources here because
1834
// ejbActivate executes in unspecified tx context (spec 6.6.1)
1835

1836            // Set the timestamp here, else Recycler might remove this bean!
1837
context.touch();
1838            
1839            context.setContainer(this);
1840            context.setState(READY);
1841            incrementMethodReadyStat();
1842            context.setInstanceKey(sessionKey);
1843            context.setExistsInStore(true);
1844
1845            if ( ejbObject == null ) {
1846
1847                // This MUST be a remote invocation
1848
if( hasRemoteHomeView ) {
1849                    createEJBObjectImpl(context);
1850                } else {
1851                    createRemoteBusinessObjectImpl(context);
1852                }
1853
1854            }
1855            else if ( ejbObject instanceof EJBObjectImpl ) {
1856
1857                EJBObjectImpl eo = (EJBObjectImpl) ejbObject;
1858                ejbObject.setContext(context);
1859                ejbObject.setKey(sessionKey);
1860
1861                byte[] sessionOID = uuidGenerator.keyToByteArray(sessionKey);
1862
1863                if( eo.isRemoteHomeView() ) {
1864
1865                    // introduce context and EJBObject to each other
1866
context.setEJBObjectImpl(eo);
1867                    
1868                    EJBObject ejbStub = (EJBObject)
1869                        remoteHomeRefFactory.createRemoteReference
1870                            (sessionOID);
1871                    eo.setStub(ejbStub);
1872                    context.setEJBStub(ejbStub);
1873                    
1874                    if( hasRemoteBusinessView ) {
1875                        createRemoteBusinessObjectImpl(context);
1876                    }
1877
1878                } else {
1879
1880                    context.setEJBRemoteBusinessObjectImpl(eo);
1881
1882                    for(RemoteBusinessIntfInfo next :
1883                            remoteBusinessIntfInfo.values()) {
1884                        java.rmi.Remote JavaDoc stub = next.referenceFactory
1885                            .createRemoteReference(sessionOID);
1886
1887                        eo.setStub(next.generatedRemoteIntf.getName(), stub);
1888                    }
1889
1890                    if( hasRemoteHomeView ) {
1891                        createEJBObjectImpl(context);
1892                    }
1893
1894                }
1895
1896                if ( isLocal ) { // create localObj too
1897
if( hasLocalHomeView ) {
1898                        createEJBLocalObjectImpl(context);
1899                    }
1900                    if( hasLocalBusinessView ) {
1901                        createEJBLocalBusinessObjectImpl(context);
1902                    }
1903                }
1904            }
1905            else if ( ejbObject instanceof EJBLocalObjectImpl ) {
1906
1907                EJBLocalObjectImpl elo = (EJBLocalObjectImpl) ejbObject;
1908                ejbObject.setContext(context);
1909                ejbObject.setKey(sessionKey);
1910
1911                if( elo.isLocalHomeView() ) {
1912                    context.setEJBLocalObjectImpl(elo);
1913                    if( hasLocalBusinessView ) {
1914                        createEJBLocalBusinessObjectImpl(context);
1915                    }
1916                } else {
1917                    context.setEJBLocalBusinessObjectImpl(elo);
1918                    if( hasLocalHomeView ) {
1919                        createEJBLocalObjectImpl(context);
1920                    }
1921
1922                }
1923                
1924                if ( hasRemoteHomeView ) { // create remote obj too
1925
createEJBObjectImpl(context);
1926                }
1927                if ( hasRemoteBusinessView ) {
1928                    createRemoteBusinessObjectImpl(context);
1929                }
1930            }
1931            
1932            try {
1933                interceptorManager.intercept(
1934                    CallbackType.POST_ACTIVATE, context);
1935            } catch (Throwable JavaDoc th) {
1936                EJBException ejbEx = new EJBException("Error during activation"
1937                        + sessionKey);
1938                ejbEx.initCause(th);
1939                throw ejbEx;
1940            }
1941            long now = System.currentTimeMillis();
1942            try {
1943                sfsbStoreManager.updateLastAccessTime(sessionKey, now);
1944                context.setLastPersistedAt(now);
1945            } catch (SFSBStoreManagerException sfsbEx) {
1946                _logger.log(Level.WARNING,
1947                "Couldn't update timestamp for: " + sessionKey
1948                + ";Exception: " + sfsbEx);
1949                _logger.log(Level.FINE,
1950                "Couldn't update timestamp for: " + sessionKey, sfsbEx);
1951            }
1952
1953            
1954        if (_logger.isLoggable(TRACE_LEVEL)) {
1955        logTraceInfo(context, "Successfully activated");
1956        }
1957        }
1958        catch ( Exception JavaDoc ex ) {
1959        if (_logger.isLoggable(TRACE_LEVEL)) {
1960        logTraceInfo(context, "Failed to activate");
1961        }
1962        _logger.log(Level.SEVERE, "ejb.sfsb_activation_error",
1963                        new Object JavaDoc[] { sessionKey });
1964            _logger.log(Level.SEVERE, "sfsb activation error. Key: "
1965                    + sessionKey, ex);
1966
1967            throw new EJBException("Unable to activate EJB for key: "
1968                                   + sessionKey, ex);
1969        }
1970        finally {
1971            invocationManager.postInvoke(ci);
1972        }
1973    }
1974
1975    public void invokePeriodically(long delay, long periodicity, Runnable JavaDoc target) {
1976        java.util.Timer JavaDoc timer = ContainerFactoryImpl.getContainerService().getTimer();
1977
1978        TimerTask timerTask = new PeriodicTask(super.loader, target);
1979        timer.scheduleAtFixedRate(timerTask, delay, periodicity);
1980        scheduledTimerTasks.add(timerTask);
1981    }
1982
1983    public ContainerService getContainerService() {
1984        return ContainerFactoryImpl.getContainerService();
1985    }
1986    
1987    //Called from Cache implementation through ContainerCallback
1988
// when cache.undeploy() is invoked
1989
public void onUndeploy(StatefulEJBContext sfsbCtx) {
1990        undeploy((SessionContextImpl) sfsbCtx.getSessionContext());
1991    }
1992    
1993    protected String JavaDoc[] getPre30LifecycleMethodNames() {
1994        return new String JavaDoc[] {
1995            null, "ejbRemove", "ejbPassivate", "ejbActivate"
1996        };
1997    };
1998
1999    /*********************************************************************/
2000    /*********** END SFSBContainerCallback methods *******************/
2001    /*********************************************************************/
2002
2003    public void onShutdown() {
2004        _logger.log(Level.FINE, "StatefulSessionContainer.onshutdown() called");
2005        super.onShutdown();
2006        cancelAllTimerTasks();
2007        sessionBeanCache.setShutdownState();
2008
2009        Iterator iter = sessionBeanCache.values();
2010        while ( iter.hasNext() ) {
2011        SessionContextImpl ctx = (SessionContextImpl) iter.next();
2012            try {
2013                sessionBeanCache.passivateEJB(
2014            (StatefulEJBContext) ctx, ctx.getInstanceKey());
2015            } catch (Exception JavaDoc ex) {
2016                _logger.log(Level.WARNING,"[" + ejbName + "]: Error while "
2017            + " saving state during shutdown. Key: "
2018            + ctx.getInstanceKey());
2019                _logger.log(Level.FINE,"[" + ejbName + "]: Error while "
2020            + " saving state during shutdown. Key: "
2021            + ctx.getInstanceKey(), ex);
2022            }
2023        }
2024        
2025        sessionBeanCache.destroy();
2026    try {
2027        sfsbStoreManager.shutdown();
2028    } catch (SFSBStoreManagerException sfsbEx) {
2029        _logger.log(Level.WARNING,"[" + ejbName + "]: Error during "
2030                            + "storeManager.shutdown()", sfsbEx);
2031    }
2032    }
2033
2034    public void undeploy() {
2035        // this will cause all new invocations to be rejected
2036
_logger.log(Level.FINE, "StatefulSessionContainer.undeploy() called");
2037        super.setUndeployedState();
2038
2039        try {
2040            cancelAllTimerTasks();
2041        sessionBeanCache.setUndeployedState();
2042
2043        Iterator iter = sessionBeanCache.values();
2044        while ( iter.hasNext() ) {
2045        SessionContextImpl ctx = (SessionContextImpl) iter.next();
2046        try {
2047            this.undeploy(ctx);
2048        } catch (Exception JavaDoc ex) {
2049            _logger.log(Level.WARNING,"[" + ejbName + "]: Error while "
2050            + " undeploying ctx. Key: "
2051            + ctx.getInstanceKey());
2052            _logger.log(Level.FINE,"[" + ejbName + "]: Error while "
2053            + " undeploying ctx. Key: "
2054            + ctx.getInstanceKey(), ex);
2055        }
2056        }
2057        
2058        sessionBeanCache.destroy();
2059        try {
2060        sfsbStoreManager.removeAll();
2061        } catch (SFSBStoreManagerException sfsbEx) {
2062        _logger.log(Level.WARNING,"[" + ejbName + "]: Error during "
2063                            + "storeManager.shutdown()", sfsbEx);
2064        }
2065        } finally {
2066            super.undeploy();
2067            
2068            // helps garbage collection
2069
//this.storeHelper = null;
2070
this.passivationCandidates = null;
2071            this.asyncTaskSemaphore = null;
2072            this.sessionBeanCache = null;
2073        }
2074    }
2075    
2076    private void cancelAllTimerTasks() {
2077        try {
2078            int size = scheduledTimerTasks.size();
2079            for (int i=0; i<size; i++) {
2080                TimerTask task = (TimerTask) scheduledTimerTasks.get(i);
2081                task.cancel();
2082            }
2083        } catch( Exception JavaDoc ex ) {}
2084    }
2085
2086    public void undeploy(SessionContextImpl ctx) {
2087        if (ctx.getContainer() == this) {
2088            if (hasRemoteHomeView) {
2089                EJBObjectImpl ejbObjectImpl = ctx.getEJBObjectImpl();
2090                if( ejbObjectImpl != null ) {
2091                    remoteHomeRefFactory.destroyReference
2092                        (ejbObjectImpl.getStub(),
2093                         ejbObjectImpl.getEJBObject());
2094                }
2095            }
2096            if (hasRemoteBusinessView) {
2097                EJBObjectImpl ejbBusinessObjectImpl =
2098                    ctx.getEJBRemoteBusinessObjectImpl();
2099                if( ejbBusinessObjectImpl != null ) {
2100                    for(RemoteBusinessIntfInfo next :
2101                            remoteBusinessIntfInfo.values()) {
2102                        next.referenceFactory.destroyReference
2103                            (ejbBusinessObjectImpl.getStub
2104                               (next.generatedRemoteIntf.getName()),
2105                             ejbBusinessObjectImpl.getEJBObject
2106                               (next.generatedRemoteIntf.getName()));
2107                    }
2108                }
2109            }
2110            sessionBeanCache.remove(ctx.getInstanceKey(), ctx.existsInStore());
2111            destroyExtendedEMsForContext(ctx);
2112            transactionManager.ejbDestroyed(ctx);
2113        }
2114    }
2115    
2116    // CacheListener interface
2117
public void trimEvent(Object JavaDoc primaryKey, Object JavaDoc context) {
2118        boolean addTask = false;
2119        synchronized (asyncTaskSemaphore) {
2120            containerTrimCount++;
2121            passivationCandidates.add(context);
2122            int requiredTaskCount =
2123            (passivationCandidates.size() / passivationBatchCount);
2124            addTask = (asyncTaskCount < requiredTaskCount);
2125
2126        if (_logger.isLoggable(Level.FINE)) {
2127        _logger.log(Level.FINE, "qSize: " + passivationCandidates.size()
2128            + "; batchCount: " + passivationBatchCount
2129            + "; asyncTaskCount: " + asyncTaskCount
2130            + "; requiredTaskCount: " + requiredTaskCount
2131            + "; ADDED TASK ==> " + addTask);
2132        }
2133
2134            if (addTask == false) {
2135                return;
2136            }
2137            asyncTaskCount++;
2138            asyncCummTaskCount++;
2139        }
2140        
2141        
2142        try {
2143            ASyncPassivator work = new ASyncPassivator();
2144            ContainerWorkPool.addLast(work);
2145        } catch (Exception JavaDoc ex) {
2146            synchronized (asyncTaskSemaphore) {
2147                asyncTaskCount--;
2148            }
2149            _logger.log(Level.WARNING, "ejb.add_cleanup_task_error",ex);
2150        }
2151        
2152    }
2153    
2154    /*
2155    class PassivateRunner
2156        implements Runnable
2157    {
2158        private ComponentContext ctx;
2159        PassivateRunner(ComponentContext ctx) {
2160            this.ctx = ctx;
2161        }
2162        
2163        public void run() {
2164            if (ctx != null) {
2165                Thread t = Thread.currentThread();
2166                ClassLoader cl = t.getContextClassLoader();
2167                t.setContextClassLoader(loader);
2168                passivateEJB(ctx);
2169                t.setContextClassLoader(cl);
2170            }
2171        }
2172    }
2173    */

2174    
2175    private class ASyncPassivator implements Servicable {
2176        
2177        public void prolog() { }
2178        
2179        public void epilog() { }
2180        
2181        public void service() { run(); }
2182        
2183        public void run() {
2184            final Thread JavaDoc currentThread = Thread.currentThread();
2185            final ClassLoader JavaDoc previousClassLoader =
2186            currentThread.getContextClassLoader();
2187            final ClassLoader JavaDoc myClassLoader = loader;
2188            
2189            boolean decrementedTaskCount = false;
2190            try {
2191                // We need to set the context class loader for
2192
// this (deamon) thread!!
2193

2194                java.security.AccessController.doPrivileged
2195                (new java.security.PrivilegedAction JavaDoc() {
2196                    public java.lang.Object JavaDoc run() {
2197                        currentThread.setContextClassLoader(loader);
2198                        return null;
2199                    }
2200                });
2201                ComponentContext ctx = null;
2202                
2203                do {
2204                    synchronized (asyncTaskSemaphore) {
2205                        int sz = passivationCandidates.size();
2206                        if (sz > 0) {
2207                            ctx = (ComponentContext)
2208                                passivationCandidates.remove(sz-1);
2209                        } else {
2210                            return;
2211                        }
2212                    }
2213                    passivateEJB(ctx);
2214                } while (true);
2215                
2216            } catch (Throwable JavaDoc th) {
2217                th.printStackTrace();
2218            } finally {
2219                if (! decrementedTaskCount) {
2220                    synchronized (asyncTaskSemaphore) {
2221                        asyncTaskCount--;
2222                    }
2223                }
2224                
2225                java.security.AccessController.doPrivileged
2226                (new java.security.PrivilegedAction JavaDoc() {
2227                    public java.lang.Object JavaDoc run() {
2228                        currentThread.setContextClassLoader
2229                        (previousClassLoader);
2230                        return null;
2231                    }
2232                });
2233            }
2234        }
2235    }
2236    
2237    //*******************************************************//
2238
//**** Implementation of SFSBContainerInitialization ****//
2239
//*******************************************************//
2240

2241    public void setSFSBUUIDUtil(SFSBUUIDUtil util) {
2242    this.uuidGenerator = util;
2243    }
2244
2245    public void setCheckpointPolicy(CheckpointPolicy policy) {
2246    this.checkpointPolicy = policy;
2247    }
2248
2249    public void setSFSBStoreManager(SFSBStoreManager storeManager) {
2250    this.sfsbStoreManager = storeManager;
2251    }
2252
2253    public void setSessionCache(LruSessionCache cache) {
2254    this.sessionBeanCache = cache;
2255    }
2256
2257    public SFSBStoreManager getSFSBStoreManager() {
2258    return this.sfsbStoreManager;
2259    }
2260
2261    public void setRemovalGracePeriodInSeconds(int val) {
2262    this.removalGracePeriodInSeconds = val;
2263    }
2264
2265    public void removeExpiredSessions() {
2266    try {
2267        _logger.log(Level.FINE, "StatefulContainer Removing expired sessions....");
2268        long val = sfsbStoreManager.removeExpiredSessions();
2269        sfsbStoreMonitor.incrementExpiredSessionsRemoved(val);
2270        _logger.log(Level.FINE, "StatefulContainer Removed " + val + " sessions....");
2271    } catch (SFSBStoreManagerException sfsbEx) {
2272        _logger.log(Level.WARNING, "Got exception from store manager",
2273        sfsbEx);
2274    }
2275    }
2276
2277    ///////////////////////////////////////////////////////////
2278

2279    private void handleEndOfMethodCheckpoint(SessionContextImpl sc,
2280        Invocation inv)
2281    {
2282    int txAttr = inv.invocationInfo.txAttr;
2283    switch (txAttr) {
2284        case TX_NEVER:
2285        case TX_SUPPORTS:
2286        case TX_NOT_SUPPORTED:
2287        if (inv.invocationInfo.checkpointEnabled) {
2288            checkpointEJB(sc);
2289        }
2290        break;
2291        case TX_BEAN_MANAGED:
2292        if (sc.isTxCheckpointDelayed()
2293            || inv.invocationInfo.checkpointEnabled)
2294        {
2295            checkpointEJB(sc);
2296            sc.setTxCheckpointDelayed(false);
2297        }
2298        break;
2299        default:
2300        if (inv.invocationInfo.isCreateHomeFinder) {
2301            if (inv.invocationInfo.checkpointEnabled) {
2302            checkpointEJB(sc);
2303            }
2304        }
2305        break;
2306    }
2307
2308    if (sc.getState() != DESTROYED) {
2309        sc.setState(READY);
2310        incrementMethodReadyStat();
2311        if (_logger.isLoggable(TRACE_LEVEL)) {
2312        logTraceInfo(inv, sc.getInstanceKey(), "Released context");
2313        }
2314    }
2315    }
2316
2317    //methods for StatefulSessionBeanStatsProvider
2318
public int getMaxCacheSize() {
2319    return sessionBeanCache.getMaxCacheSize();
2320    }
2321
2322    private boolean checkpointEJB(SessionContextImpl sc) {
2323        
2324        boolean checkpointed = false;
2325        try {
2326            
2327            if ((containerState != CONTAINER_STARTED) && (containerState != CONTAINER_STOPPED)) {
2328        _logger.log(Level.FINE, "passivateEJB() returning because "
2329            + "containerState: " + containerState);
2330                return false;
2331            }
2332
2333            if (sc.getState() == DESTROYED) {
2334                return false;
2335        }
2336            
2337            Object JavaDoc ejb = sc.getEJB();
2338            
2339        long checkpointStartTime = -1;
2340        if (sfsbStoreMonitor.isMonitoringOn()) {
2341            checkpointStartTime = System.currentTimeMillis();
2342        }
2343
2344            ComponentInvocation ci = new ComponentInvocation(ejb, this, sc);
2345            invocationManager.preInvoke(ci);
2346
2347            synchronized (sc) {
2348                try {
2349                    // dont passivate if there is a Tx/invocation in progress
2350
// for this instance.
2351
if (sc.getState() != READY) {
2352                        return false;
2353                    }
2354
2355                    // passivate the EJB
2356
sc.setState(PASSIVE);
2357                    decrementMethodReadyStat();
2358                    interceptorManager.intercept(
2359                            CallbackType.PRE_PASSIVATE, sc);
2360            sc.setLastPersistedAt(System.currentTimeMillis());
2361            byte[] serializedState = IOUtils.serializeObject(sc, true);
2362            SFSBBeanState beanState =
2363            sfsbStoreManager.createSFSBBeanState(
2364                sc.getInstanceKey(), sc.getLastAccessTime(),
2365                !sc.existsInStore(), serializedState);
2366            try {
2367            sfsbStoreManager.checkpointSave(beanState);
2368
2369            //Now that we have successfully stored.....
2370
sc.setLastPersistedAt(System.currentTimeMillis());
2371            sc.setExistsInStore(true);
2372            } catch (Exception JavaDoc ignorableEx) {
2373            _logger.log(Level.WARNING,
2374                "Error during checkpoint", ignorableEx);
2375            }
2376
2377                    interceptorManager.intercept(
2378                            CallbackType.POST_ACTIVATE, sc);
2379                    sc.setState(READY);
2380                    incrementMethodReadyStat();
2381            sfsbStoreMonitor.setCheckpointSize(serializedState.length);
2382            sfsbStoreMonitor.incrementCheckpointCount(true);
2383                } catch (Throwable JavaDoc ex) {
2384            sfsbStoreMonitor.incrementCheckpointCount(false);
2385                    _logger.log(Level.WARNING, "ejb.sfsb_checkpoint_error",
2386                                new Object JavaDoc[] { ejbDescriptor.getName() });
2387                    _logger.log(Level.WARNING, "sfsb checkpoint error. Key: "
2388                            + sc.getInstanceKey(), ex);
2389                    try {
2390                        forceDestroyBean(sc);
2391                    } catch ( Exception JavaDoc e ) {
2392                        _logger.log(Level.FINE, "error destroying bean", e);
2393                    }
2394                } finally {
2395                    invocationManager.postInvoke(ci);
2396            if (checkpointStartTime != -1) {
2397            long timeSpent = System.currentTimeMillis()
2398                - checkpointStartTime;
2399            sfsbStoreMonitor.setCheckpointTime(timeSpent);
2400            }
2401                }
2402            } //synchronized
2403

2404        } catch (Exception JavaDoc ex) {
2405            _logger.log(Level.WARNING, "ejb.sfsb_passivation_error",
2406                        new Object JavaDoc[] { ejbDescriptor.getName() });
2407            _logger.log(Level.WARNING, "sfsb passivation error", ex);
2408        }
2409
2410        return checkpointed;
2411    }
2412    
2413    public void incrementMethodReadyStat() {
2414        statMethodReadyCount++;
2415    }
2416    
2417    public void decrementMethodReadyStat() {
2418        statMethodReadyCount--;
2419    }
2420    
2421}
2422
2423class PeriodicTask
2424    extends java.util.TimerTask JavaDoc
2425{
2426    ClassLoader JavaDoc classLoader;
2427    AsynchronousTask task;
2428
2429    PeriodicTask(ClassLoader JavaDoc classLoader, Runnable JavaDoc target) {
2430        this.classLoader = classLoader;
2431        this.task = new AsynchronousTask(target);
2432    }
2433        
2434    public void run() {
2435        if (! task.isExecuting()) {
2436            ContainerFactoryImpl.getContainerService().
2437        scheduleWork(classLoader, task);
2438        }
2439    }
2440
2441    public boolean cancel() {
2442        boolean cancelled = super.cancel();
2443
2444        this.classLoader = null;
2445        this.task = null;
2446
2447        return cancelled;
2448    }
2449}
2450
2451class AsynchronousTask
2452    implements Runnable JavaDoc
2453{
2454    Runnable JavaDoc target;
2455    boolean executing;
2456
2457    AsynchronousTask(Runnable JavaDoc target) {
2458        this.target = target;
2459        this.executing = false;
2460    }
2461        
2462    boolean isExecuting() {
2463        return executing;
2464    }
2465
2466    //This will be called with the correct ClassLoader
2467
public void run() {
2468        try {
2469            target.run();
2470        } finally {
2471            executing = false;
2472        }
2473    } // end run
2474
}
2475
2476
Popular Tags