diff --git a/ejb3/build-test.xml b/ejb3/build-test.xml index 4275083..3b28066 100644 --- a/ejb3/build-test.xml +++ b/ejb3/build-test.xml @@ -2163,6 +2163,13 @@ + + + + + @@ -3860,6 +3867,7 @@ jbpapp999, jbpapp1186, jbpapp1224, + jbpapp1561, jbas4489, epcpropagation, jaccpropagation, aspectdomain, ejbcontext, schema, mail, scopedclassloader, dependency, jaxws, pkg, securitydomain, enventry, externalpersistenceunit, @@ -4504,6 +4512,9 @@ + + + diff --git a/ejb3/src/main/org/jboss/ejb3/cache/AbstractCache.java b/ejb3/src/main/org/jboss/ejb3/cache/AbstractCache.java new file mode 100644 index 0000000..c778e95 --- /dev/null +++ b/ejb3/src/main/org/jboss/ejb3/cache/AbstractCache.java @@ -0,0 +1,106 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2009, Red Hat Middleware LLC, and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.jboss.ejb3.cache; + +import javax.ejb.EJBException; + +import org.jboss.ejb3.Container; +import org.jboss.ejb3.stateful.StatefulBeanContext; +import org.jboss.ejb3.stateful.StatefulContainer; +import org.jboss.logging.Logger; + +/** + * @author Carlo de Wolf + * @version $Revision: $ + */ +public abstract class AbstractCache implements StatefulCache +{ + private static final Logger log = Logger.getLogger(AbstractCache.class); + + private StatefulObjectFactory factory; + + private int createCount = 0; + + @Deprecated + public final StatefulBeanContext create() + { + return create(null, null); + } + + public StatefulBeanContext create(Class[] initTypes, Object[] initValues) + { + StatefulBeanContext ctx = null; + try + { + ctx = factory.create(initTypes, initValues); + if (log.isTraceEnabled()) + { + log.trace("Caching context " + ctx.getId() + " of type " + ctx.getClass()); + } + putInCache(ctx); + ctx.setInUse(true); + ctx.lastUsed = System.currentTimeMillis(); + ++createCount; + } + catch (EJBException e) + { + throw e; + } + catch (Exception e) + { + throw new EJBException(e); + } + return ctx; + } + + protected final void destroy(StatefulBeanContext ctx) + { + factory.destroy(ctx); + } + + public final StatefulBeanContext get(Object key) throws EJBException + { + return get(key, true); + } + + public int getAvailableCount() + { + return -1; + } + + public int getCreateCount() + { + return createCount; + } + + public final int getCurrentSize() + { + return getCacheSize(); + } + + public void initialize(Container container) throws Exception + { + this.factory = (StatefulContainer) container; + } + + protected abstract void putInCache(StatefulBeanContext ctx); +} diff --git a/ejb3/src/main/org/jboss/ejb3/cache/StatefulObjectFactory.java b/ejb3/src/main/org/jboss/ejb3/cache/StatefulObjectFactory.java new file mode 100644 index 0000000..1c1e280 --- /dev/null +++ b/ejb3/src/main/org/jboss/ejb3/cache/StatefulObjectFactory.java @@ -0,0 +1,54 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2007, Red Hat Middleware LLC, and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.jboss.ejb3.cache; + +/** + * Creates and destroys stateful objects. + * + * The object returned by create has dependencies injected. The PostConstruct + * callback, if defined, has been called and the Init callback, if defined, + * has been called. + * + * @author Carlo de Wolf + * @version $Revision: $ + */ +public interface StatefulObjectFactory +{ + /** + * Creates a new stateful object by calling it's empty constructor, + * do injection, calling post-construct and finally calling the + * appropriate init method. + * + * @param initTypes the argument types for the init method + * @param initValues the arguments for the init method + * @return + */ + T create(Class initTypes[], Object initValues[]); + + /** + * Perform any cleanup actions on the object, such as + * calling the pre-destroy callback. + * + * @param obj the object + */ + void destroy(T obj); +} diff --git a/ejb3/src/main/org/jboss/ejb3/cache/simple/SimpleStatefulCache.java b/ejb3/src/main/org/jboss/ejb3/cache/simple/SimpleStatefulCache.java index 9e06f50..2d5cca5 100644 --- a/ejb3/src/main/org/jboss/ejb3/cache/simple/SimpleStatefulCache.java +++ b/ejb3/src/main/org/jboss/ejb3/cache/simple/SimpleStatefulCache.java @@ -23,20 +23,19 @@ package org.jboss.ejb3.cache.simple; import java.util.Iterator; import java.util.LinkedHashMap; -import java.util.LinkedList; import java.util.List; import java.util.Map; + import javax.ejb.EJBException; import javax.ejb.NoSuchEJBException; + import org.jboss.annotation.ejb.cache.simple.CacheConfig; import org.jboss.annotation.ejb.cache.simple.PersistenceManager; import org.jboss.aop.Advisor; import org.jboss.ejb3.Container; import org.jboss.ejb3.EJBContainer; -import org.jboss.ejb3.Pool; -import org.jboss.ejb3.cache.StatefulCache; +import org.jboss.ejb3.cache.AbstractCache; import org.jboss.ejb3.stateful.StatefulBeanContext; -import org.jboss.util.id.GUID; import org.jboss.logging.Logger; /** @@ -45,11 +44,10 @@ import org.jboss.logging.Logger; * @author Bill Burke * @version $Revision: 62768 $ */ -public class SimpleStatefulCache implements StatefulCache +public class SimpleStatefulCache extends AbstractCache { private Logger log = Logger.getLogger(SimpleStatefulCache.class); - private Pool pool; private CacheMap cacheMap; private int maxSize = 1000; private StatefulSessionPersistenceManager pm; @@ -240,8 +238,8 @@ public class SimpleStatefulCache implements StatefulCache public void initialize(Container container) throws Exception { + super.initialize(container); Advisor advisor = (Advisor) container; - this.pool = container.getPool(); cacheMap = new CacheMap(); PersistenceManager pmConfig = (PersistenceManager) advisor.resolveAnnotation(PersistenceManager.class); this.pm = (StatefulSessionPersistenceManager) pmConfig.value().newInstance(); @@ -307,74 +305,6 @@ public class SimpleStatefulCache implements StatefulCache } } - public StatefulBeanContext create() - { - StatefulBeanContext ctx = null; - try - { - ctx = (StatefulBeanContext) pool.get(); - - if (log.isTraceEnabled()) - { - log.trace("Caching context " + ctx.getId() + " of type " + ctx.getClass()); - } - synchronized (cacheMap) - { - cacheMap.put(ctx.getId(), ctx); - } - ctx.setInUse(true); - ctx.lastUsed = System.currentTimeMillis(); - ++createCount; - } - catch (EJBException e) - { - e.printStackTrace(); - throw e; - } - catch (Exception e) - { - e.printStackTrace(); - throw new EJBException(e); - } - return ctx; - } - - public StatefulBeanContext create(Class[] initTypes, Object[] initValues) - { - StatefulBeanContext ctx = null; - try - { - ctx = (StatefulBeanContext) pool.get(initTypes, initValues); - if (log.isTraceEnabled()) - { - log.trace("Caching context " + ctx.getId() + " of type " + ctx.getClass()); - } - synchronized (cacheMap) - { - cacheMap.put(ctx.getId(), ctx); - } - ctx.setInUse(true); - ctx.lastUsed = System.currentTimeMillis(); - ++createCount; - } - catch (EJBException e) - { - e.printStackTrace(); - throw e; - } - catch (Exception e) - { - e.printStackTrace(); - throw new EJBException(e); - } - return ctx; - } - - public StatefulBeanContext get(Object key) throws EJBException - { - return get(key, true); - } - public StatefulBeanContext get(Object key, boolean markInUse) throws EJBException { StatefulBeanContext entry = null; @@ -433,6 +363,15 @@ public class SimpleStatefulCache implements StatefulCache } } + @Override + protected void putInCache(StatefulBeanContext ctx) + { + synchronized (cacheMap) + { + cacheMap.put(ctx.getId(), ctx); + } + } + public void remove(Object key) { StatefulBeanContext ctx = null; @@ -443,7 +382,7 @@ public class SimpleStatefulCache implements StatefulCache if (ctx != null) { if (!ctx.isRemoved()) - pool.remove(ctx); + destroy(ctx); ++removeCount; @@ -491,9 +430,4 @@ public class SimpleStatefulCache implements StatefulCache { return maxSize; } - - public int getCurrentSize() - { - return cacheMap.size(); - } } diff --git a/ejb3/src/main/org/jboss/ejb3/cache/tree/StatefulTreeCache.java b/ejb3/src/main/org/jboss/ejb3/cache/tree/StatefulTreeCache.java index 562cca6..7d5ce6f 100644 --- a/ejb3/src/main/org/jboss/ejb3/cache/tree/StatefulTreeCache.java +++ b/ejb3/src/main/org/jboss/ejb3/cache/tree/StatefulTreeCache.java @@ -22,44 +22,43 @@ package org.jboss.ejb3.cache.tree; import java.lang.ref.WeakReference; -import java.util.concurrent.ConcurrentHashMap; import java.util.Iterator; import java.util.Map; - import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import javax.ejb.EJBException; import javax.ejb.NoSuchEJBException; import javax.management.MBeanServer; import javax.management.ObjectName; -import org.jboss.cache.xml.XmlHelper; -import org.jboss.cache.eviction.RegionManager; -import org.jboss.cache.eviction.Region; -import org.jboss.cache.marshall.RegionNotFoundException; -import org.jboss.cache.CacheException; +import org.jboss.annotation.ejb.cache.tree.CacheConfig; import org.jboss.cache.AbstractTreeCacheListener; +import org.jboss.cache.CacheException; import org.jboss.cache.DataNode; +import org.jboss.cache.Fqn; import org.jboss.cache.RegionNotEmptyException; import org.jboss.cache.TreeCache; import org.jboss.cache.TreeCacheMBean; +import org.jboss.cache.config.Option; +import org.jboss.cache.eviction.Region; +import org.jboss.cache.eviction.RegionManager; +import org.jboss.cache.marshall.RegionNotFoundException; +import org.jboss.cache.xml.XmlHelper; import org.jboss.ejb3.Container; import org.jboss.ejb3.EJBContainer; import org.jboss.ejb3.Pool; +import org.jboss.ejb3.cache.AbstractCache; import org.jboss.ejb3.cache.ClusteredStatefulCache; import org.jboss.ejb3.stateful.NestedStatefulBeanContext; import org.jboss.ejb3.stateful.ProxiedStatefulBeanContext; import org.jboss.ejb3.stateful.StatefulBeanContext; +import org.jboss.logging.Logger; import org.jboss.mx.util.MBeanProxyExt; import org.jboss.mx.util.MBeanServerLocator; import org.jboss.util.id.GUID; -import org.jboss.logging.Logger; -import org.jboss.annotation.ejb.cache.tree.CacheConfig; import org.w3c.dom.Element; -import org.jboss.cache.Fqn; -import org.jboss.cache.config.Option; - /** * Clustered SFSB cache that uses JBoss Cache to cache and replicate * bean contexts. @@ -69,7 +68,8 @@ import org.jboss.cache.config.Option; * * @version $Revision: 69056 $ */ -public class StatefulTreeCache implements ClusteredStatefulCache +public class StatefulTreeCache extends AbstractCache + implements ClusteredStatefulCache { private static final int FQN_SIZE = 3; // depth of fqn that we store the session in. private static final int DEFAULT_BUCKET_COUNT = 100; @@ -108,65 +108,13 @@ public class StatefulTreeCache implements ClusteredStatefulCache protected Map beans = new ConcurrentHashMap(); protected EJBContainer ejbContainer; - public StatefulBeanContext create() - { - StatefulBeanContext ctx = null; - try - { - ctx = (StatefulBeanContext) pool.get(); - if (log.isTraceEnabled()) - { - log.trace("Caching context " + ctx.getId() + " of type " + ctx.getClass()); - } - putInCache(ctx); - ctx.setInUse(true); - ctx.lastUsed = System.currentTimeMillis(); - ++createCount; - beans.put(ctx.getId(), ctx.lastUsed); - } - catch (EJBException e) - { - throw e; - } - catch (Exception e) - { - throw new EJBException(e); - } - return ctx; - } - public StatefulBeanContext create(Class[] initTypes, Object[] initValues) { - StatefulBeanContext ctx = null; - try - { - ctx = (StatefulBeanContext) pool.get(initTypes, initValues); - if (log.isTraceEnabled()) - { - log.trace("Caching context " + ctx.getId() + " of type " + ctx.getClass()); - } - putInCache(ctx); - ctx.setInUse(true); - ctx.lastUsed = System.currentTimeMillis(); - ++createCount; - beans.put(ctx.getId(), ctx.lastUsed); - } - catch (EJBException e) - { - throw e; - } - catch (Exception e) - { - throw new EJBException(e); - } + StatefulBeanContext ctx = super.create(initTypes, initValues); + beans.put(ctx.getId(), ctx.lastUsed); return ctx; } - public StatefulBeanContext get(Object key) throws EJBException - { - return get(key, true); - } - public StatefulBeanContext get(Object key, boolean markInUse) throws EJBException { StatefulBeanContext entry = null; @@ -284,15 +232,7 @@ public class StatefulTreeCache implements ClusteredStatefulCache throw new IllegalArgumentException("Received unexpected replicate call for nested context " + ctx.getId()); } - try - { - putInCache(ctx); - } - catch (CacheException e) - { - RuntimeException re = convertToRuntimeException(e); - throw re; - } + putInCache(ctx); } public void initialize(Container container) throws Exception @@ -453,12 +393,7 @@ public class StatefulTreeCache implements ClusteredStatefulCache return -1; } - public int getCurrentSize() - { - return getCacheSize(); - } - - private void putInCache(StatefulBeanContext ctx) throws CacheException + protected void putInCache(StatefulBeanContext ctx) { Boolean active = localActivity.get(); try @@ -468,6 +403,11 @@ public class StatefulTreeCache implements ClusteredStatefulCache cache.put(getFqn(ctx.getId()), "bean", ctx); ctx.markedForReplication = false; } + catch(CacheException e) + { + RuntimeException re = convertToRuntimeException(e); + throw re; + } finally { localActivity.set(active); diff --git a/ejb3/src/main/org/jboss/ejb3/stateful/StatefulContainer.java b/ejb3/src/main/org/jboss/ejb3/stateful/StatefulContainer.java index f9a454c..04468cd 100644 --- a/ejb3/src/main/org/jboss/ejb3/stateful/StatefulContainer.java +++ b/ejb3/src/main/org/jboss/ejb3/stateful/StatefulContainer.java @@ -49,6 +49,7 @@ import org.jboss.aop.joinpoint.Invocation; import org.jboss.aop.joinpoint.InvocationResponse; import org.jboss.aop.util.MethodHashing; import org.jboss.aspects.asynch.FutureHolder; +import org.jboss.ejb3.AbstractPool; import org.jboss.ejb3.BeanContext; import org.jboss.ejb3.EJBContainerInvocation; import org.jboss.ejb3.Ejb3Deployment; @@ -57,6 +58,7 @@ import org.jboss.ejb3.ProxyFactoryHelper; import org.jboss.ejb3.ProxyUtils; import org.jboss.ejb3.SessionContainer; import org.jboss.ejb3.cache.StatefulCache; +import org.jboss.ejb3.cache.StatefulObjectFactory; import org.jboss.ejb3.interceptor.InterceptorInfoRepository; import org.jboss.ejb3.proxy.EJBMetaDataImpl; import org.jboss.ejb3.proxy.handle.HomeHandleImpl; @@ -72,10 +74,69 @@ import org.jboss.logging.Logger; * @version $Revision: 74347 $ */ public class StatefulContainer extends SessionContainer + implements StatefulObjectFactory { private static final Logger log = Logger.getLogger(StatefulContainer.class); protected StatefulCache cache; + + /** + * Allow for delegation from a StatefulObjectFactory to the legacy + * AbstractPool.create and AbstractPool.remove methods. + */ + protected class DummyPool extends AbstractPool + { + protected DummyPool() + { + initialize(StatefulContainer.this, beanContextClass, beanClass, -1, -1L); + } + + // expose the method + @Override + protected BeanContext create(Class[] initTypes, Object[] initValues) + { + return super.create(initTypes, initValues); + } + + public void destroy() + { + } + + public BeanContext get() + { + return null; + } + + public BeanContext get(Class[] initTypes, Object[] initValues) + { + return null; + } + + public int getAvailableCount() + { + return 0; + } + + public int getCurrentSize() + { + return 0; + } + + public int getMaxSize() + { + return 0; + } + + public void release(BeanContext obj) + { + + } + + public void setMaxSize(int maxSize) + { + } + } + protected DummyPool dummyPool; public StatefulContainer(ClassLoader cl, String beanClassName, String ejbName, AspectManager manager, Hashtable ctxProperties, InterceptorInfoRepository interceptorRepository, @@ -83,6 +144,7 @@ public class StatefulContainer extends SessionContainer { super(cl, beanClassName, ejbName, manager, ctxProperties, interceptorRepository, deployment); beanContextClass = StatefulBeanContext.class; + dummyPool = new DummyPool(); } public void start() throws Exception @@ -110,6 +172,16 @@ public class StatefulContainer extends SessionContainer } + public StatefulBeanContext create(Class[] initTypes, Object[] initValues) + { + return (StatefulBeanContext) dummyPool.create(initTypes, initValues); + } + + public void destroy(StatefulBeanContext ctx) + { + dummyPool.remove(ctx); + } + public void stop() throws Exception { if (cache != null) cache.stop(); diff --git a/ejb3/src/test/org/jboss/ejb3/test/jbpapp1561/SimpleStateful.java b/ejb3/src/test/org/jboss/ejb3/test/jbpapp1561/SimpleStateful.java new file mode 100644 index 0000000..b985834 --- /dev/null +++ b/ejb3/src/test/org/jboss/ejb3/test/jbpapp1561/SimpleStateful.java @@ -0,0 +1,35 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2009, Red Hat Middleware LLC, and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.jboss.ejb3.test.jbpapp1561; + +/** + * @author Carlo de Wolf + * @version $Revision: $ + */ +public interface SimpleStateful +{ + String getState(); + + void remove(); + + void setState(String state); +} diff --git a/ejb3/src/test/org/jboss/ejb3/test/jbpapp1561/SimpleStatefulBean.java b/ejb3/src/test/org/jboss/ejb3/test/jbpapp1561/SimpleStatefulBean.java new file mode 100644 index 0000000..3876f9c --- /dev/null +++ b/ejb3/src/test/org/jboss/ejb3/test/jbpapp1561/SimpleStatefulBean.java @@ -0,0 +1,100 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2009, Red Hat Middleware LLC, and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.jboss.ejb3.test.jbpapp1561; + +import java.io.Serializable; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; +import javax.ejb.PostActivate; +import javax.ejb.PrePassivate; +import javax.ejb.Remote; +import javax.ejb.Remove; +import javax.ejb.Stateful; + +import org.jboss.annotation.ejb.cache.simple.CacheConfig; +import org.jboss.logging.Logger; + +/** + * @author Carlo de Wolf + * @version $Revision: $ + */ +@Stateful +@CacheConfig(idleTimeoutSeconds=1) +@Remote(SimpleStateful.class) +public class SimpleStatefulBean implements Serializable, SimpleStateful +{ + private static final Logger log = Logger.getLogger(SimpleStatefulBean.class); + private static final long serialVersionUID = 1L; + + protected static int finalized = 0; + + private String state; + + @Override + protected void finalize() throws Throwable + { + super.finalize(); + + finalized++; + } + + public String getState() + { + return state; + } + + @PostActivate + protected void postActivate() + { + log.info("postActivate"); + } + + @PostConstruct + protected void postConstruct() + { + log.info("postConstruct"); + } + + @PreDestroy + protected void preDestroy() + { + log.info("preDestroy"); + } + + @PrePassivate + protected void prePassivate() + { + log.info("prePassivate"); + TesterBean.semaphore.release(); + } + + @Remove + public void remove() + { + } + + public void setState(String state) + { + this.state = state; + } +} diff --git a/ejb3/src/test/org/jboss/ejb3/test/jbpapp1561/Tester.java b/ejb3/src/test/org/jboss/ejb3/test/jbpapp1561/Tester.java new file mode 100644 index 0000000..e1c0a02 --- /dev/null +++ b/ejb3/src/test/org/jboss/ejb3/test/jbpapp1561/Tester.java @@ -0,0 +1,35 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2009, Red Hat Middleware LLC, and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.jboss.ejb3.test.jbpapp1561; + +/** + * @author Carlo de Wolf + * @version $Revision: $ + */ +public interface Tester +{ + int getFinalized(); + + void runGC(); + + void waitForPrePassivate(); +} diff --git a/ejb3/src/test/org/jboss/ejb3/test/jbpapp1561/TesterBean.java b/ejb3/src/test/org/jboss/ejb3/test/jbpapp1561/TesterBean.java new file mode 100644 index 0000000..2543423 --- /dev/null +++ b/ejb3/src/test/org/jboss/ejb3/test/jbpapp1561/TesterBean.java @@ -0,0 +1,76 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2009, Red Hat Middleware LLC, and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.jboss.ejb3.test.jbpapp1561; + +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; + +import javax.ejb.Remote; +import javax.ejb.Stateless; + +/** + * @author Carlo de Wolf + * @version $Revision: $ + */ +@Stateless +@Remote(Tester.class) +public class TesterBean implements Tester +{ + protected static Semaphore semaphore = new Semaphore(0); + + public int getFinalized() + { + return SimpleStatefulBean.finalized; + } + + public void runGC() + { + for(int i = 0; i < 3; i++) + { + System.gc(); + try + { + Thread.sleep(100); + } + catch (InterruptedException e) + { + // ignore + } + System.runFinalization(); + } + } + + public void waitForPrePassivate() + { + boolean success = false; + try + { + success = semaphore.tryAcquire(5, TimeUnit.SECONDS); + } + catch(InterruptedException e) + { + // ignore + } + if(!success) + throw new RuntimeException("failed to acquire semaphore"); + } +} diff --git a/ejb3/src/test/org/jboss/ejb3/test/jbpapp1561/unit/PassivationMemLeakUnitTestCase.java b/ejb3/src/test/org/jboss/ejb3/test/jbpapp1561/unit/PassivationMemLeakUnitTestCase.java new file mode 100644 index 0000000..ef52791 --- /dev/null +++ b/ejb3/src/test/org/jboss/ejb3/test/jbpapp1561/unit/PassivationMemLeakUnitTestCase.java @@ -0,0 +1,93 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2009, Red Hat Middleware LLC, and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.jboss.ejb3.test.jbpapp1561.unit; + +import junit.framework.Test; + +import org.jboss.ejb3.test.jbpapp1561.SimpleStateful; +import org.jboss.ejb3.test.jbpapp1561.Tester; +import org.jboss.test.JBossTestCase; + +/** + * @author Carlo de Wolf + * @version $Revision: $ + */ +public class PassivationMemLeakUnitTestCase extends JBossTestCase +{ + private Tester tester; + private int finalizedStart; + + public PassivationMemLeakUnitTestCase(String name) + { + super(name); + } + + @Override + protected void setUp() throws Exception + { + super.setUp(); + + tester = (Tester) getInitialContext().lookup("TesterBean/remote"); + tester.runGC(); + finalizedStart = tester.getFinalized(); + } + + public void testPassivation() throws Exception + { + SimpleStateful bean = (SimpleStateful) getInitialContext().lookup("SimpleStatefulBean/remote"); + bean.setState("Hello world"); + tester.waitForPrePassivate(); + // wait for bean reference removal + Thread.sleep(1000); + + // hack to clear java:comp/env/EJBContext + ((SimpleStateful) getInitialContext().lookup("SimpleStatefulBean/remote")).setState("hack"); + + tester.runGC(); + int finalized = tester.getFinalized() - finalizedStart; + assertEquals(1, finalized); + + String actual = bean.getState(); + assertEquals("Hello world", actual); + bean.remove(); + } + + public void testRemove() throws Exception + { + SimpleStateful bean = (SimpleStateful) getInitialContext().lookup("SimpleStatefulBean/remote"); + bean.setState("Hello world"); + String actual = bean.getState(); + assertEquals("Hello world", actual); + bean.remove(); + + tester.runGC(); + int finalized = tester.getFinalized() - finalizedStart; + //assertEquals(1, finalized); + // this bean plus the hack + assertEquals(2, finalized); + } + + public static Test suite() throws Exception + { + return getDeploySetup(PassivationMemLeakUnitTestCase.class, "jbpapp1561.jar"); + } +}