KickJava   Java API By Example, From Geeks To Geeks.

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


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: JEntityContext.java,v 1.39 2005/05/16 14:52:47 durieuxp Exp $
23  * --------------------------------------------------------------------------
24  */

25
26 package org.objectweb.jonas_ejb.container;
27
28 import java.rmi.RemoteException JavaDoc;
29
30 import javax.ejb.EJBException JavaDoc;
31 import javax.ejb.EJBLocalObject JavaDoc;
32 import javax.ejb.EJBObject JavaDoc;
33 import javax.ejb.EntityBean JavaDoc;
34 import javax.ejb.EntityContext JavaDoc;
35 import javax.ejb.NoSuchObjectLocalException JavaDoc;
36 import javax.ejb.RemoveException JavaDoc;
37 import javax.ejb.TimerService JavaDoc;
38 import javax.transaction.Status JavaDoc;
39 import javax.transaction.Synchronization JavaDoc;
40 import javax.transaction.SystemException JavaDoc;
41 import javax.transaction.Transaction JavaDoc;
42
43 import org.objectweb.jonas_ejb.deployment.api.EntityDesc;
44
45 import org.objectweb.util.monolog.api.BasicLevel;
46
47 /**
48  * This class implements javax.ejb.EntityContext interface. An Entitycontext is
49  * bound to a bean instance. To be used, it must be associated to a
50  * JEntitySwitch, and possibly to a Transaction. In case the Context is used
51  * inside a Transaction, we use the Synchronization interface to be aware of
52  * transaction demarcations.
53  * @author Philippe Coq, Philippe Durieux
54  */

55 public class JEntityContext extends JContext implements EntityContext JavaDoc, Synchronization JavaDoc {
56
57     /**
58      * this instance has been modified
59      */

60     private boolean dirty = false;
61
62     /**
63      * This Context has been initialized, i.e. the EntitySwitch is
64      * relevant (initEntityContext has been called)
65      */

66     private boolean initialized = false;
67     
68     /**
69      * Transaction related to this synchronization
70      */

71     Transaction JavaDoc beanCoord = null;
72
73     private boolean mustnotifywriting = false;
74
75     private JEntitySwitch bs = null;
76
77     /**
78      * true between a remove and the commit
79      */

80     boolean ismarkedremoved;
81
82     /**
83      * true if just created in this transaction
84      */

85     boolean isnewinstance = false;
86
87     // ------------------------------------------------------------------
88
// constructors
89
// ------------------------------------------------------------------
90

91     /**
92      * Constructs an EntityContext the Context has to be initialized after this.
93      * @param bf - the JEntityFactory
94      * @param eb - the Enterprise Bean instance
95      */

96     public JEntityContext(JEntityFactory bf, EntityBean JavaDoc eb) {
97         super(bf, eb);
98     }
99
100     // ------------------------------------------------------------------
101
// EJBContext implementation
102
// ------------------------------------------------------------------
103

104     /**
105      * Get access to the EJB Timer Service.
106      * @return the EJB Timer Service
107      * @throws IllegalStateException Thrown if the instance is not allowed to
108      * use this method
109      */

110     public TimerService JavaDoc getTimerService() throws IllegalStateException JavaDoc {
111         int mystate = getState();
112         if (TraceEjb.isDebugIc()) {
113             TraceEjb.interp.log(BasicLevel.DEBUG, "" + mystate);
114         }
115         switch (mystate) {
116             case 0:
117                 TraceEjb.logger.log(BasicLevel.ERROR, "not allowed here");
118                 throw new IllegalStateException JavaDoc("getTimerService not allowed here");
119             case 4:
120                 TraceEjb.logger.log(BasicLevel.ERROR, "not allowed here");
121                 throw new IllegalStateException JavaDoc("getTimerService not allowed here");
122             case 1:
123                 // should work when called from ejbCreate,
124
// but timer operations should not -> return a dummy
125
// TimerService.
126
return bf.getTimerService();
127             default:
128                 return bs == null ? bf.getTimerService() : bs.getEntityTimerService();
129         }
130     }
131
132     // ------------------------------------------------------------------
133
// EntityContext implementation
134
// ------------------------------------------------------------------
135

136     /**
137      * Obtains a reference to the EJB object that is currently associated with
138      * the instance.
139      * @return The EJB object currently associated with the instance.
140      * @throws IllegalStateException Thrown if the instance invokes this method
141      * while the instance is in a state that does not allow the instance
142      * to invoke this method.
143      */

144     public EJBObject JavaDoc getEJBObject() throws IllegalStateException JavaDoc {
145         if (TraceEjb.isDebugIc()) {
146             TraceEjb.interp.log(BasicLevel.DEBUG, "");
147         }
148         if (ismarkedremoved) {
149             TraceEjb.logger.log(BasicLevel.ERROR, "marked removed");
150             throw new IllegalStateException JavaDoc("EJB is removed");
151         }
152         if (bs == null) {
153             TraceEjb.logger.log(BasicLevel.ERROR, "no EntitySwitch");
154             throw new IllegalStateException JavaDoc("no EntitySwitch");
155         }
156         EJBObject JavaDoc ejbobject = bs.getRemote();
157         if (ejbobject == null) {
158             throw new IllegalStateException JavaDoc("No Remote Interface for this bean");
159         }
160         return ejbobject;
161     }
162
163     /**
164      * Obtain a reference to the EJB local object that is currently associated
165      * with the instance.
166      * @param check if the local interface has been defined
167      * @return The EJB local object currently associated with the instance.
168      * @throws IllegalStateException - if the instance invokes this method while
169      * the instance is in a state that does not allow the instance to
170      * invoke this method, or if the instance does not have a local
171      * interface.
172      */

173     private EJBLocalObject JavaDoc getEJBLocalObject(boolean check) throws IllegalStateException JavaDoc {
174         if (TraceEjb.isDebugIc()) {
175             TraceEjb.interp.log(BasicLevel.DEBUG, "");
176         }
177         if (check) {
178             if (!bf.dd.hasDefinedLocalInterface()) {
179                 TraceEjb.logger.log(BasicLevel.ERROR, "No Local Interface declared for this bean");
180                 throw new IllegalStateException JavaDoc("No Local Interface declared for this bean");
181             }
182         }
183         if (ismarkedremoved) {
184             TraceEjb.logger.log(BasicLevel.ERROR, "marked removed");
185             throw new IllegalStateException JavaDoc("EJB is removed");
186         }
187         if (bs == null) {
188             TraceEjb.logger.log(BasicLevel.ERROR, "no EntitySwitch");
189             throw new IllegalStateException JavaDoc("no EntitySwitch");
190         }
191         EJBLocalObject JavaDoc ejblocalobject = bs.getLocal();
192         if (ejblocalobject == null) {
193             throw new IllegalStateException JavaDoc("No Local Object for this bean");
194         }
195         return ejblocalobject;
196     }
197
198     /**
199      * Obtain a reference to the EJB local object that is currently associated
200      * with the instance.
201      * @return The EJB local object currently associated with the instance.
202      * @throws IllegalStateException - if the instance invokes this method while
203      * the instance is in a state that does not allow the instance to
204      * invoke this method, or if the instance does not have a local
205      * interface.
206      */

207     public EJBLocalObject JavaDoc getEJBLocalObject() throws IllegalStateException JavaDoc {
208         return getEJBLocalObject(true);
209     }
210
211     /**
212      * Obtain a reference to the EJB local object that is currently associated
213      * with the instance.
214      * (internal use of getEJBLocalObject with no check).
215      * @return The EJB local object currently associated with the instance.
216      * @throws IllegalStateException - if the instance invokes this method while
217      * the instance is in a state that does not allow the instance to
218      * invoke this method, or if the instance does not have a local
219      * interface.
220      */

221     public EJBLocalObject JavaDoc get2EJBLocalObject() throws IllegalStateException JavaDoc {
222          return getEJBLocalObject(false);
223     }
224
225     /**
226      * Obtains the primary key of the EJB object that is currently associated
227      * with this instance.
228      * @return The EJB object currently associated with the instance.
229      * @throws IllegalStateException Thrown if the instance invokes this method
230      * while the instance is in a state that does not allow the instance
231      * to invoke this method.
232      */

233     public Object JavaDoc getPrimaryKey() throws IllegalStateException JavaDoc {
234         if (TraceEjb.isDebugIc()) {
235             TraceEjb.interp.log(BasicLevel.DEBUG, "");
236         }
237         if (ismarkedremoved) {
238             TraceEjb.logger.log(BasicLevel.ERROR, "marked removed");
239             throw new IllegalStateException JavaDoc("EJB is removed");
240         }
241         if (bs == null) {
242             TraceEjb.logger.log(BasicLevel.ERROR, "no EntitySwitch");
243             throw new IllegalStateException JavaDoc("no EntitySwitch");
244         }
245         return bs.getPrimaryKey();
246     }
247
248     // -------------------------------------------------------------------
249
// Synchronization implementation
250
// -------------------------------------------------------------------
251

252     /**
253      * This method is typically called at beforeCompletion
254      */

255     public void beforeCompletion() {
256         if (TraceEjb.isDebugContext()) {
257             TraceEjb.context.log(BasicLevel.DEBUG, "");
258         }
259
260         // If isMarkedRemoved, no need to do all this.
261
if (ismarkedremoved) {
262             if (TraceEjb.isDebugContext()) {
263                 TraceEjb.context.log(BasicLevel.DEBUG, "ismarkedremoved -> no ejbStore");
264             }
265             return;
266         }
267
268         if (beanCoord == null) {
269             // should not go here!
270
TraceEjb.logger.log(BasicLevel.ERROR, "no tx");
271         }
272
273         // First check that the primary key is not null.
274
// We must avoid accessing the DataBase when ejbCreate has failed.
275
if (isnewinstance) {
276             try {
277                 if (getPrimaryKey() == null) {
278                     // We do not force abort creation in order
279
// to be able to catch the CreateException
280
// otherwise CreateException will be overloaded
281
// in postInvoke by "cannot commit exception"
282
return;
283                 }
284             } catch (IllegalStateException JavaDoc e) {
285                 return;
286             }
287         }
288
289         try {
290             storeIfModified();
291         } catch (EJBException JavaDoc e) {
292             // Could not store bean data: set transaction rollback only
293
abortTransaction();
294         }
295     }
296
297     /**
298      * This method is typically called after the transaction is committed.
299      * @param status The status of the transaction completion.
300      */

301     public void afterCompletion(int status) {
302
303         boolean committed = (status == Status.STATUS_COMMITTED);
304         if (TraceEjb.isDebugContext()) {
305             if (committed) {
306                 TraceEjb.context.log(BasicLevel.DEBUG, "committed");
307             } else {
308                 TraceEjb.context.log(BasicLevel.DEBUG, "rolledback");
309             }
310         }
311
312         // Just check that we knew we were in a transaction (debug)
313
if (beanCoord == null) {
314             // should not go here!
315
TraceEjb.logger.log(BasicLevel.ERROR, "no tx for " + this);
316             return;
317         }
318         // Check also that the bs is not null (debug)
319
if (bs == null) {
320             // should not go here!
321
TraceEjb.logger.log(BasicLevel.ERROR, "Context without EntitySwitch reference");
322             throw new EJBException JavaDoc("Context with no Entity Switch");
323         }
324
325         // Let the EntitySwitch know that transaction is over and that it can
326
// now dispose of this Context for another transaction.
327
// no need to be in the correct component context ?
328
bs.txCompleted(beanCoord, committed);
329     }
330
331     // -------------------------------------------------------------------
332
// Other public methods
333
// -------------------------------------------------------------------
334

335     /**
336      * Raz Context before freeing it. This is mainly for garbage collector.
337      */

338     public void razEntityContext() {
339         if (TraceEjb.isDebugContext()) {
340             TraceEjb.context.log(BasicLevel.DEBUG, "");
341         }
342         bs = null;
343         beanCoord = null;
344         ismarkedremoved = false;
345         isnewinstance = false;
346         initialized = false;
347     }
348
349     /**
350      * Detach this Context from tx
351      */

352     public void detachTx() {
353         if (TraceEjb.isDebugContext()) {
354             TraceEjb.context.log(BasicLevel.DEBUG, "");
355         }
356         beanCoord = null;
357         ismarkedremoved = false;
358         isnewinstance = false;
359     }
360
361     /**
362      * Reinit Context for reuse
363      * @param bs - The Bean Switch this Context belongs to.
364      */

365     public void initEntityContext(JEntitySwitch bs) {
366         if (TraceEjb.isDebugContext()) {
367             TraceEjb.context.log(BasicLevel.DEBUG, "");
368         }
369         this.bs = bs;
370         initialized = true;
371     }
372
373     public void setRunningTx(Transaction JavaDoc tx) {
374         if (TraceEjb.isDebugContext()) {
375             TraceEjb.context.log(BasicLevel.DEBUG, "");
376         }
377         beanCoord = tx;
378     }
379
380     /**
381      * reuse EntityContext for another transaction. optimization: don't pass it
382      * by the pool.
383      * @param newtrans true if new transaction
384      */

385     public void reuseEntityContext(boolean newtrans) {
386         if (TraceEjb.isDebugContext()) {
387             TraceEjb.context.log(BasicLevel.DEBUG, "");
388         }
389
390         // This prevents reusing an instance removed in the same transaction.
391
if (ismarkedremoved) {
392             TraceEjb.context.log(BasicLevel.WARN, "Try to access a deleted object");
393             throw new NoSuchObjectLocalException JavaDoc("Instance has been removed");
394         }
395         if (newtrans) {
396             isnewinstance = false;
397         }
398         if (bs == null) {
399             TraceEjb.logger.log(BasicLevel.ERROR, "reuse Entity Context with no Entity Switch reference");
400         }
401     }
402
403     /**
404      * Set new instance flag
405      */

406     public void setNewInstance() {
407         isnewinstance = true;
408     }
409
410     /**
411      * Mark this context as removed. Complete removing will be achieved at the
412      * end of the transaction.
413      * @throws RemoteException ejbRemove failed
414      * @throws RemoveException ejbRemove failed
415      */

416     public void setRemoved() throws RemoteException JavaDoc, RemoveException JavaDoc {
417         if (TraceEjb.isDebugContext()) {
418             TraceEjb.context.log(BasicLevel.DEBUG, "");
419         }
420         EntityBean JavaDoc eb = (EntityBean JavaDoc) instance;
421
422         if (instance == null) {
423             TraceEjb.logger.log(BasicLevel.ERROR, "null instance!");
424             return;
425         }
426         // call ejbRemove() on instance
427
eb.ejbRemove();
428         // getPrimaryKey and getEJBObject should work in ejbRemove.
429
// => we do this only after ejbRemove call.
430
ismarkedremoved = true;
431     }
432
433     /**
434      * Check if context has been marked removed
435      * @return true when instance is marked removed.
436      */

437     public boolean isMarkedRemoved() {
438         return ismarkedremoved;
439     }
440
441     /**
442      * Check if context is a newly created instance
443      * @return true when instance has been created in the current transaction.
444      */

445     public boolean isNewInstance() {
446         return isnewinstance;
447     }
448
449     /**
450      * Returns the bean instance of this context Used in the generated classes
451      * to retrieve the instance
452      * @return the bean instance
453      * @throws RemoteException if no instance.
454      */

455     // RemoteException is throwned to allow simpler genic templates
456
public EntityBean JavaDoc getInstance() throws RemoteException JavaDoc {
457         if (instance == null) {
458             TraceEjb.logger.log(BasicLevel.ERROR, "null!");
459             throw new RemoteException JavaDoc("No instance available");
460         }
461         return (EntityBean JavaDoc) instance;
462     }
463
464     /**
465      * JEntityFactory accessor
466      * @return the JEntityFactory
467      */

468     public JEntityFactory getEntityFactory() {
469         return (JEntityFactory) bf;
470     }
471
472     /**
473      * JEntitySwitch accessor
474      * @return the JEntitySwitch
475      */

476     public JEntitySwitch getEntitySwitch() {
477         return (JEntitySwitch) bs;
478     }
479
480     /**
481      * set the EntitySwitch
482      * @param bs - the EntitySwitch
483      */

484     public void setEntitySwitch(JEntitySwitch bs) {
485         this.bs = bs;
486         ismarkedremoved = false;
487         mustnotifywriting = (bs.getPolicy() == EntityDesc.LOCK_CONTAINER_READ_UNCOMMITTED || bs.getPolicy() == EntityDesc.LOCK_DATABASE);
488      }
489
490     /**
491      * @return true if instance has been modified
492      */

493     public boolean isDirty() {
494         return dirty;
495     }
496
497     /**
498      * Set the dirty flag: true = instance modified.
499      */

500     public void setDirty(boolean d) {
501         if (TraceEjb.isDebugContext() && d) {
502             TraceEjb.context.log(BasicLevel.DEBUG, "mustnotifywriting=" + mustnotifywriting);
503             TraceEjb.context.log(BasicLevel.DEBUG, "dirty=" + dirty);
504         }
505         // Notify the EntitySwitch at 1st writing
506
if (mustnotifywriting && d && !dirty && initialized) {
507             // retrieve the current transaction.
508
Transaction JavaDoc tx = null;
509             try {
510                 tx = tm.getTransaction();
511             } catch (SystemException JavaDoc e) {
512                 TraceEjb.context.log(BasicLevel.ERROR, "getTransaction failed", e);
513             }
514             if (tx == null) {
515                 if (TraceEjb.isDebugContext()) {
516                     TraceEjb.context.log(BasicLevel.DEBUG, "Try to modify bean outside any transaction");
517                 }
518             } else {
519                 bs.notifyWriting(tx, this);
520             }
521         }
522         dirty = d;
523     }
524
525     /**
526      * Persistence: write data on storage
527      */

528     public void storeIfModified() {
529
530         EntityBean JavaDoc eb = (EntityBean JavaDoc) instance;
531
532         if (ismarkedremoved) {
533             // TODO something smart to do here ?
534
if (TraceEjb.isDebugContext()) {
535                 TraceEjb.context.log(BasicLevel.DEBUG, "marked removed");
536             }
537             return;
538         }
539         if (TraceEjb.isDebugContext()) {
540             TraceEjb.context.log(BasicLevel.DEBUG, "");
541         }
542
543         try {
544             // this method can fail if database serializes transactions
545
// This may do nothing if bean has not been modified (isModified
546
// optimization)
547
eb.ejbStore();
548         } catch (RemoteException JavaDoc e) {
549             throw new EJBException JavaDoc("Exception while storing data", e);
550         } catch (EJBException JavaDoc e) {
551             TraceEjb.logger.log(BasicLevel.ERROR, "raised EJBException ", e);
552             throw e;
553         } catch (RuntimeException JavaDoc e) {
554             TraceEjb.logger.log(BasicLevel.ERROR, "runtime exception: ", e);
555             throw new EJBException JavaDoc("Exception while storing data", e);
556         } catch (Error JavaDoc e) {
557             TraceEjb.logger.log(BasicLevel.ERROR, "error: ", e);
558             throw new EJBException JavaDoc("Error while storing data");
559         }
560     }
561
562     /**
563      * passivate this instance
564      */

565     public void passivate() {
566
567         if (TraceEjb.isDebugContext()) {
568             TraceEjb.context.log(BasicLevel.DEBUG, "");
569         }
570
571         EntityBean JavaDoc eb = (EntityBean JavaDoc) instance;
572         setState(1);
573
574         try {
575             eb.ejbPassivate();
576         } catch (Exception JavaDoc e) {
577             TraceEjb.logger.log(BasicLevel.ERROR, "ejbPassivate failed", e);
578         } catch (Error JavaDoc e) {
579             TraceEjb.logger.log(BasicLevel.ERROR, "ejbPassivate error", e);
580         }
581     }
582
583     /**
584      * Activate instance.
585      * @param doactivate True if ejbActivate() is called before ejbLoad()
586      */

587     public void activate(boolean doactivate) {
588         if (TraceEjb.isDebugContext()) {
589             TraceEjb.context.log(BasicLevel.DEBUG, "");
590         }
591
592         EntityBean JavaDoc eb = (EntityBean JavaDoc) instance;
593
594         try {
595             if (doactivate) {
596                 setState(1);
597                 // Call ejbActivate
598
eb.ejbActivate();
599             }
600             setState(2);
601             // Load bean state from database
602
eb.ejbLoad();
603         } catch (RemoteException JavaDoc e) {
604             TraceEjb.logger.log(BasicLevel.ERROR, "remote exception: ", e);
605             throw new EJBException JavaDoc("Cannot activate bean", e);
606         } catch (RuntimeException JavaDoc e) {
607             TraceEjb.logger.log(BasicLevel.ERROR, "runtime exception: ", e);
608             throw new EJBException JavaDoc("Cannot activate bean", e);
609         } catch (Error JavaDoc e) {
610             TraceEjb.logger.log(BasicLevel.ERROR, "error: ", e);
611             throw new EJBException JavaDoc("Cannot activate bean");
612         }
613     }
614
615     // ----------------------------------------------------------------
616
// private methods
617
// ----------------------------------------------------------------
618

619     /**
620      * abort current transaction if an exception occured while accessing the
621      * bean state (load, store, ...)
622      */

623     private void abortTransaction() {
624         if (TraceEjb.isDebugContext()) {
625             TraceEjb.context.log(BasicLevel.DEBUG, "");
626         }
627
628         // If we are inside a transaction, it must be rolled back
629
if (beanCoord != null) {
630             try {
631                 beanCoord.setRollbackOnly();
632             } catch (SystemException JavaDoc e) {
633                 TraceEjb.logger.log(BasicLevel.ERROR, "cannot setRollbackOnly", e);
634             }
635         }
636     }
637
638 }
639
Popular Tags