JEntityContext.java

00001 
00026 package org.objectweb.jonas_ejb.container;
00027 
00028 import java.rmi.RemoteException;
00029 
00030 import javax.ejb.EJBException;
00031 import javax.ejb.EJBLocalObject;
00032 import javax.ejb.EJBObject;
00033 import javax.ejb.EntityBean;
00034 import javax.ejb.EntityContext;
00035 import javax.ejb.NoSuchObjectLocalException;
00036 import javax.ejb.RemoveException;
00037 import javax.ejb.TimerService;
00038 import javax.transaction.Status;
00039 import javax.transaction.Synchronization;
00040 import javax.transaction.SystemException;
00041 import javax.transaction.Transaction;
00042 
00043 import org.objectweb.jonas_ejb.deployment.api.EntityDesc;
00044 
00045 import org.objectweb.util.monolog.api.BasicLevel;
00046 
00055 public class JEntityContext extends JContext implements EntityContext, Synchronization {
00056 
00060     private boolean dirty = false;
00061 
00065     Transaction beanCoord = null;
00066 
00067     private boolean mustnotifywriting = false;
00068 
00069     private JEntitySwitch bs = null;
00070 
00074     boolean ismarkedremoved;
00075 
00079     boolean isnewinstance = false;
00080 
00081     // ------------------------------------------------------------------
00082     // constructors
00083     // ------------------------------------------------------------------
00084 
00090     public JEntityContext(JEntityFactory bf, EntityBean eb) {
00091         super(bf, eb);
00092         // entity beans may have home or localHome
00093         this.home = bf.getHome();
00094         this.localhome = bf.getLocalHome();
00095     }
00096 
00097     // ------------------------------------------------------------------
00098     // EJBContext implementation
00099     // ------------------------------------------------------------------
00100 
00107     public TimerService getTimerService() throws IllegalStateException {
00108         int mystate = getState();
00109         TraceEjb.interp.log(BasicLevel.DEBUG, "" + mystate);
00110         switch (mystate) {
00111             case 0:
00112                 TraceEjb.logger.log(BasicLevel.ERROR, "not allowed here");
00113                 throw new IllegalStateException("getTimerService not allowed here");
00114             case 4:
00115                 TraceEjb.logger.log(BasicLevel.ERROR, "not allowed here");
00116                 throw new IllegalStateException("getTimerService not allowed here");
00117             case 1:
00118                 // should work when called from ejbCreate,
00119                 // but timer operations should not -> return a dummy
00120                 // TimerService.
00121                 return bf.getTimerService();
00122             default:
00123                 return bs == null ? bf.getTimerService() : bs.getEntityTimerService();
00124         }
00125     }
00126 
00127     // ------------------------------------------------------------------
00128     // EntityContext implementation
00129     // ------------------------------------------------------------------
00130 
00139     public EJBObject getEJBObject() throws IllegalStateException {
00140         TraceEjb.interp.log(BasicLevel.DEBUG, "");
00141         if (ismarkedremoved) {
00142             TraceEjb.logger.log(BasicLevel.ERROR, "marked removed");
00143             throw new IllegalStateException("EJB is removed");
00144         }
00145         if (bs == null) {
00146             TraceEjb.logger.log(BasicLevel.ERROR, "no EntitySwitch");
00147             throw new IllegalStateException("no EntitySwitch");
00148         }
00149         EJBObject ejbobject = bs.getRemote();
00150         if (ejbobject == null) {
00151             throw new IllegalStateException("No Remote Interface for this bean");
00152         }
00153         return ejbobject;
00154     }
00155 
00166     private EJBLocalObject getEJBLocalObject(boolean check) throws IllegalStateException {
00167         TraceEjb.interp.log(BasicLevel.DEBUG, "");
00168         if (check) {
00169             if (!bf.dd.hasDefinedLocalInterface()) {
00170                 TraceEjb.logger.log(BasicLevel.ERROR, "No Local Interface declared for this bean");
00171                 throw new IllegalStateException("No Local Interface declared for this bean");
00172             }
00173         }
00174         if (ismarkedremoved) {
00175             TraceEjb.logger.log(BasicLevel.ERROR, "marked removed");
00176             throw new IllegalStateException("EJB is removed");
00177         }
00178         if (bs == null) {
00179             TraceEjb.logger.log(BasicLevel.ERROR, "no EntitySwitch");
00180             throw new IllegalStateException("no EntitySwitch");
00181         }
00182         EJBLocalObject ejblocalobject = bs.getLocal();
00183         if (ejblocalobject == null) {
00184             throw new IllegalStateException("No Local Object for this bean");
00185         }
00186         return ejblocalobject;
00187     }
00188 
00198     public EJBLocalObject getEJBLocalObject() throws IllegalStateException {
00199         return getEJBLocalObject(true);
00200     }
00201 
00212     public EJBLocalObject get2EJBLocalObject() throws IllegalStateException {
00213          return getEJBLocalObject(false);
00214     }
00215 
00224     public Object getPrimaryKey() throws IllegalStateException {
00225         TraceEjb.interp.log(BasicLevel.DEBUG, "");
00226         if (ismarkedremoved) {
00227             TraceEjb.logger.log(BasicLevel.ERROR, "marked removed");
00228             throw new IllegalStateException("EJB is removed");
00229         }
00230         if (bs == null) {
00231             TraceEjb.logger.log(BasicLevel.ERROR, "no EntitySwitch");
00232             throw new IllegalStateException("no EntitySwitch");
00233         }
00234         return bs.getPrimaryKey();
00235     }
00236 
00237     // -------------------------------------------------------------------
00238     // Synchronization implementation
00239     // -------------------------------------------------------------------
00240 
00244     public void beforeCompletion() {
00245         TraceEjb.context.log(BasicLevel.DEBUG, "");
00246 
00247         // If isMarkedRemoved, no need to do all this.
00248         if (ismarkedremoved) {
00249             TraceEjb.context.log(BasicLevel.DEBUG, "ismarkedremoved -> no ejbStore");
00250             return;
00251         }
00252 
00253         if (beanCoord == null) {
00254             // should not go here!
00255             TraceEjb.logger.log(BasicLevel.ERROR, "no tx");
00256         }
00257 
00258         // First check that the primary key is not null.
00259         // We must avoid accessing the DataBase when ejbCreate has failed.
00260         if (isnewinstance) {
00261             try {
00262                 if (getPrimaryKey() == null) {
00263                     // We do not force abort creation in order
00264                     // to be able to catch the CreateException
00265                     // otherwise CreateException will be overloaded
00266                     // in postInvoke by "cannot commit exception"
00267                     return;
00268                 }
00269             } catch (IllegalStateException e) {
00270                 return;
00271             }
00272         }
00273 
00274         try {
00275             storeIfModified();
00276         } catch (EJBException e) {
00277             // Could not store bean data: set transaction rollback only
00278             abortTransaction();
00279         }
00280     }
00281 
00286     public void afterCompletion(int status) {
00287 
00288         boolean committed = (status == Status.STATUS_COMMITTED);
00289         if (committed) {
00290             TraceEjb.context.log(BasicLevel.DEBUG, "committed");
00291         } else {
00292             TraceEjb.context.log(BasicLevel.DEBUG, "rolledback");
00293         }
00294 
00295         // Just check that we knew we were in a transaction (debug)
00296         if (beanCoord == null) {
00297             // should not go here!
00298             TraceEjb.logger.log(BasicLevel.ERROR, "no tx for " + this);
00299             return;
00300         }
00301         // Check also that the bs is not null (debug)
00302         if (bs == null) {
00303             // should not go here!
00304             TraceEjb.logger.log(BasicLevel.ERROR, "Context without EntitySwitch reference");
00305             throw new EJBException("Context with no Entity Switch");
00306         }
00307 
00308         // Let the EntitySwitch know that transaction is over and that it can
00309         // now dispose of this Context for another transaction.
00310         // no need to be in the correct component context ?
00311         bs.txCompleted(beanCoord, committed);
00312     }
00313 
00314     // -------------------------------------------------------------------
00315     // Other public methods
00316     // -------------------------------------------------------------------
00317 
00321     public void razEntityContext() {
00322         TraceEjb.context.log(BasicLevel.DEBUG, "");
00323         bs = null;
00324         beanCoord = null;
00325         ismarkedremoved = false;
00326         isnewinstance = false;
00327     }
00328 
00332     public void detachTx() {
00333         TraceEjb.context.log(BasicLevel.DEBUG, "");
00334         beanCoord = null;
00335         ismarkedremoved = false;
00336         isnewinstance = false;
00337     }
00338 
00343     public void initEntityContext(JEntitySwitch bs) {
00344         TraceEjb.context.log(BasicLevel.DEBUG, "");
00345         this.bs = bs;
00346         ismarkedremoved = false;
00347         mustnotifywriting = (bs.getPolicy() == EntityDesc.LOCK_CONTAINER_READ_UNCOMMITTED || bs.getPolicy() == EntityDesc.LOCK_DATABASE);
00348     }
00349 
00350     public void setRunningTx(Transaction tx) {
00351         TraceEjb.context.log(BasicLevel.DEBUG, "");
00352         beanCoord = tx;
00353     }
00354 
00360     public void reuseEntityContext(boolean newtrans) {
00361         TraceEjb.context.log(BasicLevel.DEBUG, "");
00362 
00363         // This prevents reusing an instance removed in the same transaction.
00364         if (ismarkedremoved) {
00365             TraceEjb.context.log(BasicLevel.WARN, "Try to access a deleted object");
00366             throw new NoSuchObjectLocalException("Instance has been removed");
00367         }
00368         if (newtrans) {
00369             isnewinstance = false;
00370         }
00371         if (bs == null) {
00372             TraceEjb.logger.log(BasicLevel.ERROR, "reuse Entity Context with no Entity Switch reference");
00373         }
00374     }
00375 
00379     public void setNewInstance() {
00380         isnewinstance = true;
00381     }
00382 
00389     public void setRemoved() throws RemoteException, RemoveException {
00390         TraceEjb.context.log(BasicLevel.DEBUG, "");
00391         EntityBean eb = (EntityBean) instance;
00392 
00393         if (instance == null) {
00394             TraceEjb.logger.log(BasicLevel.ERROR, "null instance!");
00395             return;
00396         }
00397         // call ejbRemove() on instance
00398         eb.ejbRemove();
00399         // getPrimaryKey and getEJBObject should work in ejbRemove.
00400         // => we do this only after ejbRemove call.
00401         ismarkedremoved = true;
00402     }
00403 
00408     public boolean isMarkedRemoved() {
00409         return ismarkedremoved;
00410     }
00411 
00416     public boolean isNewInstance() {
00417         return isnewinstance;
00418     }
00419 
00426     // RemoteException is throwned to allow simpler genic templates
00427     public EntityBean getInstance() throws RemoteException {
00428         if (instance == null) {
00429             TraceEjb.logger.log(BasicLevel.ERROR, "null!");
00430             throw new RemoteException("No instance available");
00431         }
00432         return (EntityBean) instance;
00433     }
00434 
00439     public JEntityFactory getEntityFactory() {
00440         return (JEntityFactory) bf;
00441     }
00442 
00447     public JEntitySwitch getEntitySwitch() {
00448         return (JEntitySwitch) bs;
00449     }
00450 
00455     public void setEntitySwitch(JEntitySwitch bs) {
00456         this.bs = bs;
00457     }
00458 
00462     public boolean isDirty() {
00463         return dirty;
00464     }
00465 
00469     public void setDirty(boolean d) {
00470         // Notify the EntitySwitch at 1st writing
00471         if (mustnotifywriting && d && !dirty) {
00472             // retrieve the current transaction.
00473             Transaction tx = null;
00474             try {
00475                 tx = tm.getTransaction();
00476             } catch (SystemException e) {
00477                 TraceEjb.context.log(BasicLevel.ERROR, "getTransaction failed:" + e);
00478             }
00479             if (tx == null) {
00480                 TraceEjb.context.log(BasicLevel.DEBUG, "Try to modify bean outside any transaction");
00481             } else {
00482                 bs.notifyWriting(tx, this);
00483             }
00484         }
00485         dirty = d;
00486     }
00487 
00491     public void storeIfModified() {
00492 
00493         EntityBean eb = (EntityBean) instance;
00494 
00495         if (ismarkedremoved) {
00496             // TODO something smart to do here ?
00497             TraceEjb.context.log(BasicLevel.DEBUG, "marked removed");
00498             return;
00499         }
00500         TraceEjb.context.log(BasicLevel.DEBUG, "");
00501 
00502         try {
00503             // this method can fail if database serializes transactions
00504             // This may do nothing if bean has not been modified (isModified
00505             // optimization)
00506             eb.ejbStore();
00507         } catch (RemoteException e) {
00508             throw new EJBException("Exception while storing data");
00509         } catch (EJBException e) {
00510             TraceEjb.logger.log(BasicLevel.ERROR, "raised EJBException ", e);
00511             throw e;
00512         } catch (RuntimeException e) {
00513             TraceEjb.logger.log(BasicLevel.ERROR, "runtime exception: ", e);
00514             throw new EJBException("Exception while storing data", e);
00515         } catch (Error e) {
00516             TraceEjb.logger.log(BasicLevel.ERROR, "error: ", e);
00517             throw new EJBException("Error while storing data");
00518         }
00519     }
00520 
00524     public void passivate() {
00525 
00526         TraceEjb.context.log(BasicLevel.DEBUG, "");
00527 
00528         EntityBean eb = (EntityBean) instance;
00529         setState(1);
00530 
00531         try {
00532             eb.ejbPassivate();
00533         } catch (Exception e) {
00534             TraceEjb.logger.log(BasicLevel.ERROR, "ejbPassivate failed", e);
00535         } catch (Error e) {
00536             TraceEjb.logger.log(BasicLevel.ERROR, "ejbPassivate error", e);
00537         }
00538     }
00539 
00544     public void activate(boolean doactivate) {
00545         TraceEjb.context.log(BasicLevel.DEBUG, "");
00546 
00547         EntityBean eb = (EntityBean) instance;
00548 
00549         try {
00550             if (doactivate) {
00551                 setState(1);
00552                 // Call ejbActivate
00553                 eb.ejbActivate();
00554             }
00555             setState(2);
00556             // Load bean state from database
00557             eb.ejbLoad();
00558         } catch (RemoteException e) {
00559             TraceEjb.logger.log(BasicLevel.ERROR, "remote exception: ", e);
00560             throw new EJBException("Cannot activate bean");
00561         } catch (RuntimeException e) {
00562             TraceEjb.logger.log(BasicLevel.ERROR, "runtime exception: ", e);
00563             throw new EJBException("Cannot activate bean");
00564         } catch (Error e) {
00565             TraceEjb.logger.log(BasicLevel.ERROR, "error: ", e);
00566             throw new EJBException("Cannot activate bean");
00567         }
00568     }
00569 
00570     // ----------------------------------------------------------------
00571     // private methods
00572     // ----------------------------------------------------------------
00573 
00578     private void abortTransaction() {
00579         TraceEjb.context.log(BasicLevel.DEBUG, "");
00580 
00581         // If we are inside a transaction, it must be rolled back
00582         if (beanCoord != null) {
00583             try {
00584                 beanCoord.setRollbackOnly();
00585             } catch (SystemException e) {
00586                 TraceEjb.logger.log(BasicLevel.ERROR, "cannot setRollbackOnly");
00587             }
00588         }
00589     }
00590 
00591 }

Generated on Tue Feb 15 15:05:37 2005 for JOnAS by  doxygen 1.3.9.1