KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openejb > core > stateful > StatefulInstanceManager


1 /**
2  * Redistribution and use of this software and associated documentation
3  * ("Software"), with or without modification, are permitted provided
4  * that the following conditions are met:
5  *
6  * 1. Redistributions of source code must retain copyright
7  * statements and notices. Redistributions must also contain a
8  * copy of this document.
9  *
10  * 2. Redistributions in binary form must reproduce the
11  * above copyright notice, this list of conditions and the
12  * following disclaimer in the documentation and/or other
13  * materials provided with the distribution.
14  *
15  * 3. The name "Exolab" must not be used to endorse or promote
16  * products derived from this Software without prior written
17  * permission of Exoffice Technologies. For written permission,
18  * please contact info@exolab.org.
19  *
20  * 4. Products derived from this Software may not be called "Exolab"
21  * nor may "Exolab" appear in their names without prior written
22  * permission of Exoffice Technologies. Exolab is a registered
23  * trademark of Exoffice Technologies.
24  *
25  * 5. Due credit should be given to the Exolab Project
26  * (http://www.exolab.org/).
27  *
28  * THIS SOFTWARE IS PROVIDED BY EXOFFICE TECHNOLOGIES AND CONTRIBUTORS
29  * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
30  * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
31  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
32  * EXOFFICE TECHNOLOGIES OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
33  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
34  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
35  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
37  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
39  * OF THE POSSIBILITY OF SUCH DAMAGE.
40  *
41  * Copyright 1999 (C) Exoffice Technologies Inc. All Rights Reserved.
42  *
43  * $Id: StatefulInstanceManager.java 1921 2005-06-19 22:40:34Z jlaskowski $
44  */

45
46
47 package org.openejb.core.stateful;
48
49 import java.rmi.RemoteException JavaDoc;
50 import java.util.Hashtable JavaDoc;
51 import java.util.Properties JavaDoc;
52
53 import javax.ejb.EJBException JavaDoc;
54 import javax.ejb.EnterpriseBean JavaDoc;
55 import javax.ejb.SessionBean JavaDoc;
56 import javax.transaction.Status JavaDoc;
57 import javax.transaction.Transaction JavaDoc;
58 import javax.transaction.TransactionManager JavaDoc;
59
60 import org.openejb.ApplicationException;
61 import org.openejb.InvalidateReferenceException;
62 import org.openejb.OpenEJB;
63 import org.openejb.OpenEJBException;
64 import org.openejb.SystemException;
65 import org.openejb.core.EnvProps;
66 import org.openejb.core.Operations;
67 import org.openejb.core.ThreadContext;
68 import org.openejb.core.ivm.IntraVmCopyMonitor;
69 import org.openejb.util.Logger;
70 import org.openejb.util.OpenEJBErrorHandler;
71 import org.openejb.util.SafeProperties;
72 import org.openejb.util.SafeToolkit;
73
74 /**
75  *
76  * @author <a HREF="mailto:Richard@Monson-Haefel.com">Richard Monson-Haefel</a>
77  * @author <a HREF="mailto:david.blevins@visi.com">David Blevins</a>
78  * @version $Revision: 1921 $ $Date: 2005-06-19 15:40:34 -0700 (Sun, 19 Jun 2005) $
79  */

80 public class StatefulInstanceManager {
81
82     /**
83      * Represents the time-out period for a stateful bean instance in milliseconds.
84      * Measured as the time between method invocations.
85      */

86     protected long timeOUT = 0;
87
88     /**
89      * This index keeps track of all beans that are not passivated. A bean in the
90      * method ready or "method ready in transaction" pools will be in this index.
91      * Passivated beans are not in this index.
92      */

93     protected Hashtable JavaDoc beanINDEX = new Hashtable JavaDoc();
94
95     /**
96      * This colleciton keeps track of all beans that are in the method ready pool
97      * and are not passivated. Beans that are enrolled in a current transaction
98      * are NOT elements of this collection. Only beans in the lruQUE may be
99      * passivated or timeout.
100      */

101     protected BeanEntryQue lruQUE;// que of beans for LRU algorithm
102

103     /**
104      * The passivator is responsible for writing beans to disk at passivation time.
105      * Different passivators can be used and are chosen by setting the
106      * EnvProps.IM_PASSIVATOR property used in initialization of this instance to
107      * a the fully qualified class name of the PassivationStrategy. The passivator
108      * is not responsible for invoking any callbacks or other processing. Its only
109      * responsibly is to write the bean state to disk.
110      */

111     protected PassivationStrategy passivator;
112
113     /**
114      * Timeout Manager
115      */

116     protected int BULK_PASSIVATION_SIZE = 100;
117
118     protected SafeToolkit toolkit = SafeToolkit.getToolkit("StatefulInstanceManager");
119
120     /**
121      * CONSTRUCTOR METHODS
122      */

123     public StatefulInstanceManager( ) {
124     }
125
126     /**********************************************************************
127             InstanceManager INTERFACE METHODS
128     ***********************************************************************/

129     /**
130      * Fully instaniates this instance manager and assigns it to the specified
131      * ContainerManager. The properities passed in a re retrieved from the section
132      * of the OpenEJB XML config that defines this instance manager.
133      *
134      * @param props the properties the instance manager needs to fully initialize and run
135      * @exception OpenEJBException
136      * if there is a problem initializing this instance manager
137      */

138     public void init(Properties JavaDoc props)
139     throws OpenEJBException{
140
141         SafeProperties safeProps = toolkit.getSafeProperties(props);
142
143         String JavaDoc passivatorClass=null;
144         try {
145             passivatorClass = safeProps.getProperty(EnvProps.IM_PASSIVATOR);
146         } catch ( org.openejb.OpenEJBException e ) {
147             // try old property name for backward compat
148
try {
149                 passivatorClass = safeProps.getProperty("org/openejb/core/InstanceManager/PASSIVATOR");
150             } catch ( org.openejb.OpenEJBException e1 ) {
151                 //throw old exception
152
throw e;
153             }
154         }
155
156         try {
157             passivator = (PassivationStrategy)toolkit.newInstance(passivatorClass);
158         } catch ( Exception JavaDoc e ) {
159             OpenEJBErrorHandler.propertyValueIsIllegal(EnvProps.IM_PASSIVATOR, passivatorClass, e.getLocalizedMessage());
160         }
161         passivator.init(props);
162
163         int poolSize = safeProps.getPropertyAsInt(EnvProps.IM_POOL_SIZE, 100);
164         int timeOutInMinutes = safeProps.getPropertyAsInt(EnvProps.IM_TIME_OUT,5);
165         int bulkPassivationSize = safeProps.getPropertyAsInt(EnvProps.IM_PASSIVATE_SIZE,(int)(poolSize*.25));
166
167
168         lruQUE = new BeanEntryQue(poolSize);
169         BULK_PASSIVATION_SIZE = (bulkPassivationSize > poolSize)? poolSize: bulkPassivationSize;
170         timeOUT = timeOutInMinutes*60*1000; // (minutes x 60 sec x 1000 milisec)
171
}
172
173     /**
174      * Gets the ancillary state object of the instance with the specified
175      * primaryKey.
176      *
177      * The Ancillary state object is used to hold additional information specific
178      * to the bean instance that is not captured by the instance itself.
179      *
180      * Example:
181      *
182      * The org.openejb.core.StatefulContainer uses a ancillary object to store the
183      * client identity (unique identity of the JVM and computer) that created the
184      * stateful bean instance.
185      *
186      * @param primaryKey the primary key of the bean instance
187      * @return the ancillary state object
188      * @exception OpenEJBException if there is a problem retrieving the ancillary state object
189      */

190     public Object JavaDoc getAncillaryState(Object JavaDoc primaryKey)
191     throws OpenEJBException{
192         return this.getBeanEntry(primaryKey).ancillaryState;
193     }
194
195     /**
196      * Sets the ancillary state of the bean instance with the specified primaryKey
197      *
198      * Setting the ancillary state after modifing it is not necessary, because
199      * getAncillary state returns an object reference.
200      *
201      * @param primaryKey the unique key that can identify the instance being managed
202      * @param ancillaryState
203      * the new ancillary state of the bean instance in this instance manager
204      * @exception OpenEJBException
205      * if there is a problem setting the ancillary state object
206      */

207     public void setAncillaryState(Object JavaDoc primaryKey, Object JavaDoc ancillaryState)
208     throws OpenEJBException{
209         BeanEntry entry = getBeanEntry(primaryKey);
210         entry.ancillaryState = ancillaryState;
211         if ( ancillaryState instanceof javax.transaction.Transaction JavaDoc )
212             entry.transaction = (javax.transaction.Transaction JavaDoc)ancillaryState;
213
214     }
215
216     /**
217      * Instantiates and returns an new instance of the specified bean class.
218      *
219      * @param primaryKey the unique key that can identify the instance being managed
220      * @param beanClass the type of the bean's class
221      * @return an new instance of the bean class
222      * @exception OpenEJBException
223      * if there is a problem initializing the bean class
224      */

225     public EnterpriseBean JavaDoc newInstance(Object JavaDoc primaryKey, Class JavaDoc beanClass)
226     throws OpenEJBException{
227         return this.newInstance(primaryKey,null, beanClass);
228     }
229
230     /**
231      * Instantiates and returns an new instance of the specified bean class.
232      *
233      * @param primaryKey the unique key that can identify the instance being managed
234      * @param ancillaryState
235      * the ancillary state of the bean instance in this instance manager
236      * @param beanClass the type of the bean's class
237      * @return an new instance of the bean class
238      * @exception OpenEJBException
239      * if there is a problem initializing the bean class
240      */

241     public EnterpriseBean JavaDoc newInstance(Object JavaDoc primaryKey, Object JavaDoc ancillaryState, Class JavaDoc beanClass)
242     throws OpenEJBException{
243
244         SessionBean JavaDoc bean = null;
245
246         try {
247             bean = (SessionBean JavaDoc)toolkit.newInstance(beanClass);
248         } catch ( OpenEJBException oee ) {
249             logger.error("Can't instantiate new instance of class +"+beanClass.getName()+". Received exception "+oee, oee);
250             throw (SystemException)oee;
251         }
252
253         ThreadContext thrdCntx = ThreadContext.getThreadContext();
254         byte currentOp = thrdCntx.getCurrentOperation();
255         thrdCntx.setCurrentOperation(Operations.OP_SET_CONTEXT);
256         try {
257             bean.setSessionContext((javax.ejb.SessionContext JavaDoc)thrdCntx.getDeploymentInfo().getEJBContext());
258         } catch ( Throwable JavaDoc callbackException ) {
259             /*
260             In the event of an exception, OpenEJB is required to log the exception, evict the instance,
261             and mark the transaction for rollback. If there is a transaction to rollback, then the a
262             javax.transaction.TransactionRolledbackException must be throw to the client. Otherwise a
263             java.rmi.RemoteException is thrown to the client.
264             See EJB 1.1 specification, section 12.3.2
265             See EJB 2.0 specification, section 18.3.3
266             */

267             handleCallbackException(callbackException, bean, thrdCntx, "setSessionContext");
268         } finally {
269             thrdCntx.setCurrentOperation(currentOp);
270         }
271
272
273         BeanEntry entry = new BeanEntry(bean,primaryKey, ancillaryState, timeOUT);
274
275         beanINDEX.put(primaryKey, entry);
276
277
278         return entry.bean;
279     }
280
281     /**
282      * Gets a previously instantiated instance of the bean class with the
283      * specified primaryKey
284      *
285      * @param primaryKey the unique key that can identify the instance to return
286      * @return an instance of the bean class
287      * @exception OpenEJBException
288      * if there is a problem retreiving the instance from the pool
289      * @exception InvalidateReferenceException
290      * if the instance has timed out
291      */

292     public SessionBean JavaDoc obtainInstance(Object JavaDoc primaryKey, ThreadContext callContext)throws OpenEJBException{
293         if ( primaryKey == null ) {
294             throw new org.openejb.SystemException( new NullPointerException JavaDoc("Cannot obtain an instance of the stateful session bean with a null session id"));
295         }
296
297         BeanEntry entry = (BeanEntry)beanINDEX.get(primaryKey);
298         if ( entry == null ) {
299             // if the bean is not in the beanINDEX then it must either be passivated or it doesn't exist.
300
entry = activate(primaryKey);
301             if ( entry != null ) {
302                 // the bean instance was passivated
303
if ( entry.isTimedOut() ) {
304                     /* Since the bean instance hasn't had its ejbActivate() method called yet,
305                        it is still considered to be passivated at this point. Instances that timeout
306                        while passivated must be evicted WITHOUT having their ejbRemove()
307                        method invoked. Section 6.6 of EJB 1.1 specification.
308                     */

309                     throw new org.openejb.InvalidateReferenceException(new java.rmi.NoSuchObjectException JavaDoc("Timed Out"));
310                 }
311                 // invoke ejbActivate( ) on bean
312
byte currentOp = callContext.getCurrentOperation();
313                 callContext.setCurrentOperation(Operations.OP_ACTIVATE);
314
315                 try {
316                     entry.bean.ejbActivate( );
317                 } catch ( Throwable JavaDoc callbackException ) {
318                     /*
319                     In the event of an exception, OpenEJB is required to log the exception, evict the instance,
320                     and mark the transaction for rollback. If there is a transaction to rollback, then the a
321                     javax.transaction.TransactionRolledbackException must be throw to the client. Otherwise a
322                     java.rmi.RemoteException is thrown to the client.
323                     See EJB 1.1 specification, section 12.3.2
324                     */

325                     handleCallbackException(callbackException, entry.bean, callContext, "ejbActivate");
326                 } finally {
327                     callContext.setCurrentOperation(currentOp);
328                 }
329
330                 beanINDEX.put(primaryKey, entry);
331                 return entry.bean;
332             } else {
333                 throw new org.openejb.InvalidateReferenceException(new java.rmi.NoSuchObjectException JavaDoc("Not Found"));
334             }
335         } else {// bean has been created and is pooled
336
if ( entry.transaction != null ) { // the bean is pooled in the "tx method ready" pool.
337
// session beans can only be accessed by one transaction at a time.
338
// session beans involved in a transaction can not time out.
339
try {
340                     if ( entry.transaction.getStatus() == Status.STATUS_ACTIVE ) {
341                         // Unfortunately, we can't enforce this right here, because the
342
// calling sequence in the stateful container calls beforeInvoke AFTER
343
// obtainInstance(), so that the transaction hasn't been resumed yet.
344
// the transaction assocaite with the thread must be the same as the trasnaction associated with the bean entry
345
// if(entry.transaction.equals(OpenEJB.getTransactionManager().getTransaction()))
346
return entry.bean;
347 // else
348
// throw new ApplicationException(new javax.transaction.InvalidTransactionException());
349
} else {
350                         // the tx assoc with the entry must have commited or rolledback since the last request.
351
// this means that the bean is not assicated with a live tx can can service the new thread.
352
entry.transaction = null;
353                         return entry.bean;
354                     }
355                 } catch ( javax.transaction.SystemException JavaDoc se ) {
356                     throw new org.openejb.SystemException(se);
357                 } catch ( IllegalStateException JavaDoc ise ) {
358                     throw new org.openejb.SystemException(ise);
359                 } catch ( java.lang.SecurityException JavaDoc lse ) {
360                     throw new org.openejb.SystemException(lse);
361                 }
362             } else {// bean is pooled in the "method ready" pool.
363
// locate bean and return it
364
BeanEntry queEntry = lruQUE.remove(entry);// remove from Que so its not passivated while in use
365
if ( queEntry != null ) {
366                     if ( entry.isTimedOut() ) {
367                         // dereference bean instance for GC
368
entry = (BeanEntry)beanINDEX.remove(entry.primaryKey );// remove frm index
369
handleTimeout(entry, callContext);
370                         throw new org.openejb.InvalidateReferenceException(new java.rmi.NoSuchObjectException JavaDoc("Stateful SessionBean has timed-out"));
371                     }
372                     return entry.bean;
373                 } else {
374                     byte currentOperation = callContext.getCurrentOperation();
375                     if ( currentOperation == Operations.OP_AFTER_COMPLETION || currentOperation == Operations.OP_BEFORE_COMPLETION ) {
376                         return entry.bean;
377                     } else {
378                         // if the entry was not in the que and its synchronization methods are not being exeuted, then its in use and this is a concurrent call. Not allowed.
379
throw new ApplicationException(new RemoteException JavaDoc("Concurrent calls not allowed"));
380                     }
381                 }
382             }
383         }
384     }
385
386     protected void handleTimeout(BeanEntry entry, ThreadContext thrdCntx) {
387
388         // current operation to ejbRemove
389
byte currentOp = thrdCntx.getCurrentOperation();
390         thrdCntx.setCurrentOperation(Operations.OP_REMOVE);
391
392         // instances that timeout while in the method ready pool must have their ejbRemove()
393
// method invoked before being evicted. Section 6.6 of EJB 1.1 specification.
394
try {
395             entry.bean.ejbRemove();
396         } catch ( Throwable JavaDoc callbackException ) {
397             /*
398               Exceptions are processed "quietly"; they are not reported to the client since
399               the timeout that caused the ejbRemove() operation did not, "technically", take
400               place in the context of a client call. Logically, it may have timeout sometime
401               before the client call.
402             */

403             String JavaDoc logMessage = "An unexpected exception occured while invoking the ejbRemove method on the timed-out Stateful SessionBean instance; "+callbackException.getClass().getName()+" "+callbackException.getMessage();
404
405             /* [1] Log the exception or error */
406             logger.error( logMessage );
407
408         } finally {
409             logger.info("Removing the timed-out stateful session bean instance "+entry.primaryKey );
410             thrdCntx.setCurrentOperation(currentOp);
411         }
412     }
413     /**
414      * Hands an instance of the bean class over to this instance manager to be
415      * managed until the instace is needed again.
416      *
417      * @param primaryKey the unique key that can identify the instance being managed
418      * @param bean an instance of the bean class
419      * @exception OpenEJBException
420      * if there is a problem adding the instance to the pool
421      */

422     public void poolInstance(Object JavaDoc primaryKey, EnterpriseBean JavaDoc bean)
423     throws OpenEJBException{
424         if ( primaryKey == null || bean == null )
425             throw new SystemException("Invalid arguments");
426
427         BeanEntry entry = (BeanEntry)beanINDEX.get(primaryKey);
428         if ( entry == null ) {
429             entry = activate(primaryKey);
430             if ( entry == null ) {
431                 throw new SystemException("Invalid primaryKey:"+primaryKey);
432             }
433         } else if ( entry.bean != bean )
434             throw new SystemException("Invalid ID for bean");
435
436
437         if ( entry.transaction!=null && entry.transaction == entry.ancillaryState ) {
438             // only Bean Managed Transaction beans will have their ancillary ...
439
// ... state and transaction variable equal to the same object
440
return;// don't put in LRU (method ready) pool.
441
} else {
442             try {
443                 entry.transaction = OpenEJB.getTransactionManager().getTransaction();
444             } catch ( javax.transaction.SystemException JavaDoc se ) {
445                 throw new org.openejb.SystemException("TransactionManager failure");
446             }
447
448             if ( entry.transaction == null ) {// only put in LRU if no current transaction
449
lruQUE.add(entry);// add it to end of Que; the most reciently used bean
450
}
451         }
452     }
453
454     /**
455      * Permanently removes the bean instance with the specified primaryKey from
456      * this instance manager's pool. The primaryKey will be of type SessionKey
457      *
458      * @param primaryKey the unique key that can identify the instance to be freed
459      * @return EnterpriseBean
460      * @exception SystemException if there is a problem removing the bean instance from the pool
461      * @exception org.openejb.SystemException
462      */

463     public EnterpriseBean JavaDoc freeInstance(Object JavaDoc primaryKey)
464     throws org.openejb.SystemException{
465         BeanEntry entry = null;
466         entry = (BeanEntry)beanINDEX.remove(primaryKey);// remove frm index
467
if ( entry == null ) {
468             entry = activate(primaryKey);
469         } else {
470             lruQUE.remove(entry); // remove from que
471
}
472
473         if ( entry == null )
474             return null;
475
476         // bean instanance and entry should be dereferenced and ready for garbage collection
477
return entry.bean;
478     }
479
480     /**
481      * PASSIVATION
482      *
483      * @exception SystemException
484      */

485     protected void passivate( ) throws SystemException {
486         final ThreadContext thrdCntx = ThreadContext.getThreadContext();
487         Hashtable JavaDoc stateTable = new Hashtable JavaDoc(BULK_PASSIVATION_SIZE);
488
489         BeanEntry currentEntry;
490         final byte currentOp = thrdCntx.getCurrentOperation();
491         try {
492             for ( int i=0; i<BULK_PASSIVATION_SIZE; ++i ) {
493                 currentEntry=lruQUE.first();
494                 if ( currentEntry==null )
495                     break;
496                 beanINDEX.remove(currentEntry.primaryKey);
497                 if ( currentEntry.isTimedOut() ) {
498                     handleTimeout(currentEntry, thrdCntx);
499                 } else {
500                     thrdCntx.setCurrentOperation(Operations.OP_PASSIVATE);
501                     try {
502                         // invoke ejbPassivate on bean instance
503
currentEntry.bean.ejbPassivate();
504                     } catch ( Throwable JavaDoc e ) {
505                         //FIXME: Register exception so it can thrown when client attempt to obtin this entry
506
//WHY? A NoSuchObjectException will be thrown.
507
String JavaDoc logMessage = "An unexpected exception occured while invoking the ejbPassivate method on the Stateful SessionBean instance; "+e.getClass().getName()+" "+e.getMessage();
508
509                         /* [1] Log the exception or error */
510                         logger.error( logMessage );
511                     }
512                     stateTable.put(currentEntry.primaryKey, currentEntry);
513                 }
514             }
515         } finally {
516             thrdCntx.setCurrentOperation(currentOp);
517         }
518
519         /*
520            the IntraVmCopyMonitor.prePssivationOperation() demarcates
521            the begining of passivation; used by EjbHomeProxyHandler,
522            EjbObjectProxyHandler, IntraVmMetaData, and IntraVmHandle
523            to deterime how serialization for these artifacts.
524         */

525         try {
526             IntraVmCopyMonitor.prePassivationOperation();
527             // pass the beans to the PassivationStrategy to write to disk.
528
passivator.passivate(stateTable);
529         } finally {
530             // demarcate the end of passivation.
531
IntraVmCopyMonitor.postPassivationOperation();
532         }
533     }
534     protected BeanEntry activate(Object JavaDoc primaryKey) throws SystemException {
535         return(BeanEntry)passivator.activate(primaryKey);
536     }
537
538     /**
539      *
540      * @param entry
541      * @param t
542      * @return InvalidateReferenceException
543      * @exception org.openejb.SystemException
544      */

545     protected org.openejb.InvalidateReferenceException destroy(BeanEntry entry, Exception JavaDoc t)
546     throws org.openejb.SystemException{
547
548         beanINDEX.remove(entry.primaryKey);// remove frm index
549
lruQUE.remove(entry);// remove from que
550
if ( entry.transaction != null ) {
551             try {
552                 entry.transaction.setRollbackOnly();
553             } catch ( javax.transaction.SystemException JavaDoc se ) {
554                 throw new org.openejb.SystemException(se);
555             } catch ( IllegalStateException JavaDoc ise ) {
556                 throw new org.openejb.SystemException("Attempt to rollback a non-tx context",ise);
557             } catch ( java.lang.SecurityException JavaDoc lse ) {
558                 throw new org.openejb.SystemException("Container not authorized to rollback tx",lse);
559             }
560             return new org.openejb.InvalidateReferenceException(new javax.transaction.TransactionRolledbackException JavaDoc(t.getMessage()));
561         } else if ( t instanceof RemoteException JavaDoc )
562             return new org.openejb.InvalidateReferenceException(t);
563         else {
564             EJBException JavaDoc ejbE = (EJBException JavaDoc)t;
565             return new org.openejb.InvalidateReferenceException(new RemoteException JavaDoc(ejbE.getMessage(), ejbE.getCausedByException()));
566         }
567
568
569         //FIXME: Spec 12.3.6 release all resources
570

571     }
572     /**
573      * Used by get/setAncillaryState( ) methods
574      *
575      * @param primaryKey
576      * @return BeanEntry
577      * @exception OpenEJBException
578      */

579     protected BeanEntry getBeanEntry(Object JavaDoc primaryKey)
580     throws OpenEJBException{
581         if ( primaryKey == null ) {
582             throw new SystemException(new NullPointerException JavaDoc("The primary key is null. Cannot get the bean entry"));
583         }
584         BeanEntry entry = (BeanEntry)beanINDEX.get(primaryKey);
585         if ( entry == null ) {
586             EnterpriseBean JavaDoc bean = this.obtainInstance(primaryKey, ThreadContext.getThreadContext());
587             this.poolInstance(primaryKey,bean);
588             entry = (BeanEntry)beanINDEX.get(primaryKey);
589         }
590         return entry;
591     }
592
593
594     /**
595      * INNER CLASSS
596      */

597     class BeanEntryQue {
598         private final java.util.LinkedList JavaDoc list;
599         private final int capacity;
600
601         protected BeanEntryQue(int preferedCapacity) {
602             capacity = preferedCapacity;
603             list = new java.util.LinkedList JavaDoc();
604         }
605
606         protected synchronized BeanEntry first( ) {
607             return(BeanEntry)list.removeFirst();
608         }
609
610         protected synchronized void add(BeanEntry entry) throws org.openejb.SystemException {
611             if ( list.size() >= capacity ) {// is the LRU QUE full?
612
passivate();
613             }
614             entry.resetTimeOut();
615             // add it to end of Que; the most reciently used bean
616
list.addLast(entry);
617             entry.inQue = true;
618         }
619         protected synchronized BeanEntry remove(BeanEntry entry) {
620             if ( !entry.inQue )
621                 return null;
622             if ( list.remove(entry)==true ) {
623                 entry.inQue = false;
624                 return entry;
625             } else {
626                 // e.g. cleanup from freeInstance()
627
return null;
628             }
629         }
630     }
631
632     public Logger logger = Logger.getInstance( "OpenEJB", "org.openejb.util.resources" );
633
634
635     protected void handleCallbackException(Throwable JavaDoc e, EnterpriseBean JavaDoc instance, ThreadContext callContext, String JavaDoc callBack) throws ApplicationException, org.openejb.SystemException{
636
637         // EJB 2.0: 18.3.3 Exceptions from container-invoked callbacks
638
String JavaDoc remoteMessage = "An unexpected exception occured while invoking the "+callBack+" method on the Stateful SessionBean instance";
639         String JavaDoc logMessage = remoteMessage +"; "+e.getClass().getName()+" "+e.getMessage();
640
641         /* [1] Log the exception or error */
642         logger.error( logMessage );
643
644         /* [2] If the instance is in a transaction, mark the transaction for rollback. */
645         Transaction JavaDoc tx = null;
646         try {
647             tx = getTxMngr().getTransaction();
648         } catch ( Throwable JavaDoc t ) {
649             logger.error("Could not retreive the current transaction from the transaction manager while handling a callback exception from the "+callBack+" method of bean "+callContext.getPrimaryKey());
650         }
651         if ( tx != null ) markTxRollbackOnly( tx );
652
653
654         /* [3] Discard the instance */
655         freeInstance( callContext.getPrimaryKey() );
656
657         /* [4] throw the java.rmi.RemoteException to the client */
658         if ( tx == null ) {
659             throw new InvalidateReferenceException( new RemoteException JavaDoc( remoteMessage, e ) );
660         } else {
661             throw new InvalidateReferenceException( new javax.transaction.TransactionRolledbackException JavaDoc( logMessage ) );
662         }
663
664     }
665
666
667     protected void markTxRollbackOnly( Transaction JavaDoc tx ) throws SystemException{
668         try {
669             if ( tx != null ) tx.setRollbackOnly();
670         } catch ( javax.transaction.SystemException JavaDoc se ) {
671             throw new org.openejb.SystemException(se);
672         }
673     }
674
675     protected TransactionManager JavaDoc getTxMngr( ) {
676         return OpenEJB.getTransactionManager();
677     }
678
679 }
680
681
Popular Tags