JEntitySwitchCS.java

00001 
00026 package org.objectweb.jonas_ejb.container;
00027 
00028 import javax.ejb.EJBException;
00029 import javax.ejb.NoSuchObjectLocalException;
00030 import javax.ejb.TransactionRolledbackLocalException;
00031 import javax.transaction.Status;
00032 import javax.transaction.SystemException;
00033 import javax.transaction.Transaction;
00034 
00035 import org.objectweb.jonas_ejb.deployment.api.EntityDesc;
00036 
00037 import org.objectweb.util.monolog.api.BasicLevel;
00038 
00045 public class JEntitySwitchCS extends JEntitySwitch {
00046 
00050     protected JEntityContext itContext = null;
00051 
00052     // max time to wait when in a transaction, before checking if
00053     // transaction has been set rollback only (deadlock detection)
00054     protected static int maxtime = 3000; // 3 sec.
00055 
00060     public JEntitySwitchCS() {
00061         lockpolicy = EntityDesc.LOCK_CONTAINER_SERIALIZED;
00062         txUpdates = false; // TODO : can set this in DD.
00063     }
00064 
00065     protected void initpolicy(JEntityFactory bf) {
00066         lazyregister = false;
00067     }
00068 
00069     protected JEntityContext getContext4Tx(Transaction tx) {
00070         return itContext;
00071     }
00072 
00073     protected void setContext4Tx(Transaction tx, JEntityContext ctx) {
00074         if (TraceEjb.isDebugContext()) {
00075             TraceEjb.context.log(BasicLevel.DEBUG, "set itContext=" + ctx);
00076         }
00077         itContext = ctx;
00078     }
00079 
00080     protected void removeContext4Tx(Transaction tx) {
00081         if (TraceEjb.isDebugContext()) {
00082             TraceEjb.context.log(BasicLevel.DEBUG, "unset itContext=" + itContext);
00083         }
00084         itContext = null;
00085     }
00086 
00087     public void waitmyturn(Transaction tx) {
00088         // Synchronization.
00089         if (tx == null) {
00090             // Must wait in case of TX
00091             while (runningtx != null) {
00092                 if (TraceEjb.isDebugSynchro()) {
00093                     TraceEjb.synchro.log(BasicLevel.DEBUG, ident + "mapICtx IH: WAIT end IT");
00094                 }
00095                 waiters++;
00096                 try {
00097                     wait(maxtime);
00098                     if (TraceEjb.isDebugSynchro())
00099                             TraceEjb.synchro.log(BasicLevel.DEBUG, ident + "mapICtx IH: NOTIFIED");
00100                 } catch (InterruptedException e) {
00101                     if (TraceEjb.isDebugSynchro())
00102                             TraceEjb.synchro.log(BasicLevel.DEBUG, ident + "mapICtx IH: INTERRUPTED");
00103                 } catch (Exception e) {
00104                     throw new EJBException("JEntitySwitch synchronization pb", e);
00105                 } finally {
00106                     waiters--;
00107                 }
00108             }
00109         } else {
00110             
00111             // Must wait in case of TX or if instance has been modified outside
00112             // transaction.
00113             // Don't wait transactions if 1 instance per transaction.
00114             int waitcount = 0;
00115             while (inDirtyList || (runningtx != null && !tx.equals(runningtx))) {
00116                 // instance is dirty : must write it before working on it again.
00117                 // this is mandatory to be able to retrieve a good state in case
00118                 // of rollback.
00119                 if (inDirtyList) {
00120                     if (TraceEjb.isDebugSynchro())
00121                             TraceEjb.synchro.log(BasicLevel.DEBUG, ident + "mapICtx IT: WAIT end IH");
00122                     // Cannot passivate here, because must be done outside tx
00123                     // context
00124                     bf.synchronizeEntities();
00125                 } else {
00126                     if (TraceEjb.isDebugSynchro())
00127                             TraceEjb.synchro.log(BasicLevel.DEBUG, ident + "mapICtx IT: WAIT end IT");
00128                     // deadlock detection
00129                     blockedtx = tx;
00130                     if (waitcount++ > 1 && bf.isBlocked(runningtx) && bf.isBlocking(tx)) {
00131                         try {
00132                             tx.setRollbackOnly();
00133                         } catch (SystemException e) {
00134                             TraceEjb.logger.log(BasicLevel.ERROR, ident
00135                                     + "getICtx IT: unexpected exception setting rollbackonly");
00136                         }
00137                         TraceEjb.logger.log(BasicLevel.WARN, ident + "getICtx IT: transaction rolled back");
00138                         throw new TransactionRolledbackLocalException("possible deadlock");
00139                     }
00140                 }
00141                 waiters++;
00142                 try {
00143                     wait(maxtime);
00144                     if (TraceEjb.isDebugSynchro())
00145                             TraceEjb.synchro.log(BasicLevel.DEBUG, ident + "mapICtx IT: NOTIFIED");
00146                 } catch (InterruptedException e) {
00147                     if (TraceEjb.isDebugSynchro())
00148                             TraceEjb.synchro.log(BasicLevel.DEBUG, ident + "mapICtx IT: INTERRUPTED");
00149                 } catch (Exception e) {
00150                     throw new EJBException("JEntitySwitch synchronization pb", e);
00151                 } finally {
00152                     waiters--;
00153                     blockedtx = null;
00154                 }
00155                 // If transaction has been rolledback or set rollback only, give
00156                 // up.
00157                 int status = Status.STATUS_ROLLEDBACK;
00158                 try {
00159                     status = tx.getStatus();
00160                 } catch (SystemException e) {
00161                     TraceEjb.logger.log(BasicLevel.ERROR, ident
00162                             + "getICtx IT: unexpected exception getting transaction status");
00163                 }
00164                 switch (status) {
00165                 case Status.STATUS_MARKED_ROLLBACK:
00166                 case Status.STATUS_ROLLEDBACK:
00167                 case Status.STATUS_ROLLING_BACK:
00168                     TraceEjb.logger.log(BasicLevel.WARN, ident + "getICtx IT: transaction rolled back");
00169                     throw new TransactionRolledbackLocalException("rollback occured while waiting");
00170                 }
00171             }
00172         }
00173 
00174     }
00175 
00181     public synchronized boolean passivateIH(boolean passivation) {
00182 
00183         JEntityContext jec = getContext4Tx(null);
00184 
00185         // If already passivated, look if we can destroy the objects
00186         if (jec == null) {
00187             if (inactivityTimeout > 0) {
00188                 long diff = System.currentTimeMillis() - timestamp;
00189                 if (diff > inactivityTimeout) {
00190                     TraceEjb.context.log(BasicLevel.DEBUG, ident + timestamp);
00191                     discardContext(null, true, false);
00192                 }
00193             }
00194             return true;
00195         }
00196 
00197         // If the instance is busy, don't touch it.
00198         if (countIH > 0 && !txUpdates) {
00199             // will be stored later, when released by last thread (countIH = 0)
00200             // return true to remove from the dirty list, since it will be
00201             // written anyway.
00202             if (TraceEjb.isDebugSynchro()) TraceEjb.synchro.log(BasicLevel.DEBUG, ident + " used off TX");
00203             mustStore = true;
00204             return true;
00205         }
00206         if (runningtx != null) {
00207             if (TraceEjb.isDebugSynchro()) TraceEjb.synchro.log(BasicLevel.DEBUG, ident + " used in TX");
00208             return false;
00209         }
00210 
00211         if (TraceEjb.isDebugSynchro()) TraceEjb.synchro.log(BasicLevel.DEBUG, ident);
00212 
00213         if (jec.isMarkedRemoved()) {
00214             discardContext(null, true, true);
00215             return true;
00216         }
00217         
00218         // Store the instance state
00219         // -> only if instance not discarded, and not readonly.
00220         if (!todiscard && !txUpdates) {
00221             try {
00222                 jec.storeIfModified();
00223             } catch (Exception e) {
00224                 TraceEjb.logger.log(BasicLevel.ERROR, ident, "error while storing bean state:", e);
00225             }
00226             mustStore = false;
00227             // don't set dirty false here, will be done in endIH.
00228             // this prevent duplicates in dirty list.
00229         }
00230 
00231         // passivate this instance if required.
00232         if (passivation) {
00233             if (TraceEjb.isDebugContext()) TraceEjb.context.log(BasicLevel.DEBUG, "passivated: " + jec);
00234             jec.passivate();
00235             bf.releaseJContext(jec);
00236             removeContext4Tx(null);
00237             // passivation done, set the timestamp
00238             timestamp = System.currentTimeMillis();
00239             TraceEjb.context.log(BasicLevel.DEBUG, ident + timestamp);
00240             if (waiters > 0) {
00241                 TraceEjb.synchro.log(BasicLevel.DEBUG, ident + " notify");
00242                 notifyAll();
00243             }
00244         }
00245         return true;
00246     }
00247 
00251     public synchronized void endIH() {
00252         inDirtyList = false;
00253         if (getContext4Tx(null) == null) {
00254             if (TraceEjb.isDebugSynchro()) TraceEjb.synchro.log(BasicLevel.DEBUG, ident + " discarded!");
00255             return;
00256         }
00257         // If the instance is busy, don't touch it.
00258         // If no context mapped, nothing to do
00259         if (countIH == 0) {
00260             if (TraceEjb.isDebugSynchro()) TraceEjb.synchro.log(BasicLevel.DEBUG, ident + " ready again");
00261         } else {
00262             if (TraceEjb.isDebugSynchro()) TraceEjb.synchro.log(BasicLevel.DEBUG, ident + " busy!");
00263         }
00264         if (waiters > 0) {
00265             TraceEjb.synchro.log(BasicLevel.DEBUG, ident + " notify");
00266             notifyAll();
00267         }
00268     }
00269 
00270     public synchronized void notifyWriting(Transaction tx, JEntityContext bctx) {
00271         return; // NEVER
00272     }
00273 
00279     public int getState() {
00280         if (itContext != null) {
00281             if (itContext.isMarkedRemoved()) {
00282                 return 4;
00283             } else {
00284                 if (runningtx != null) {
00285                     return 0;
00286                 } else {
00287                     if (inDirtyList) {
00288                         return 1;
00289                     } else {
00290                         return 2;
00291                     }
00292                 }
00293             }
00294         }
00295         return 3;
00296     }
00297 
00298 }

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