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
00064 protected JServiceEndpointHome sehome = null;
00065
00066 protected int instanceCount = 0;
00067
00068
00069 protected int minPoolSize = 0;
00070
00071
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
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
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
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
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();
00143 synchronized (bctxlist) {
00144 for (int i = 0; i < minPoolSize; i++) {
00145 JSessionContext ctx = null;
00146 try {
00147
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
00166
00167
00171 public int getPoolSize() {
00172 return bctxlist.size();
00173 }
00174
00179 public void reduceCache() {
00180 TraceEjb.swapper.log(BasicLevel.DEBUG, "");
00181
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
00204
00205
00210 public TimerService getTimerService() {
00211 if (myTimerService == null) {
00212
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
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
00246 }
00247 }
00248
00249 if (bctx == null) {
00250
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
00273
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
00298
00299
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
00305
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
00322
00323
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
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
00359
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
00386
00387
00391 private JStatelessContext createNewInstance(JSessionSwitch ss) throws Exception {
00392 TraceEjb.interp.log(BasicLevel.DEBUG, "");
00393
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
00406 JStatelessContext bctx = new JStatelessContext(this, bean);
00407 bean.setSessionContext(bctx);
00408 bctx.setState(1);
00409 bctx.initSessionContext(ss);
00410
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
00420
00421 synchronized (bctxlist) {
00422 instanceCount++;
00423 }
00424 return bctx;
00425 }
00426
00427 }