JStatelessFactory.java

00001 
00026 package org.objectweb.jonas_ejb.container;
00027 
00028 import java.rmi.RemoteException;
00029 import java.util.ArrayList;
00030 import java.util.List;
00031 import java.util.ListIterator;
00032 
00033 import javax.ejb.EJBException;
00034 import javax.ejb.EnterpriseBean;
00035 import javax.ejb.SessionBean;
00036 import javax.ejb.TimedObject;
00037 import javax.ejb.Timer;
00038 import javax.ejb.TimerService;
00039 import javax.naming.Context;
00040 import javax.transaction.Status;
00041 import javax.transaction.SystemException;
00042 
00043 import org.objectweb.jonas_ejb.deployment.api.MethodDesc;
00044 import org.objectweb.jonas_ejb.deployment.api.SessionStatelessDesc;
00045 import org.objectweb.jonas_ejb.lib.EJBInvocation;
00046 import org.objectweb.jonas_timer.TraceTimer;
00047 
00048 import org.objectweb.util.monolog.api.BasicLevel;
00049 
00054 public class JStatelessFactory extends JSessionFactory {
00055 
00061     protected List bctxlist = new ArrayList();
00062 
00063     // service endpoint home
00064     protected JServiceEndpointHome sehome = null;
00065 
00066     protected int instanceCount = 0;
00067 
00068     // initial value for pool size
00069     protected int minPoolSize = 0;
00070 
00071     // nb max of instances in pool
00072     protected int maxCacheSize = 0;
00073 
00074         private static final int MAX_NB_RETRY = 2;
00075 
00076 
00082     public JStatelessFactory(SessionStatelessDesc dd, JContainer cont) {
00083         super(dd, cont);
00084         TraceEjb.interp.log(BasicLevel.DEBUG, "");
00085 
00086         // Create the ServiceEndpointHome if defined in DD
00087         Class sehomeclass = null;
00088         String clname = dd.getFullWrpSEHomeName();
00089         if (clname != null) {
00090             try {
00091                 sehomeclass = cont.getClassLoader().loadClass(clname);
00092             } catch (ClassNotFoundException e) {
00093                 throw new EJBException(ejbname + " Cannot load " + clname, e);
00094             }
00095             if (TraceEjb.isDebugIc()) {
00096                 TraceEjb.interp.log(BasicLevel.DEBUG, ejbname + ": " + clname + " loaded");
00097             }
00098             try {
00099                 // new JServiceEndpointHome(dd, this)
00100                 int nbp = 2;
00101                 Class[] ptype = new Class[nbp];
00102                 Object[] pobj = new Object[nbp];
00103                 ptype[0] = org.objectweb.jonas_ejb.deployment.api.SessionStatelessDesc.class;
00104                 pobj[0] = (Object) dd;
00105                 ptype[1] = org.objectweb.jonas_ejb.container.JStatelessFactory.class;
00106                 pobj[1] = (Object) this;
00107                 sehome = (JServiceEndpointHome) sehomeclass.getConstructor(ptype).newInstance(pobj);
00108             } catch (Exception e) {
00109                 throw new EJBException(ejbname + " Cannot create serviceEndpointHome ", e);
00110             }
00111             // register it in JNDI
00112             try {
00113                 sehome.register();
00114             } catch (Exception e) {
00115                 throw new EJBException(ejbname + " Cannot register serviceEndpointHome ", e);
00116             }
00117         }
00118 
00119         isStateful = false;
00120         maxCacheSize = dd.getCacheMax();
00121         minPoolSize = dd.getPoolMin();
00122         if (TraceEjb.isDebugSwapper()) {
00123             TraceEjb.swapper.log(BasicLevel.DEBUG, " maxCacheSize = " + maxCacheSize);
00124         }
00125     }
00126     
00130     public void initInstancePool() {
00131         // pre-allocate a set of JSessionContext (bean instances)
00132         if (minPoolSize != 0) {
00133             TraceEjb.interp.log(BasicLevel.INFO, "pre-allocate a set of " + minPoolSize
00134                     + " stateless session instances");
00135             JSessionSwitch ss = null;
00136             try {
00137                 ss = createNewSession();
00138             } catch (RemoteException e) {
00139                 TraceEjb.logger.log(BasicLevel.ERROR, ejbname + " cannot create new session", e);
00140                 throw new EJBException(ejbname + " Cannot create session for pool: ", e);
00141             }
00142             Context bnctx = setComponentContext(); // for createNewInstance
00143             synchronized (bctxlist) {
00144                 for (int i = 0; i < minPoolSize; i++) {
00145                     JSessionContext ctx = null;
00146                     try {
00147                         // must pass a session switch (for ejbCreate)
00148                         ctx = createNewInstance(ss);
00149                         bctxlist.add(ctx);
00150                     } catch (Exception e) {
00151                         TraceEjb.logger.log(BasicLevel.ERROR, ejbname + " cannot create new instance", e);
00152                         throw new EJBException(ejbname + " Cannot init pool of instances ", e);
00153                     }
00154                 }
00155             }
00156             resetComponentContext(bnctx);
00157         }
00158     }
00159 
00160     public JServiceEndpointHome getSEHome() {
00161         return sehome;
00162     }
00163     
00164     // ---------------------------------------------------------------
00165     // BeanFactory implementation
00166     // ---------------------------------------------------------------
00167 
00171     public int getPoolSize() {
00172         return bctxlist.size();
00173     }
00174 
00179     public void reduceCache() {
00180         TraceEjb.swapper.log(BasicLevel.DEBUG, "");
00181         // reduce the pool to the minPoolSize
00182         int poolsz = minPoolSize;
00183         synchronized (bctxlist) {
00184             if (TraceEjb.isDebugSwapper()) {
00185                 TraceEjb.swapper.log(BasicLevel.DEBUG, "try to reduce " + bctxlist.size() + " to " + poolsz);
00186             }
00187             while (bctxlist.size() > poolsz) {
00188                 ListIterator i = bctxlist.listIterator();
00189                 if (i.hasNext()) {
00190                     i.next();
00191                     i.remove();
00192                     instanceCount--;
00193                 }
00194             }
00195         }
00196         if (TraceEjb.isDebugSwapper()) {
00197             TraceEjb.swapper.log(BasicLevel.DEBUG, "cacheSize= " + getCacheSize());
00198         }
00199 
00200     }
00201 
00202     // ---------------------------------------------------------------
00203     // other public methods
00204     // ---------------------------------------------------------------
00205 
00210     public TimerService getTimerService() {
00211         if (myTimerService == null) {
00212             // TODO : Check that instance implements TimedObject ?
00213             myTimerService = new JTimerService(this);
00214         }
00215         return myTimerService;
00216     }
00217 
00222     public JSessionSwitch createNewSession() throws RemoteException {
00223         TraceEjb.interp.log(BasicLevel.DEBUG, "");
00224         JStatelessSwitch bs = new JStatelessSwitch(this);
00225         return bs;
00226     }
00227 
00231     public JSessionContext getJContext(JSessionSwitch ss) {
00232         TraceEjb.interp.log(BasicLevel.DEBUG, "");
00233         JStatelessContext bctx = null;
00234 
00235         // try to find a free context in the pool
00236         synchronized (bctxlist) {
00237             try {
00238                 ListIterator i = bctxlist.listIterator();
00239                 if (i.hasNext()) {
00240                     bctx = (JStatelessContext) i.next();
00241                     bctx.initSessionContext(ss);
00242                     i.remove();
00243                 }
00244             } catch (IndexOutOfBoundsException ex) {
00245                 // pool is empty
00246             }
00247         }
00248 
00249         if (bctx == null) {
00250             // create a new one if pool empty
00251             try {
00252                 bctx = createNewInstance(ss);
00253             } catch (Exception e) {
00254                 TraceEjb.logger.log(BasicLevel.ERROR, "exception:" + e);
00255                 throw new EJBException("Cannot create a new instance");
00256             }
00257         }
00258         if (TraceEjb.isDebugSwapper()) {
00259             TraceEjb.swapper.log(BasicLevel.DEBUG, "nb instances " + getCacheSize());
00260         }
00261         return bctx;
00262     }
00263 
00268     public void releaseJContext(JContext ctx) {
00269         TraceEjb.interp.log(BasicLevel.DEBUG, "");
00270         JStatelessContext bctx = (JStatelessContext) ctx;
00271 
00272         // if the max number of instances is reached
00273         // we can reduce the number of instances
00274         synchronized (bctxlist) {
00275             if (maxCacheSize != 0 && instanceCount > maxCacheSize) {
00276                 if (TraceEjb.isDebugSwapper()) {
00277                     TraceEjb.swapper.log(BasicLevel.DEBUG, "too much instances :" + instanceCount + ", max="
00278                             + maxCacheSize);
00279                 }
00280                 instanceCount--;
00281             } else {
00282                 bctxlist.add(bctx);
00283             }
00284         }
00285         if (TraceEjb.isDebugSwapper()) {
00286             TraceEjb.swapper.log(BasicLevel.DEBUG, "nb instances " + getCacheSize());
00287         }
00288     }
00289 
00294     public void notifyTimeout(Timer timer) {
00295         TraceTimer.logger.log(BasicLevel.DEBUG, "");
00296 
00297         // Get a JStatelessSwitch (similar to createEJB)
00298         // In fact, we don't need the Local and Remote objects here.
00299         // This object is just needed to initilize the SessionContext.
00300         JSessionSwitch bs = null;
00301         if (sessionList.size() > 0) {
00302             TraceEjb.interp.log(BasicLevel.DEBUG, "get a JStatelessSwitch from the pool");
00303             bs = (JSessionSwitch) sessionList.remove(0);
00304             // must re-export the remote object in the Orb since EJBObjects
00305             // to avoids a fail when object is put in the pool.
00306             JSessionRemote remote = bs.getRemote();
00307             if (remote != null) {
00308                 if (!remote.exportObject()) {
00309                     TraceEjb.logger.log(BasicLevel.ERROR, "bad JSessionSwitch found in pool.");
00310                 }
00311             }
00312         } else {
00313             TraceEjb.interp.log(BasicLevel.DEBUG, "create a new JStatelessSwitch");
00314             try {
00315                 bs = new JStatelessSwitch(this);
00316             } catch (RemoteException e) {
00317                 TraceEjb.logger.log(BasicLevel.ERROR, "Notify Timeout - Unexpected : " + e);
00318                 return;
00319             }
00320         }
00321         //EJBInvocation ejbInv = new EJBInvocation();
00322         //ejbInv.methodPermissionSignature = getEjbTimeoutSignature();
00323         //ejbInv.arguments = new Object [] {timer};
00324 
00325         for (int nbretry = 0; nbretry < MAX_NB_RETRY; nbretry++) {
00326             RequestCtx rctx = preInvoke(getTimerTxAttribute());
00327             JSessionContext bctx = null;
00328             try {
00329                 bctx = bs.getICtx(rctx.currTx);
00330                 TimedObject instance = (TimedObject) bctx.getInstance();
00331                 //ejbInv.bean = (EnterpriseBean) instance;
00332                 checkSecurity(null);
00333                 instance.ejbTimeout(timer);
00334                 if (rctx.currTx == null
00335                         || (rctx.currTx.getStatus() != Status.STATUS_MARKED_ROLLBACK)) {
00336                     break;
00337                 }
00338             } catch (EJBException e) {
00339                 rctx.sysExc = e;
00340                 throw e;
00341             } catch (RuntimeException e) {
00342                 rctx.sysExc = e;
00343                 throw new EJBException("RuntimeException thrown by an enterprise Bean", e);
00344             } catch (Error e) {
00345                 rctx.sysExc = e;
00346                 throw new EJBException("Error thrown by an enterprise Bean" + e);
00347             } catch (RemoteException e) {
00348                 rctx.sysExc = e;
00349                 throw new EJBException("Remote Exception raised:", e);
00350             } catch (SystemException e) {
00351                 rctx.sysExc = e;
00352                 throw new EJBException("Cannot get transaction status:", e);
00353             } finally {
00354                 postInvoke(rctx);
00355             }
00356         }
00357 
00358         // release everything - Exactly as if the session timeout had
00359         // expired.
00360         bs.timeoutExpired(null);
00361     }
00362 
00366     public int getMinPoolSize() {
00367         return minPoolSize;
00368     }
00369 
00373     public int getMaxCacheSize() {
00374         return maxCacheSize;
00375     }
00376 
00380     public int getCacheSize() {
00381         return instanceCount;
00382     }
00383 
00384     // ---------------------------------------------------------------
00385     // private methods
00386     // ---------------------------------------------------------------
00387 
00391     private JStatelessContext createNewInstance(JSessionSwitch ss) throws Exception {
00392         TraceEjb.interp.log(BasicLevel.DEBUG, "");
00393         // create the bean instance
00394         SessionBean bean = null;
00395         try {
00396             bean = (SessionBean) beanclass.newInstance();
00397         } catch (InstantiationException e) {
00398             TraceEjb.logger.log(BasicLevel.ERROR, ejbname + " cannot instantiate session bean");
00399             throw e;
00400         } catch (IllegalAccessException e) {
00401             TraceEjb.logger.log(BasicLevel.ERROR, ejbname + " Cannot instantiate SessionBean");
00402             throw e;
00403         }
00404 
00405         // create a new StatelessContext and bind it to the instance
00406         JStatelessContext bctx = new JStatelessContext(this, bean);
00407         bean.setSessionContext(bctx);
00408         bctx.setState(1);
00409         bctx.initSessionContext(ss);
00410         // call ejbCreate on the instance
00411         TraceEjb.interp.log(BasicLevel.DEBUG, "call ejbCreate on the instance");
00412         try {
00413             beanclass.getMethod("ejbCreate", (Class[]) null).invoke(bean, (Object[]) null);
00414         } catch (Exception e) {
00415             TraceEjb.logger.log(BasicLevel.ERROR, ejbname + " cannot call ejbCreate on Stateless Session " + e);
00416         }
00417         bctx.setState(2);
00418 
00419         // We always create an instance even if the max is reached
00420         // see releaseJContext
00421         synchronized (bctxlist) {
00422             instanceCount++;
00423         }
00424         return bctx;
00425     }
00426 
00427 }

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