KickJava   Java API By Example, From Geeks To Geeks.

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


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

25
26 package org.objectweb.jonas_ejb.container;
27
28 import java.io.Serializable JavaDoc;
29 import java.util.ArrayList JavaDoc;
30 import java.util.Collection JavaDoc;
31 import java.util.Collections JavaDoc;
32 import java.util.Date JavaDoc;
33 import java.util.HashMap JavaDoc;
34 import java.util.Iterator JavaDoc;
35 import java.util.LinkedList JavaDoc;
36 import java.util.List JavaDoc;
37 import java.util.ListIterator JavaDoc;
38
39 import javax.ejb.EJBException JavaDoc;
40 import javax.ejb.EntityBean JavaDoc;
41 import javax.ejb.FinderException JavaDoc;
42 import javax.ejb.Timer JavaDoc;
43 import javax.ejb.TimerService JavaDoc;
44 import javax.naming.Context JavaDoc;
45 import javax.naming.NamingException JavaDoc;
46 import javax.transaction.RollbackException JavaDoc;
47 import javax.transaction.SystemException JavaDoc;
48 import javax.transaction.Transaction JavaDoc;
49
50 import org.objectweb.jonas_ejb.deployment.api.EntityDesc;
51 import org.objectweb.jonas_ejb.deployment.api.EntityJdbcCmp1Desc;
52 import org.objectweb.jonas_ejb.deployment.api.EntityJdbcCmp2Desc;
53 import org.objectweb.jorm.naming.api.PExceptionNaming;
54 import org.objectweb.jorm.naming.api.PName;
55
56 import org.objectweb.util.monolog.api.BasicLevel;
57
58 /**
59  * This class is a factory for an Entity Bean. It is responsible for
60  * - managing Home and LocalHome.
61  * - managing a pool of instances/contexts
62  * - keeping the list of PKs and the associated JEntitySwitch's
63  * - keeping the JNDI context for this component (java:comp/env)
64  * @author Philippe Coq, Philippe Durieux
65  */

66 public class JEntityFactory extends JFactory implements TimerService JavaDoc {
67
68     /**
69      * optional home
70      */

71     protected JEntityHome home = null;
72
73     /**
74      * optional local home
75      */

76     protected JEntityLocalHome localhome = null;
77
78     /**
79      * reentrant if instance can be used concurrently
80      */

81     protected boolean reentrant;
82
83     /**
84      * shared if the EJB container is not the only one to modify
85      * the bean state on the database, or if a cluster of container
86      * access the bean concurrently.
87      */

88     protected boolean shared = false;
89
90     /**
91      * lock policy
92      */

93     protected int lockPolicy;
94
95     /**
96      * enable the prefetch for CMP2 bean
97      */

98     protected boolean prefetch = false;
99
100     /**
101      * instance pool management (list of available JEntityContext objects)
102      */

103     protected List JavaDoc bctxlist = new ArrayList JavaDoc();
104
105     protected int instanceCount = 0;
106
107
108     protected int inactivityTimeout; // sec.
109

110     /**
111      * List of JEntitySwitch objects
112      * At each PK is associated a JEntitySwitch object
113      */

114     protected HashMap JavaDoc pklist = new HashMap JavaDoc();
115
116     /**
117      * List of Transaction Listeners.
118      * At each Transaction is associated a TxListener object
119      */

120     protected HashMap JavaDoc txlist = new HashMap JavaDoc();
121
122     /**
123      * dirty list of JEntitySwitch
124      */

125     private LinkedList JavaDoc dirtyList = new LinkedList JavaDoc();
126
127     private boolean mustSyncDirtyEntities = false;
128
129     // Datasource in case of CMP
130
protected Object JavaDoc datasource = null;
131
132     /**
133      * This field is used to generate an uid for unique automatic pk
134      */

135     private static int ucount = 1;
136
137     /**
138      * datasource name
139      */

140     String JavaDoc dsname = null;
141
142     /**
143      * constructor must be without parameters (required by Jorm)
144      */

145     public JEntityFactory() {
146         if (TraceEjb.isDebugIc()) {
147             TraceEjb.interp.log(BasicLevel.DEBUG, "");
148         }
149     }
150
151     /**
152      * Init this object
153      * @param dd the deployment descriptor
154      * @param cont the Container
155      */

156     public void init(EntityDesc dd, JContainer cont) {
157         super.init(dd, cont);
158         reentrant = dd.isReentrant();
159         shared = dd.isShared();
160         lockPolicy = dd.getLockPolicy();
161         prefetch = dd.isPrefetch();
162         if (lockPolicy == EntityDesc.LOCK_CONTAINER_READ_UNCOMMITTED && prefetch) {
163             throw new EJBException JavaDoc("Cannot set READ_UNCOMMITTED and prefetch for a bean");
164         }
165         inactivityTimeout = dd.getInactivityTimeout();
166
167         // Finds the DataSource associated to the bean
168
// Useful for Entity with Container Managed Persistence.
169
if (dd instanceof EntityJdbcCmp1Desc) {
170             dsname = ((EntityJdbcCmp1Desc) dd).getDatasourceJndiName();
171             if (dsname != null) {
172                 try {
173                     datasource = getInitialContext().lookup(dsname);
174                 } catch (NamingException JavaDoc e) {
175                     String JavaDoc err = dsname + " is not known by the EJB server.";
176                     TraceEjb.logger.log(BasicLevel.ERROR, err, e);
177                     throw new EJBException JavaDoc(err, e);
178                 }
179             }
180         }
181
182         if (dd instanceof EntityJdbcCmp2Desc) {
183             dsname = ((EntityJdbcCmp2Desc) dd).getDatasourceJndiName();
184             if (dsname != null) {
185                 try {
186                     datasource = getInitialContext().lookup(dsname);
187                 } catch (NamingException JavaDoc e) {
188                     String JavaDoc err = dsname + " is not known by the EJB server.";
189                     TraceEjb.logger.log(BasicLevel.ERROR, err);
190                     throw new EJBException JavaDoc(err, e);
191                 }
192             }
193         }
194
195         // Create the Home if defined in DD
196
Class JavaDoc homeclass = null;
197         String JavaDoc clname = dd.getFullWrpHomeName();
198         if (clname != null) {
199             try {
200                 homeclass = cont.getClassLoader().loadClass(clname);
201             } catch (ClassNotFoundException JavaDoc e) {
202                 throw new EJBException JavaDoc(ejbname + "Cannot load " + clname, e);
203             }
204             if (TraceEjb.isDebugIc()) {
205                 TraceEjb.interp.log(BasicLevel.DEBUG, ejbname + ": " + clname + " loaded");
206             }
207             try {
208                 // new JEntityHome(dd, this)
209
int nbp = 2;
210                 Class JavaDoc[] ptype = new Class JavaDoc[nbp];
211                 Object JavaDoc[] pobj = new Object JavaDoc[nbp];
212                 ptype[0] = org.objectweb.jonas_ejb.deployment.api.EntityDesc.class;
213                 pobj[0] = (Object JavaDoc) dd;
214                 ptype[1] = org.objectweb.jonas_ejb.container.JEntityFactory.class;
215                 pobj[1] = (Object JavaDoc) this;
216                 home = (JEntityHome) homeclass.getConstructor(ptype).newInstance(pobj);
217             } catch (Exception JavaDoc e) {
218                throw new EJBException JavaDoc(ejbname + " Cannot create home ", e);
219             }
220
221             // register it in JNDI
222
try {
223                 home.register();
224             } catch (Exception JavaDoc e) {
225                 throw new EJBException JavaDoc(ejbname + " Cannot register home ", e);
226             }
227         }
228
229         // Create the LocalHome if defined in DD
230
clname = dd.getFullWrpLocalHomeName();
231         if (clname != null) {
232             try {
233                 homeclass = cont.getClassLoader().loadClass(clname);
234             } catch (ClassNotFoundException JavaDoc e) {
235                 TraceEjb.logger.log(BasicLevel.ERROR, ejbname + " cannot load " + clname);
236                 throw new EJBException JavaDoc("Cannot load " + clname, e);
237             }
238             if (TraceEjb.isDebugIc()) {
239                 TraceEjb.interp.log(BasicLevel.DEBUG, ejbname + ": " + clname + " loaded");
240             }
241             try {
242                 // new JEntityLocalHome(dd, this)
243
int nbp = 2;
244                 Class JavaDoc[] ptype = new Class JavaDoc[nbp];
245                 Object JavaDoc[] pobj = new Object JavaDoc[nbp];
246                 ptype[0] = org.objectweb.jonas_ejb.deployment.api.EntityDesc.class;
247                 pobj[0] = (Object JavaDoc) dd;
248                 ptype[1] = org.objectweb.jonas_ejb.container.JEntityFactory.class;
249                 pobj[1] = (Object JavaDoc) this;
250                 localhome = (JEntityLocalHome) homeclass.getConstructor(ptype).newInstance(pobj);
251             } catch (Exception JavaDoc e) {
252                 throw new EJBException JavaDoc(ejbname + " Cannot create localhome ", e);
253             }
254             // register it in JNDI
255
try {
256                 localhome.register();
257             } catch (Exception JavaDoc e) {
258                 throw new EJBException JavaDoc(ejbname + " Cannot register localhome ", e);
259             }
260         }
261     }
262
263     /**
264      * Init the pool of instances
265      */

266     public void initInstancePool() {
267         // pre-allocate a set of JEntityContext (bean instances)
268
Context JavaDoc bnctx = setComponentContext(); // for createNewInstance
269
for (int i = 0; i < minPoolSize; i++) {
270             JEntityContext ctx = null;
271             try {
272                 ctx = createNewInstance(null);
273                 synchronized(bctxlist) {
274                     bctxlist.add(ctx);
275                 }
276             } catch (Exception JavaDoc e) {
277                 TraceEjb.logger.log(BasicLevel.ERROR, ejbname + " cannot create new instance", e);
278                 throw new EJBException JavaDoc(ejbname + " Cannot init pool of instances ", e);
279             }
280         }
281         resetComponentContext(bnctx);
282     }
283
284     /**
285      * get EJB by its PK
286      * Creates if not exist yet.
287      * @param pk The Primary Key Object
288      * @return The JEntitySwitch matching the PK.
289      */

290     public synchronized JEntitySwitch getEJB(Object JavaDoc pk) {
291
292         if (TraceEjb.isDebugIc()) {
293             TraceEjb.interp.log(BasicLevel.DEBUG, ejbname);
294         }
295
296         if (pk == null) {
297             TraceEjb.logger.log(BasicLevel.ERROR, "pk null ???");
298             return null;
299         }
300         JEntitySwitch bs = (JEntitySwitch) pklist.get(pk);
301         if (bs == null) {
302             bs = getJEntitySwitch();
303             bs.init(this, pk);
304             if (TraceEjb.isDebugIc()) {
305                 TraceEjb.interp.log(BasicLevel.DEBUG, "Adding PK to pklist:" + pk);
306             }
307             pklist.put(pk, bs);
308         }
309         return bs;
310     }
311
312     /**
313      * get EJB by its PK. If not exist yet, map the EntitySwitch to the PK.
314      * @param pk The Primary Key Object
315      * @param bs the Entityswitch
316      * @return The JEntitySwitch matching the PK, or null if none exist.
317      */

318     public synchronized JEntitySwitch existEJB(Object JavaDoc pk, JEntitySwitch bs) {
319         if (pk == null) {
320             TraceEjb.logger.log(BasicLevel.ERROR, "pk null ???");
321             return null;
322         }
323         JEntitySwitch ret = (JEntitySwitch) pklist.get(pk);
324         if (TraceEjb.isDebugIc()) {
325             TraceEjb.interp.log(BasicLevel.DEBUG, "Looking for PK in pklist:" + pk);
326             TraceEjb.interp.log(BasicLevel.DEBUG, ret == null ? "no" : "yes");
327         }
328         if (ret == null && bs != null) {
329             // Bind new EntitySwitch while we got the lock.
330
bs.init(this, pk);
331             pklist.put(pk, bs);
332         }
333         return ret;
334     }
335
336     /**
337      * rebind a PK with a JEntitySwitch (called by create methods)
338      * @param tx current Transaction
339      * @param bctx The EntityContext
340      * @param pk The Primary Key Object
341      * @return true if bs has been added to the PK list.
342      */

343     public boolean rebindEJB(Transaction JavaDoc tx, JEntityContext bctx, Object JavaDoc pk) {
344         if (TraceEjb.isDebugIc()) {
345             TraceEjb.interp.log(BasicLevel.DEBUG, ejbname);
346         }
347
348         if (pk == null) {
349             TraceEjb.logger.log(BasicLevel.ERROR, "pk null ???");
350             return false;
351         }
352         JEntitySwitch bs = bctx.getEntitySwitch();
353         JEntitySwitch old = null;
354         synchronized (this) {
355             old = (JEntitySwitch) pklist.get(pk);
356         }
357         boolean ret = true;
358         if (old != null) {
359             // different cases:
360
// - a create after a remove, in the same tx (or no tx)
361
// - in CMP2: a "DuplicateKey".
362
// - Bean removed by another server (bean shared)
363

364             // Release completely the old EntitySwitch before binding the new one.
365
// must be done outside the lock, to avoid a deadlock.
366
ret = old.terminate(tx);
367         }
368         synchronized (this) {
369             bs.init(this, pk);
370             if (TraceEjb.isDebugIc()) {
371                 TraceEjb.interp.log(BasicLevel.DEBUG, "Adding PK to pklist:" + pk);
372             }
373             pklist.put(pk, bs);
374         }
375         return ret;
376     }
377
378     /**
379      * Bind a PK with a JEntitySwitch
380      * @param pk The Primary Key Object
381      * @param bs The JEntitySwitch
382      */

383     public synchronized void bindEJB(Object JavaDoc pk, JEntitySwitch bs) {
384         if (TraceEjb.isDebugIc()) {
385             TraceEjb.interp.log(BasicLevel.DEBUG, ejbname);
386         }
387         if (pk == null) {
388             TraceEjb.logger.log(BasicLevel.ERROR, "pk null ???");
389             return;
390         }
391         bs.init(this, pk);
392         pklist.put(pk, bs);
393     }
394
395     /**
396      * This method allocates a new JEntitySwitch. But no association has been
397      * done between the primary key and the new JEntitySwitch. Therefore the
398      * initialisation is not done.
399      * @return The JEntitySwitch.
400      */

401     public JEntitySwitch getJEntitySwitch() {
402         switch (lockPolicy) {
403             case EntityDesc.LOCK_CONTAINER_READ_UNCOMMITTED:
404                 return new JEntitySwitchCRU();
405             case EntityDesc.LOCK_CONTAINER_READ_COMMITTED:
406                 return new JEntitySwitchCRC();
407             case EntityDesc.LOCK_DATABASE:
408                 return new JEntitySwitchDB();
409             case EntityDesc.LOCK_READ_ONLY:
410                 return new JEntitySwitchRO();
411             default:
412                 return new JEntitySwitchCS();
413         }
414     }
415
416     /**
417      * remove an EJB by its PK
418      * @param pk The Primary Key Object
419      */

420     public synchronized void removeEJB(Object JavaDoc pk) {
421         if (TraceEjb.isDebugIc()) {
422             TraceEjb.interp.log(BasicLevel.DEBUG, ejbname);
423         }
424         if (pk == null) {
425             TraceEjb.logger.log(BasicLevel.ERROR, "pk null ???");
426             return;
427         }
428         pklist.remove(pk);
429     }
430
431     /**
432      * Register an EntitySwitch in the dirty list.
433      * should be called each time a new instance is modified outside transaction
434      * @param ejb The Entity Switch to be registered
435      */

436     public synchronized void registerEJB(JEntitySwitch ejb) {
437         if (TraceEjb.isDebugSwapper()) {
438             TraceEjb.swapper.log(BasicLevel.DEBUG, ejbname);
439         }
440         if (dirtyList.contains(ejb)) {
441             TraceEjb.swapper.log(BasicLevel.ERROR, ejbname + " Elt already in the dirty list");
442             return;
443         }
444         dirtyList.addLast(ejb);
445         mustSyncDirtyEntities = true;
446     }
447
448     /**
449      * Ask swapper to synchronize all dirty EntitySwitch
450      */

451     public void synchronizeEntities() {
452         if (TraceEjb.isDebugSwapper()) {
453             TraceEjb.swapper.log(BasicLevel.DEBUG, ejbname);
454         }
455         cont.registerBFS(this);
456     }
457
458     /**
459      * @return true if dirty list is not empty
460      */

461     public boolean dirtyInstances() {
462         return mustSyncDirtyEntities;
463     }
464
465     /**
466      * @return inactivity timeout in sec.
467      */

468     public int getInactivityTimeout() {
469         return inactivityTimeout;
470     }
471
472     // ---------------------------------------------------------------
473
// BeanFactory implementation
474
// ---------------------------------------------------------------
475

476     /**
477      * @return the Instance pool size for this Ejb
478      */

479     public int getPoolSize() {
480         return bctxlist.size();
481     }
482
483     /**
484      * stop this EJB.
485      * Mainly unregister it in JNDI.
486      */

487     public void stop() {
488         if (TraceEjb.isDebugIc()) {
489             TraceEjb.interp.log(BasicLevel.DEBUG, ejbname);
490         }
491         try {
492             if (home != null) {
493                 home.unregister();
494             }
495             if (localhome != null) {
496                 localhome.unregister();
497             }
498         } catch (NamingException JavaDoc e) {
499         }
500     }
501
502     /**
503      * Synchronize all dirty instances
504      */

505     public void sync() {
506
507         if (!mustSyncDirtyEntities) {
508             if (TraceEjb.isDebugSwapper()) {
509                 TraceEjb.swapper.log(BasicLevel.DEBUG, ejbname + " cacheSize = " + getCacheSize());
510             }
511             // nothing to do
512
return;
513         }
514
515         if (TraceEjb.isDebugSwapper()) {
516             TraceEjb.swapper.log(BasicLevel.DEBUG, ejbname + " dirtyList size = " + dirtyList.size());
517         }
518
519         // Set the JNDI component context (for ejbStore)
520
Context JavaDoc bnctx = setComponentContext();
521
522         // try to passivate all instances and build a new list.
523
LinkedList JavaDoc wsdone = new LinkedList JavaDoc();
524         synchronized (this) {
525             for (ListIterator JavaDoc i = dirtyList.listIterator(0); i.hasNext();) {
526                 JEntitySwitch es = (JEntitySwitch) i.next();
527                 if (es.passivateIH(false)) {
528                     // passivation OK.
529
i.remove();
530                     wsdone.addLast(es);
531                 } else {
532                     if (TraceEjb.isDebugSwapper()) {
533                         TraceEjb.swapper.log(BasicLevel.DEBUG, ejbname + " swapper could not passivate an instance");
534                     }
535                 }
536             }
537         }
538
539         // for each instance passivated, notify it's OK to continue.
540
// must be done after all instances are passivated, in case of relations.
541
mustSyncDirtyEntities = false; // do this before endIH
542
for (ListIterator JavaDoc i = wsdone.listIterator(0); i.hasNext();) {
543             JEntitySwitch es = (JEntitySwitch) i.next();
544             es.endIH();
545         }
546
547         // Reset old value for component context
548
resetComponentContext(bnctx);
549     }
550
551     /**
552      * Reduce number of instances in memory
553      */

554     public void reduceCache() {
555         if (TraceEjb.isDebugSwapper()) {
556             TraceEjb.swapper.log(BasicLevel.DEBUG, ejbname + pklist.size());
557         }
558         //printAllPks();
559

560         // passivate all instances that are not busy
561
// count is the number of busy instances (not freed)
562
// other instances should be added to the pool (bctxlist)
563
int count = 0;
564
565         // Set classloader for getting the right component context
566
ClassLoader JavaDoc old = Thread.currentThread().getContextClassLoader();
567         Thread.currentThread().setContextClassLoader(myClassLoader());
568
569         // Set the JNDI component context (for ejbStore)
570
Context JavaDoc bnctx = setComponentContext();
571
572         Collection JavaDoc coll = null;
573         HashMap JavaDoc clone = null;
574         synchronized (this) {
575             clone = (HashMap JavaDoc) pklist.clone();
576         }
577         JEntitySwitch bs = null;
578         for (Iterator JavaDoc i = clone.values().iterator(); i.hasNext();) {
579             bs = (JEntitySwitch) i.next();
580             if (!bs.passivateIH(true)) {
581                 count++;
582             }
583         }
584         // Reset old value for component context
585
resetComponentContext(bnctx);
586         Thread.currentThread().setContextClassLoader(old);
587
588         // compute the new size we want for the pool
589
// (if more busy instances than min size, we want an empty pool)
590
int poolsz = minPoolSize - count;
591         if (poolsz < 0) {
592             poolsz = 0;
593         }
594
595         // reduce the pool to this new value
596
synchronized (bctxlist) {
597             if (TraceEjb.isDebugSwapper()) {
598                 TraceEjb.swapper.log(BasicLevel.DEBUG, ejbname + ": try to reduce " + bctxlist.size() + " to " + poolsz);
599             }
600             while (bctxlist.size() > poolsz) {
601                 ListIterator JavaDoc i = bctxlist.listIterator();
602                 if (i.hasNext()) {
603                     i.next();
604                     i.remove();
605                     instanceCount--;
606                 }
607             }
608         }
609         if (TraceEjb.isDebugSwapper()) {
610             TraceEjb.swapper.log(BasicLevel.DEBUG, ejbname + " cacheSize= " + getCacheSize());
611         }
612         printMemoryUsage();
613     }
614
615     /**
616      * @return the home if it exists
617      */

618     public JHome getHome() {
619         return home;
620     }
621
622     /**
623      * @return the local home if it exists
624      */

625     public JLocalHome getLocalHome() {
626         return localhome;
627     }
628
629     // ---------------------------------------------------------------
630
// Context Pool
631
// ---------------------------------------------------------------
632

633     /**
634      * Get a Context from the pool, or create a new one if no more
635      * available in the pool.
636      * This JContext must be initialized then by the caller.
637      * @return a JEntityContext, not initialized.
638      */

639     public JEntityContext getJContext(JEntitySwitch es) {
640         if (TraceEjb.isDebugIc()) {
641             TraceEjb.interp.log(BasicLevel.DEBUG, ejbname);
642         }
643         JEntityContext bctx = null;
644
645         // try to find a free context in the pool
646
synchronized (bctxlist) {
647             try {
648                 bctx = (JEntityContext) bctxlist.remove(0);
649                 // TODO init es ref in ctxt
650
} catch (IndexOutOfBoundsException JavaDoc ex) {
651                 // pool is empty
652
}
653         }
654
655         if (bctx == null) {
656             // create a new one if pool empty
657
try {
658                 bctx = createNewInstance(es);
659             } catch (Exception JavaDoc e) {
660                 throw new EJBException JavaDoc("Cannot create a new instance ", e);
661             }
662         }
663
664         // DEBUG
665
if (bctx.getEntitySwitch() != null) {
666             TraceEjb.context.log(BasicLevel.ERROR, ejbname + "Context already initialized!");
667         }
668
669         return bctx;
670     }
671
672     /**
673      * Release a Context
674      * @param ctx - The JContext to release.
675      */

676     public void releaseJContext(JContext ctx) {
677         JEntityContext bctx = (JEntityContext) ctx;
678         if (TraceEjb.isDebugContext()) {
679             TraceEjb.context.log(BasicLevel.DEBUG, ejbname);
680         }
681         bctx.razEntityContext();
682         synchronized(bctxlist) {
683             /* For Debug Only
684             if (bctxlist.contains(bctx)) {
685                 TraceEjb.context.log(BasicLevel.ERROR, ejbname + ": try to put twice this ctx " + bctx);
686                 Thread.dumpStack();
687                 return;
688             }
689             */

690             bctxlist.add(bctx);
691         }
692     }
693
694     // ---------------------------------------------------------------
695
// other public methods
696
// ---------------------------------------------------------------
697

698     /**
699      * Obtains the TimerService associated for this Bean
700      * @return a JTimerService instance.
701      */

702     public TimerService JavaDoc getTimerService() {
703         return this;
704     }
705
706     /**
707      * @return current cache size for Jmx
708      */

709     public int getCacheSize() {
710         return instanceCount;
711     }
712
713     /**
714      * @return true if reentrant
715      */

716     public boolean isReentrant() {
717         return reentrant;
718     }
719
720     /**
721      * @return true if shared
722      */

723     public boolean isShared() {
724         return shared;
725     }
726
727     /**
728      * @return lockPolicy
729      */

730     public int lockPolicy() {
731         return lockPolicy;
732     }
733
734     /**
735      * @return true if prefetch enable
736      */

737     public boolean isPrefetch() {
738         return prefetch;
739     }
740
741     /**
742      * @return the Datasource used for CMP
743      */

744     public Object JavaDoc getDataSource() {
745         if (datasource == null) {
746             TraceEjb.logger.log(BasicLevel.ERROR, ejbname + ": datasource not defined in JEntityFactory");
747         }
748         return datasource;
749     }
750
751     /**
752      * Check Transaction before calling a method on a bean. For Entity beans,
753      * the only possible case is "Container Managed Tx"
754      * @param rctx The Request Context
755      */

756     public void checkTransaction(RequestCtx rctx) {
757         checkTransactionContainer(rctx);
758     }
759
760     /**
761      * synchronize data modified in this transaction.
762      * this is necessary in case of finder method, because
763      * ejb-ql looks for on disk.
764      * @param tx the Transaction
765      */

766     public void syncForFind(Transaction JavaDoc tx) {
767         if (TraceEjb.isDebugIc()) {
768             TraceEjb.interp.log(BasicLevel.DEBUG, ejbname);
769         }
770         if (tx == null) {
771             if (lockPolicy == EntityDesc.LOCK_CONTAINER_SERIALIZED) {
772                 sync();
773             }
774         } else {
775             TxListener txl = (TxListener) txlist.get(tx);
776             if (txl != null) {
777                 txl.storeInstances();
778             }
779         }
780     }
781
782     /**
783      * Return True if this Tx is blocking an instance
784      */

785     public boolean isBlocking(Transaction JavaDoc tx) {
786         HashMap JavaDoc clone = null;
787         synchronized (this) {
788             clone = (HashMap JavaDoc) pklist.clone();
789         }
790         JEntitySwitch bs = null;
791         for (Iterator JavaDoc i = clone.values().iterator(); i.hasNext();) {
792             bs = (JEntitySwitch) i.next();
793             Transaction JavaDoc tb = bs.getBlockingTx();
794             if (tb != null && tb.equals(tx)) {
795                 return true;
796             }
797         }
798         return false;
799     }
800
801     /**
802      * Return True if this Tx is blocked waiting an instance
803      */

804     public boolean isBlocked(Transaction JavaDoc tx) {
805         HashMap JavaDoc clone = null;
806         synchronized (this) {
807             clone = (HashMap JavaDoc) pklist.clone();
808         }
809         JEntitySwitch bs = null;
810         for (Iterator JavaDoc i = clone.values().iterator(); i.hasNext();) {
811             bs = (JEntitySwitch) i.next();
812             Transaction JavaDoc tb = bs.getBlockedTx();
813             if (tb != null && tb.equals(tx)) {
814                 return true;
815             }
816         }
817         return false;
818     }
819
820     /**
821      * Remove a Transaction Listener from the list.
822      * @param tx the Transaction to remove
823      */

824     public void removeTxListener(Transaction JavaDoc tx) {
825         if (TraceEjb.isDebugIc()) {
826             TraceEjb.interp.log(BasicLevel.DEBUG, ejbname);
827         }
828         txlist.remove(tx);
829     }
830
831     /**
832      * Register a Context/Instance in the transaction.
833      * @param tx current Transaction
834      * @param ctx JEntityContext to be registered
835      * @return true if instance has been registered.
836      */

837     public boolean registerContext(Transaction JavaDoc tx, JEntityContext ec) throws IllegalStateException JavaDoc {
838         if (TraceEjb.isDebugIc()) {
839             TraceEjb.interp.log(BasicLevel.DEBUG, ejbname);
840         }
841
842         // Get the TXListener associated to this tx, or create it.
843
TxListener txl = (TxListener) txlist.get(tx);
844         if (txl == null) {
845             txl = new TxListener(this, tx);
846             // register it as Synchronization.
847
try {
848                 tx.registerSynchronization(txl);
849             } catch (RollbackException JavaDoc e) {
850                 if (TraceEjb. isVerbose()) {
851                     TraceEjb.logger.log(BasicLevel.WARN, ejbname + " transaction has been marked rollbackOnly", e);
852                 }
853             } catch (SystemException JavaDoc e) {
854                 TraceEjb.logger.log(BasicLevel.ERROR, ejbname + " cannot register synchro ", e);
855                 // forget txl.
856
throw new IllegalStateException JavaDoc("cannot register synchro");
857             }
858             txlist.put(tx, txl);
859         }
860
861         // Add the JEntityContext
862
txl.addInstance(ec);
863         return true;
864     }
865
866     /**
867      * Take a dump of current entity counters and return them
868      * @return EntityCounters
869      */

870     public synchronized EntityCounters getEntityCounters() {
871         EntityCounters ec = new EntityCounters();
872         Collection JavaDoc coll = pklist.values();
873         for (Iterator JavaDoc i = coll.iterator(); i.hasNext();) {
874             JEntitySwitch es = (JEntitySwitch) i.next();
875             switch (es.getState()) {
876                 case 0:
877                     ec.inTx++;
878                     break;
879                 case 1:
880                     ec.outTx++;
881                     break;
882                 case 2:
883                     ec.idle++;
884                     break;
885                 case 3:
886                     ec.passive++;
887                     break;
888                 case 4:
889                     ec.removed++;
890                     break;
891             }
892         }
893         return ec;
894     }
895
896     /**
897      * Calculate a new uid for automatic pk creation Used by JEntityCmpJdbc.vm
898      * @return int (unique pk)
899      */

900     public int calculateAutomaticPk() {
901         if (TraceEjb.isDebugIc()) {
902             TraceEjb.interp.log(BasicLevel.DEBUG, ejbname);
903         }
904         int uid;
905         synchronized (getClass()) {
906             uid = (int) (System.currentTimeMillis() % (java.lang.Integer.MAX_VALUE / 10));
907             uid = uid * 10 + ucount++;
908         }
909         return uid;
910     }
911
912     /**
913      * Dummy method that defines the FinderException in the throws clause
914      * to can catch this exception in any case in the JentityHome.vm
915      * @param dummy if true do nothing, else throw the FinderException
916      * @throws FinderException if dummy is false
917      */

918     public void dummyFinderException(boolean dummy) throws FinderException JavaDoc {
919         if (!dummy) {
920             throw new FinderException JavaDoc("dummy exception !!!");
921         }
922     }
923
924     /**
925      * print the list of PKs
926      * for DEBUG only
927      */

928     public void printAllPks() {
929         if (TraceEjb.isDebugSwapper()) {
930             HashMap JavaDoc clone = null;
931             synchronized (this) {
932                 clone = (HashMap JavaDoc) pklist.clone();
933             }
934             JEntitySwitch bs = null;
935             for (Iterator JavaDoc i = clone.values().iterator(); i.hasNext();) {
936                 bs = (JEntitySwitch) i.next();
937                 TraceEjb.swapper.log(BasicLevel.DEBUG, "PK=" + bs.getPrimaryKey());
938             }
939         }
940     }
941
942     /**
943      * print memory usage
944      * for DEBUG only
945      */

946     private void printMemoryUsage() {
947         if (TraceEjb.isDebugSwapper()) {
948             System.gc();
949             TraceEjb.swapper.log(BasicLevel.DEBUG,
950                                  " total = " + Runtime.getRuntime().totalMemory() / 1024 +
951                                  " free = " + Runtime.getRuntime().freeMemory() / 1024);
952         }
953     }
954
955     // ---------------------------------------------------------------
956
// private methods
957
// ---------------------------------------------------------------
958

959     /**
960      * Create a new instance of the bean and its EntityContext
961      * In case of CMP, the bean class is derived to manage entity persistence.
962      * @return JEntityContext
963      * @throws Exception cannot instantiate bean
964      */

965     protected JEntityContext createNewInstance(JEntitySwitch es) throws Exception JavaDoc {
966         if (TraceEjb.isDebugIc()) {
967             TraceEjb.interp.log(BasicLevel.DEBUG, ejbname);
968         }
969
970         // create the bean instance
971
EntityBean JavaDoc bean = null;
972         try {
973             bean = (EntityBean JavaDoc) beanclass.newInstance();
974         } catch (InstantiationException JavaDoc e) {
975             TraceEjb.logger.log(BasicLevel.ERROR, ejbname + " cannot instantiate bean");
976             throw e;
977         } catch (IllegalAccessException JavaDoc e) {
978             TraceEjb.logger.log(BasicLevel.ERROR, ejbname + " cannot instantiate bean");
979             throw e;
980         }
981
982         // create a new EntityContext and bind it to the instance
983
JEntityContext ec = createNewContext(bean);
984         bean.setEntityContext(ec);
985         ec.setState(1);
986
987         // If too many instances, ask swapper to clean memory.
988
synchronized (this) {
989             instanceCount++;
990         }
991         if (maxCacheSize != 0 && instanceCount > maxCacheSize) {
992             // Register this factory, if not already done.
993
if (TraceEjb.isDebugSwapper()) {
994                 TraceEjb.swapper.log(BasicLevel.DEBUG, ejbname + ": Too many instances :" + instanceCount + ", max="
995                         + maxCacheSize);
996             }
997             cont.registerBF(this);
998         }
999
1000        return ec;
1001    }
1002
1003    protected JEntityContext createNewContext(EntityBean JavaDoc bean) {
1004        return new JEntityContext(this, bean);
1005    }
1006
1007    /**
1008     * Encode PK. This does nothing, except in case of CMP2
1009     * @return String representation of the PK
1010     */

1011    public Serializable JavaDoc encodePK(Serializable JavaDoc pk) {
1012        return pk;
1013    }
1014
1015    /**
1016     * Decode PK. This does nothing, except in case of CMP2
1017     * @return PK matching the String
1018     */

1019    public Serializable JavaDoc decodePK(Serializable JavaDoc strpk) {
1020        return strpk;
1021    }
1022
1023    /*
1024     * (non-Javadoc)
1025     * @see javax.ejb.TimerService#createTimer(long, java.io.Serializable)
1026     */

1027    public Timer JavaDoc createTimer(long arg0, Serializable JavaDoc arg1) throws IllegalArgumentException JavaDoc, IllegalStateException JavaDoc, EJBException JavaDoc {
1028        throw new IllegalStateException JavaDoc("timer are associated with a PK");
1029    }
1030
1031    /* (non-Javadoc)
1032     * @see javax.ejb.TimerService#createTimer(long, long, java.io.Serializable)
1033     */

1034    public Timer JavaDoc createTimer(long arg0, long arg1, Serializable JavaDoc arg2) throws IllegalArgumentException JavaDoc, IllegalStateException JavaDoc, EJBException JavaDoc {
1035        throw new IllegalStateException JavaDoc("timer are associated with a PK");
1036    }
1037
1038    /* (non-Javadoc)
1039     * @see javax.ejb.TimerService#createTimer(java.util.Date, java.io.Serializable)
1040     */

1041    public Timer JavaDoc createTimer(Date JavaDoc arg0, Serializable JavaDoc arg1) throws IllegalArgumentException JavaDoc, IllegalStateException JavaDoc, EJBException JavaDoc {
1042        throw new IllegalStateException JavaDoc("timer are associated with a PK");
1043    }
1044
1045    /* (non-Javadoc)
1046     * @see javax.ejb.TimerService#createTimer(java.util.Date, long, java.io.Serializable)
1047     */

1048    public Timer JavaDoc createTimer(Date JavaDoc arg0, long arg1, Serializable JavaDoc arg2) throws IllegalArgumentException JavaDoc, IllegalStateException JavaDoc, EJBException JavaDoc {
1049        throw new IllegalStateException JavaDoc("timer are associated with a PK");
1050    }
1051
1052    /* (non-Javadoc)
1053     * @see javax.ejb.TimerService#getTimers()
1054     */

1055    public Collection JavaDoc getTimers() throws IllegalStateException JavaDoc, EJBException JavaDoc {
1056        throw new IllegalStateException JavaDoc("timer are associated with a PK");
1057    }
1058
1059}
1060
Popular Tags