You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tomee.apache.org by db...@apache.org on 2010/03/18 19:09:27 UTC

svn commit: r924925 [1/2] - in /openejb/trunk/openejb3: assembly/openejb-jetty/openejb-jetty-webapp/src/main/resources/META-INF/org.apache.openejb.jetty/ assembly/openejb-tomcat/openejb-tomcat-webapp/src/main/resources/META-INF/org.apache.openejb.tomca...

Author: dblevins
Date: Thu Mar 18 18:09:27 2010
New Revision: 924925

URL: http://svn.apache.org/viewvc?rev=924925&view=rev
Log:
More options for OPENEJB-1235
New "Flush" ability.  Fixes to MaxAge and IdleTimeout.  Many more tests.  Weaved configuration through the system.

Added:
    openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessContainerFactory.java   (with props)
    openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/util/PassthroughFactory.java   (with props)
    openejb/trunk/openejb3/container/openejb-junit/src/main/java/org/apache/openejb/junit/LocalClientRunner.java   (with props)
    openejb/trunk/openejb3/container/openejb-junit/src/main/java/org/apache/openejb/junit/Transaction.java   (with props)
Modified:
    openejb/trunk/openejb3/assembly/openejb-jetty/openejb-jetty-webapp/src/main/resources/META-INF/org.apache.openejb.jetty/service-jar.xml
    openejb/trunk/openejb3/assembly/openejb-tomcat/openejb-tomcat-webapp/src/main/resources/META-INF/org.apache.openejb.tomcat/service-jar.xml
    openejb/trunk/openejb3/assembly/openejb-webapp/src/main/resources/META-INF/org.apache.openejb.tomcat/service-jar.xml
    openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/InjectionProcessor.java
    openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessContainer.java
    openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessInstanceManager.java
    openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/transaction/TransactionType.java
    openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/util/Pool.java
    openejb/trunk/openejb3/container/openejb-core/src/main/resources/META-INF/org.apache.openejb.embedded/service-jar.xml
    openejb/trunk/openejb3/container/openejb-core/src/main/resources/META-INF/org.apache.openejb/service-jar.xml
    openejb/trunk/openejb3/container/openejb-core/src/main/resources/default.openejb.conf
    openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/config/ConfigureServiceTest.java
    openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/util/PoolTest.java
    openejb/trunk/openejb3/container/openejb-osgi/src/main/resources/META-INF/org.apache.openejb/service-jar.xml

Modified: openejb/trunk/openejb3/assembly/openejb-jetty/openejb-jetty-webapp/src/main/resources/META-INF/org.apache.openejb.jetty/service-jar.xml
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/assembly/openejb-jetty/openejb-jetty-webapp/src/main/resources/META-INF/org.apache.openejb.jetty/service-jar.xml?rev=924925&r1=924924&r2=924925&view=diff
==============================================================================
--- openejb/trunk/openejb3/assembly/openejb-jetty/openejb-jetty-webapp/src/main/resources/META-INF/org.apache.openejb.jetty/service-jar.xml (original)
+++ openejb/trunk/openejb3/assembly/openejb-jetty/openejb-jetty-webapp/src/main/resources/META-INF/org.apache.openejb.jetty/service-jar.xml Thu Mar 18 18:09:27 2010
@@ -87,17 +87,20 @@
           id="Default Stateless Container"
           service="Container"
           types="STATELESS"
-          constructor="id, securityService, TimeOut, PoolMin, PoolSize, StrictPooling"
-          class-name="org.apache.openejb.core.stateless.StatelessContainer">
+          factory-name="create"
+          class-name="org.apache.openejb.core.stateless.StatelessContainerFactory">
 
     # Specifies the time an invokation should wait for an instance
-    # of the pool to become available. This measured by default in
-    # milliseconds, but other time units can be specified, such as
-    # nanoseconds, microsecons, seconds or minutes.  After the timeout
-    # is reached, if an instance in the pool cannot be obtained, the
-    # method invocation will fail.
+    # of the pool to become available.
+    #
+    # After the timeout is reached, if an instance in the pool cannot
+    # be obtained, the method invocation will fail.
+    #
+    # Usable time units: nanoseconds, microsecons, milliseconds,
+    # seconds, minutes, hours, days.  Or any combination such as
+    # "1 hour and 27 minutes and 10 seconds"
 
-    TimeOut = 0 milliseconds
+    AccessTimeout = 0 milliseconds
 
     # Specifies the minimum number of bean instances that should be
     # in the pool for each bean.  Pools are prefilled to the minimum
@@ -107,28 +110,72 @@
 
     PoolMin 0
 
-    # Specifies the size of the bean pools for this
-    # stateless SessionBean container.  If StrictPooling is not
-    # used, instances will still be created beyond this number if
-    # there is demand, but they will not be returned to the pool
-    # and instead will be immediately destroyed.
+    # Specifies the size of the bean pools for this stateless
+    # SessionBean container.  If StrictPooling is not used, instances
+    # will still be created beyond this number if there is demand, but
+    # they will not be returned to the pool and instead will be
+    # immediately destroyed.
 
     PoolSize 10
 
     # StrictPooling tells the container what to do when the pool
-    # reaches it's maximum size and there are incoming requests
-    # that need instances.
+    # reaches it's maximum size and there are incoming requests that
+    # need instances.
     #
-    # With strict pooling, requests will have to wait for instances
-    # to become available. The pool size will never grow beyond the
-    # the set PoolSize value.
+    # With strict pooling, requests will have to wait for instances to
+    # become available. The pool size will never grow beyond the the
+    # set PoolSize value.  The maximum amount of time a request should
+    # wait is specified via the AccessTimeout setting.
     #
     # Without strict pooling, the container will create temporary
     # instances to meet demand. The instances will last for just one
     # method invocation and then are removed.
+    #
+    # Setting StrictPooling to false and PoolSize to 0 will result in
+    # no pooling. Instead instances will be created on demand and live
+    # for exactly one method call before being removed.
 
     StrictPooling true
 
+    # Specifies the maximum time that an instance should live before
+    # it should be retired and removed from use.  This will happen
+    # gracefully.  Useful for situations where bean instances are
+    # designed to hold potentially expensive resources such as memory
+    # or file handles and need to be periodically cleared out.
+    #
+    # Usable time units: nanoseconds, microsecons, milliseconds,
+    # seconds, minutes, hours, days.  Or any combination such as
+    # "1 hour and 27 minutes and 10 seconds"
+
+    MaxAge = 0 hours
+
+    # Specifies the maximum time that an instance should be allowed to
+    # sit idly in the pool without use before it should be retired and
+    # removed.
+    #
+    # Note that all instances in the pool, excluding the minimum, are
+    # eligible for garbage collection by the virtual machine as per
+    # the rules of java.lang.ref.WeakReference, so the use of an
+    # IdleTimeout is not required to conserve JVM-managed memory or
+    # shrink the pool.
+    #
+    # Usable time units: nanoseconds, microsecons, milliseconds,
+    # seconds, minutes, hours, days.  Or any combination such as
+    # "1 hour and 27 minutes and 10 seconds"
+
+    IdleTimeout = 0 minutes
+
+    # The frequency in which the container will sweep the pool and
+    # evict expired instances.  Eviction is how the IdleTimeout,
+    # MaxAge, and pool "flush" functionality is enforced.  Higher
+    # intervals are better.  Expired instances in use while the pool
+    # is swept will still be evicted upon return to the pool.
+    #
+    # Usable time units: nanoseconds, microsecons, milliseconds,
+    # seconds, minutes, hours, days.  Or any combination such as
+    # "1 hour and 27 minutes and 10 seconds"
+
+    PollInterval = 5 minutes
 
   </ServiceProvider>
 

Modified: openejb/trunk/openejb3/assembly/openejb-tomcat/openejb-tomcat-webapp/src/main/resources/META-INF/org.apache.openejb.tomcat/service-jar.xml
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/assembly/openejb-tomcat/openejb-tomcat-webapp/src/main/resources/META-INF/org.apache.openejb.tomcat/service-jar.xml?rev=924925&r1=924924&r2=924925&view=diff
==============================================================================
--- openejb/trunk/openejb3/assembly/openejb-tomcat/openejb-tomcat-webapp/src/main/resources/META-INF/org.apache.openejb.tomcat/service-jar.xml (original)
+++ openejb/trunk/openejb3/assembly/openejb-tomcat/openejb-tomcat-webapp/src/main/resources/META-INF/org.apache.openejb.tomcat/service-jar.xml Thu Mar 18 18:09:27 2010
@@ -87,17 +87,20 @@
           id="Default Stateless Container"
           service="Container"
           types="STATELESS"
-          constructor="id, securityService, TimeOut, PoolMin, PoolSize, StrictPooling"
-          class-name="org.apache.openejb.core.stateless.StatelessContainer">
+          factory-name="create"
+          class-name="org.apache.openejb.core.stateless.StatelessContainerFactory">
 
     # Specifies the time an invokation should wait for an instance
-    # of the pool to become available. This measured by default in
-    # milliseconds, but other time units can be specified, such as
-    # nanoseconds, microsecons, seconds or minutes.  After the timeout
-    # is reached, if an instance in the pool cannot be obtained, the
-    # method invocation will fail.
+    # of the pool to become available.
+    #
+    # After the timeout is reached, if an instance in the pool cannot
+    # be obtained, the method invocation will fail.
+    #
+    # Usable time units: nanoseconds, microsecons, milliseconds,
+    # seconds, minutes, hours, days.  Or any combination such as
+    # "1 hour and 27 minutes and 10 seconds"
 
-    TimeOut = 0 milliseconds
+    AccessTimeout = 0 milliseconds
 
     # Specifies the minimum number of bean instances that should be
     # in the pool for each bean.  Pools are prefilled to the minimum
@@ -107,28 +110,72 @@
 
     PoolMin 0
 
-    # Specifies the size of the bean pools for this
-    # stateless SessionBean container.  If StrictPooling is not
-    # used, instances will still be created beyond this number if
-    # there is demand, but they will not be returned to the pool
-    # and instead will be immediately destroyed.
+    # Specifies the size of the bean pools for this stateless
+    # SessionBean container.  If StrictPooling is not used, instances
+    # will still be created beyond this number if there is demand, but
+    # they will not be returned to the pool and instead will be
+    # immediately destroyed.
 
     PoolSize 10
 
     # StrictPooling tells the container what to do when the pool
-    # reaches it's maximum size and there are incoming requests
-    # that need instances.
+    # reaches it's maximum size and there are incoming requests that
+    # need instances.
     #
-    # With strict pooling, requests will have to wait for instances
-    # to become available. The pool size will never grow beyond the
-    # the set PoolSize value.
+    # With strict pooling, requests will have to wait for instances to
+    # become available. The pool size will never grow beyond the the
+    # set PoolSize value.  The maximum amount of time a request should
+    # wait is specified via the AccessTimeout setting.
     #
     # Without strict pooling, the container will create temporary
     # instances to meet demand. The instances will last for just one
     # method invocation and then are removed.
+    #
+    # Setting StrictPooling to false and PoolSize to 0 will result in
+    # no pooling. Instead instances will be created on demand and live
+    # for exactly one method call before being removed.
 
     StrictPooling true
 
+    # Specifies the maximum time that an instance should live before
+    # it should be retired and removed from use.  This will happen
+    # gracefully.  Useful for situations where bean instances are
+    # designed to hold potentially expensive resources such as memory
+    # or file handles and need to be periodically cleared out.
+    #
+    # Usable time units: nanoseconds, microsecons, milliseconds,
+    # seconds, minutes, hours, days.  Or any combination such as
+    # "1 hour and 27 minutes and 10 seconds"
+
+    MaxAge = 0 hours
+
+    # Specifies the maximum time that an instance should be allowed to
+    # sit idly in the pool without use before it should be retired and
+    # removed.
+    #
+    # Note that all instances in the pool, excluding the minimum, are
+    # eligible for garbage collection by the virtual machine as per
+    # the rules of java.lang.ref.WeakReference, so the use of an
+    # IdleTimeout is not required to conserve JVM-managed memory or
+    # shrink the pool.
+    #
+    # Usable time units: nanoseconds, microsecons, milliseconds,
+    # seconds, minutes, hours, days.  Or any combination such as
+    # "1 hour and 27 minutes and 10 seconds"
+
+    IdleTimeout = 0 minutes
+
+    # The frequency in which the container will sweep the pool and
+    # evict expired instances.  Eviction is how the IdleTimeout,
+    # MaxAge, and pool "flush" functionality is enforced.  Higher
+    # intervals are better.  Expired instances in use while the pool
+    # is swept will still be evicted upon return to the pool.
+    #
+    # Usable time units: nanoseconds, microsecons, milliseconds,
+    # seconds, minutes, hours, days.  Or any combination such as
+    # "1 hour and 27 minutes and 10 seconds"
+
+    PollInterval = 5 minutes
 
   </ServiceProvider>
 

Modified: openejb/trunk/openejb3/assembly/openejb-webapp/src/main/resources/META-INF/org.apache.openejb.tomcat/service-jar.xml
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/assembly/openejb-webapp/src/main/resources/META-INF/org.apache.openejb.tomcat/service-jar.xml?rev=924925&r1=924924&r2=924925&view=diff
==============================================================================
--- openejb/trunk/openejb3/assembly/openejb-webapp/src/main/resources/META-INF/org.apache.openejb.tomcat/service-jar.xml (original)
+++ openejb/trunk/openejb3/assembly/openejb-webapp/src/main/resources/META-INF/org.apache.openejb.tomcat/service-jar.xml Thu Mar 18 18:09:27 2010
@@ -87,17 +87,20 @@
           id="Default Stateless Container"
           service="Container"
           types="STATELESS"
-          constructor="id, securityService, TimeOut, PoolMin, PoolSize, StrictPooling"
-          class-name="org.apache.openejb.core.stateless.StatelessContainer">
+          factory-name="create"
+          class-name="org.apache.openejb.core.stateless.StatelessContainerFactory">
 
     # Specifies the time an invokation should wait for an instance
-    # of the pool to become available. This measured by default in
-    # milliseconds, but other time units can be specified, such as
-    # nanoseconds, microsecons, seconds or minutes.  After the timeout
-    # is reached, if an instance in the pool cannot be obtained, the
-    # method invocation will fail.
+    # of the pool to become available.
+    #
+    # After the timeout is reached, if an instance in the pool cannot
+    # be obtained, the method invocation will fail.
+    #
+    # Usable time units: nanoseconds, microsecons, milliseconds,
+    # seconds, minutes, hours, days.  Or any combination such as
+    # "1 hour and 27 minutes and 10 seconds"
 
-    TimeOut = 0 milliseconds
+    AccessTimeout = 0 milliseconds
 
     # Specifies the minimum number of bean instances that should be
     # in the pool for each bean.  Pools are prefilled to the minimum
@@ -107,28 +110,72 @@
 
     PoolMin 0
 
-    # Specifies the size of the bean pools for this
-    # stateless SessionBean container.  If StrictPooling is not
-    # used, instances will still be created beyond this number if
-    # there is demand, but they will not be returned to the pool
-    # and instead will be immediately destroyed.
+    # Specifies the size of the bean pools for this stateless
+    # SessionBean container.  If StrictPooling is not used, instances
+    # will still be created beyond this number if there is demand, but
+    # they will not be returned to the pool and instead will be
+    # immediately destroyed.
 
     PoolSize 10
 
     # StrictPooling tells the container what to do when the pool
-    # reaches it's maximum size and there are incoming requests
-    # that need instances.
+    # reaches it's maximum size and there are incoming requests that
+    # need instances.
     #
-    # With strict pooling, requests will have to wait for instances
-    # to become available. The pool size will never grow beyond the
-    # the set PoolSize value.
+    # With strict pooling, requests will have to wait for instances to
+    # become available. The pool size will never grow beyond the the
+    # set PoolSize value.  The maximum amount of time a request should
+    # wait is specified via the AccessTimeout setting.
     #
     # Without strict pooling, the container will create temporary
     # instances to meet demand. The instances will last for just one
     # method invocation and then are removed.
+    #
+    # Setting StrictPooling to false and PoolSize to 0 will result in
+    # no pooling. Instead instances will be created on demand and live
+    # for exactly one method call before being removed.
 
     StrictPooling true
 
+    # Specifies the maximum time that an instance should live before
+    # it should be retired and removed from use.  This will happen
+    # gracefully.  Useful for situations where bean instances are
+    # designed to hold potentially expensive resources such as memory
+    # or file handles and need to be periodically cleared out.
+    #
+    # Usable time units: nanoseconds, microsecons, milliseconds,
+    # seconds, minutes, hours, days.  Or any combination such as
+    # "1 hour and 27 minutes and 10 seconds"
+
+    MaxAge = 0 hours
+
+    # Specifies the maximum time that an instance should be allowed to
+    # sit idly in the pool without use before it should be retired and
+    # removed.
+    #
+    # Note that all instances in the pool, excluding the minimum, are
+    # eligible for garbage collection by the virtual machine as per
+    # the rules of java.lang.ref.WeakReference, so the use of an
+    # IdleTimeout is not required to conserve JVM-managed memory or
+    # shrink the pool.
+    #
+    # Usable time units: nanoseconds, microsecons, milliseconds,
+    # seconds, minutes, hours, days.  Or any combination such as
+    # "1 hour and 27 minutes and 10 seconds"
+
+    IdleTimeout = 0 minutes
+
+    # The frequency in which the container will sweep the pool and
+    # evict expired instances.  Eviction is how the IdleTimeout,
+    # MaxAge, and pool "flush" functionality is enforced.  Higher
+    # intervals are better.  Expired instances in use while the pool
+    # is swept will still be evicted upon return to the pool.
+    #
+    # Usable time units: nanoseconds, microsecons, milliseconds,
+    # seconds, minutes, hours, days.  Or any combination such as
+    # "1 hour and 27 minutes and 10 seconds"
+
+    PollInterval = 5 minutes
 
   </ServiceProvider>
 

Modified: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/InjectionProcessor.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/InjectionProcessor.java?rev=924925&r1=924924&r2=924925&view=diff
==============================================================================
--- openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/InjectionProcessor.java (original)
+++ openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/InjectionProcessor.java Thu Mar 18 18:09:27 2010
@@ -20,6 +20,7 @@ package org.apache.openejb;
 import org.apache.openejb.util.LogCategory;
 import org.apache.openejb.util.Logger;
 import org.apache.openejb.util.AsmParameterNameLoader;
+import org.apache.openejb.util.PassthroughFactory;
 import org.apache.xbean.recipe.ObjectRecipe;
 import org.apache.xbean.recipe.Option;
 
@@ -96,7 +97,7 @@ public class InjectionProcessor<T> {
         ObjectRecipe objectRecipe;
         if (suppliedInstance != null) {
             clazz = (Class<? extends T>) suppliedInstance.getClass();
-            objectRecipe = getInstanceRecipe(suppliedInstance);
+            objectRecipe = PassthroughFactory.recipe(suppliedInstance);
         } else {
             objectRecipe = new ObjectRecipe(clazz);
         }
@@ -203,23 +204,5 @@ public class InjectionProcessor<T> {
         
         return context;
     }
-    
-    private static ObjectRecipe getInstanceRecipe(Object instance) {
-        ObjectRecipe recipe = new ObjectRecipe(PassthroughFactory.class);
-        recipe.setFactoryMethod("create");
-
-        String param = "instance"+recipe.hashCode();
-
-        recipe.setConstructorArgNames(new String[]{param});
-        recipe.setProperty(param, instance);
-
-        return recipe;
-    }
-
-    public static class PassthroughFactory {
-        public static Object create(Object instance) {
-            return instance;
-        }
-    }
 
 }

Modified: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessContainer.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessContainer.java?rev=924925&r1=924924&r2=924925&view=diff
==============================================================================
--- openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessContainer.java (original)
+++ openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessContainer.java Thu Mar 18 18:09:27 2010
@@ -21,7 +21,6 @@ import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.concurrent.TimeUnit;
 
 import javax.ejb.EJBAccessException;
 import javax.ejb.EJBHome;
@@ -48,6 +47,7 @@ import static org.apache.openejb.core.tr
 import static org.apache.openejb.core.transaction.EjbTransactionUtil.createTransactionPolicy;
 import org.apache.openejb.spi.SecurityService;
 import org.apache.openejb.util.Duration;
+import org.apache.openejb.util.Pool;
 import org.apache.xbean.finder.ClassFinder;
 
 /**
@@ -62,11 +62,11 @@ public class StatelessContainer implemen
     private Object containerID = null;
     private SecurityService securityService;
 
-    public StatelessContainer(Object id, SecurityService securityService, Duration timeOut, int poolMin, int poolSize, boolean strictPooling) throws OpenEJBException {
+    public StatelessContainer(Object id, SecurityService securityService, Duration accessTimeout, Pool.Builder poolBuilder, int callbackThreads) {
         this.containerID = id;
         this.securityService = securityService;
 
-        instanceManager = new StatelessInstanceManager(securityService, timeOut, poolMin, poolSize, strictPooling);
+        instanceManager = new StatelessInstanceManager(securityService, accessTimeout, poolBuilder, callbackThreads);
 
         for (DeploymentInfo deploymentInfo : deploymentRegistry.values()) {
             org.apache.openejb.core.CoreDeploymentInfo di = (org.apache.openejb.core.CoreDeploymentInfo) deploymentInfo;

Added: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessContainerFactory.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessContainerFactory.java?rev=924925&view=auto
==============================================================================
--- openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessContainerFactory.java (added)
+++ openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessContainerFactory.java Thu Mar 18 18:09:27 2010
@@ -0,0 +1,103 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.openejb.core.stateless;
+
+import org.apache.openejb.spi.SecurityService;
+import org.apache.openejb.util.Duration;
+import org.apache.openejb.util.Pool;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class StatelessContainerFactory {
+
+    private final Pool.Builder pool = new Pool.Builder();
+
+    private Integer max;
+    private Object id;
+    private SecurityService securityService;
+    private Duration accessTimeout;
+    private int callbackThreads = 5;
+
+    public void setCallbackThreads(int callbackThreads) {
+        this.callbackThreads = callbackThreads;
+    }
+
+    public void setId(Object id) {
+        this.id = id;
+    }
+
+    public void setSecurityService(SecurityService securityService) {
+        this.securityService = securityService;
+    }
+
+    /**
+     * Alias for AccessTimeout
+     * backwards compatibility
+     *
+     * @deprecated use AccessTimeout
+     * @param accessTimeout
+     */
+    public void setTimeOut(Duration accessTimeout) {
+        this.accessTimeout = accessTimeout;
+    }
+
+    /**
+     *
+     * @param accessTimeout
+     */
+    public void setAccessTimeout(Duration accessTimeout) {
+        if (this.accessTimeout == null) setTimeOut(accessTimeout);
+    }
+
+    public void setPoolMax(int max) {
+        if (this.max == null) setPoolSize(max);
+    }
+
+    /**
+     * @deprecated use PoolMax
+     * @param max
+     */
+    public void setPoolSize(int max) {
+        this.max = max;
+        pool.setPoolSize(max);
+    }
+
+    public void setPoolMin(int min) {
+        pool.setPoolMin(min);
+    }
+
+    public void setStrictPooling(boolean strict) {
+        pool.setStrictPooling(strict);
+    }
+
+    public void setMaxAge(Duration maxAge) {
+        pool.setMaxAge(maxAge);
+    }
+
+    public void setIdleTimeout(Duration idleTimeout) {
+        pool.setIdleTimeout(idleTimeout);
+    }
+
+    public void setPollInterval(Duration interval) {
+        pool.setPollInterval(interval);
+    }
+
+    public StatelessContainer create() {
+        return new StatelessContainer(id, securityService, accessTimeout, pool, callbackThreads);
+    }
+}

Propchange: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessContainerFactory.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessInstanceManager.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessInstanceManager.java?rev=924925&r1=924924&r2=924925&view=diff
==============================================================================
--- openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessInstanceManager.java (original)
+++ openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessInstanceManager.java Thu Mar 18 18:09:27 2010
@@ -25,6 +25,9 @@ import java.util.List;
 import java.util.Map;
 import java.util.concurrent.TimeoutException;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.Executor;
 
 import javax.ejb.SessionBean;
 import javax.ejb.SessionContext;
@@ -48,6 +51,7 @@ import org.apache.openejb.util.LogCatego
 import org.apache.openejb.util.Logger;
 import org.apache.openejb.util.SafeToolkit;
 import org.apache.openejb.util.Pool;
+import org.apache.openejb.util.PassthroughFactory;
 import org.apache.xbean.recipe.ConstructionException;
 import org.apache.xbean.recipe.ObjectRecipe;
 import org.apache.xbean.recipe.Option;
@@ -55,33 +59,47 @@ import org.apache.xbean.recipe.Option;
 public class StatelessInstanceManager {
     private static final Logger logger = Logger.getInstance(LogCategory.OPENEJB, "org.apache.openejb.util.resources");
 
-    protected int poolLimit = 0;
     protected Duration timeout;
     protected int beanCount = 0;
-    protected boolean strictPooling = false;
 
     protected final SafeToolkit toolkit = SafeToolkit.getToolkit("StatefulInstanceManager");
     private SecurityService securityService;
-    private int poolMin = 0;
+    private final Pool.Builder poolBuilder;
+    private final Executor executor;
 
-    public StatelessInstanceManager(SecurityService securityService, Duration timeout, int poolMin, int poolMax, boolean strictPooling) {
+    public StatelessInstanceManager(SecurityService securityService, Duration timeout, Pool.Builder poolBuilder, int callbackThreads) {
         this.securityService = securityService;
-        this.poolLimit = poolMax;
-        this.strictPooling = strictPooling;
         this.timeout = timeout;
-        this.poolMin = poolMin;
-
+        this.poolBuilder = poolBuilder;
+        
         if (timeout.getUnit() == null) timeout.setUnit(TimeUnit.MILLISECONDS);
-        if (this.poolMin > poolLimit) {
-            throw new IllegalArgumentException("Minimum pool size cannot be larger than the maximum pool size: min="+ this.poolMin +", max="+poolLimit);
+
+        executor = new ThreadPoolExecutor(callbackThreads, callbackThreads*2,
+                0L, TimeUnit.MILLISECONDS,
+                new LinkedBlockingQueue<Runnable>());
+    }
+
+    private class StatelessSupplier implements Pool.Supplier<Instance> {
+        private final CoreDeploymentInfo deploymentInfo;
+
+        private StatelessSupplier(CoreDeploymentInfo deploymentInfo) {
+            this.deploymentInfo = deploymentInfo;
         }
-        
-        if (strictPooling && poolMax < 1) {
-            throw new IllegalArgumentException("Cannot use strict pooling with a pool size less than one.  Strict pooling blocks threads till an instance in the pool is available.  Please increase the pool size or set strict pooling to false");
+
+        public void discard(Instance instance) {
+            ThreadContext ctx = new ThreadContext(deploymentInfo, null);
+            ThreadContext oldCallContext = ThreadContext.enter(ctx);
+            try {
+                freeInstance(ctx, instance);
+            } finally {
+                 ThreadContext.exit(oldCallContext);
+            }
         }
 
+        public Instance create() {
+            return createInstance(deploymentInfo);
+        }
     }
-
     /**
      * Removes an instance from the pool and returns it for use
      * by the container in business methods.
@@ -348,28 +366,41 @@ public class StatelessInstanceManager {
     public void deploy(CoreDeploymentInfo deploymentInfo) {
         Options options = new Options(deploymentInfo.getProperties());
 
-        int max = options.get("PoolSize", poolLimit);
-        boolean strict = options.get("StrictPooling", this.strictPooling);
-        int min = options.get("PoolMin", poolMin);
+        final Pool.Builder builder = new Pool.Builder(poolBuilder);
 
         String timeString = options.get("Timeout", this.timeout.toString());
         timeString = options.get("AccessTimeout", timeString);
         Duration accessTimeout = new Duration(timeString);
 
-        Data data = new Data(max, strict, min, accessTimeout);
+        final ObjectRecipe recipe = PassthroughFactory.recipe(builder);
+        recipe.setAllProperties(deploymentInfo.getProperties());
+
+        builder.setSupplier(new StatelessSupplier(deploymentInfo));
+        builder.setExecutor(executor);
+        
+        Data data = new Data(builder.build(), accessTimeout);
         deploymentInfo.setContainerData(data);
 
+        final int min = builder.getMin();
+        
+        for (int i = 0; i < min; i++) {
+            Instance obj = createInstance(deploymentInfo);
+            if (obj != null) data.getPool().add(obj);
+        }
+    }
+
+    private Instance createInstance(CoreDeploymentInfo deploymentInfo) {
         ThreadContext ctx = new ThreadContext(deploymentInfo, null);
         ThreadContext oldCallContext = ThreadContext.enter(ctx);
         try {
-            for (int i = 0; i < min; i++) {
-                data.getPool().add(ceateInstance(ctx));
-            }
+            return ceateInstance(ctx);
         } catch (OpenEJBException e) {
-            logger.error("Unable to pre-fill pool to mimimum size: " + min + " for deployment '" + deploymentInfo.getDeploymentID() + "'", e);
+            logger.error("Unable to fill pool to mimimum size: for deployment '" + deploymentInfo.getDeploymentID() + "'", e);
         } finally {
              ThreadContext.exit(oldCallContext);
         }
+
+        return null;
     }
 
     public void undeploy(CoreDeploymentInfo deploymentInfo) {
@@ -384,9 +415,9 @@ public class StatelessInstanceManager {
         private final Pool<Instance> pool;
         private Duration accessTimeout;
 
-        public Data(int poolLimit, boolean strictPooling, int min, Duration accessTimeout) {
+        public Data(Pool<Instance> pool, Duration accessTimeout) {
             this.accessTimeout = accessTimeout;
-            pool = new Pool<Instance>(poolLimit, min, strictPooling);
+            this.pool = pool;
         }
 
         public Duration getAccessTimeout() {

Modified: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/transaction/TransactionType.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/transaction/TransactionType.java?rev=924925&r1=924924&r2=924925&view=diff
==============================================================================
--- openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/transaction/TransactionType.java (original)
+++ openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/transaction/TransactionType.java Thu Mar 18 18:09:27 2010
@@ -17,6 +17,8 @@
  */
 package org.apache.openejb.core.transaction;
 
+import javax.ejb.TransactionAttributeType;
+
 public enum TransactionType {
     Mandatory,
     Never,
@@ -24,5 +26,17 @@ public enum TransactionType {
     Required,
     RequiresNew,
     Supports,
-    BeanManaged
+    BeanManaged;
+
+    public static TransactionType get(TransactionAttributeType type) {
+        switch (type) {
+            case REQUIRED: return Required;
+            case REQUIRES_NEW: return RequiresNew;
+            case MANDATORY: return Mandatory;
+            case NEVER: return Never;
+            case NOT_SUPPORTED: return NotSupported;
+            case SUPPORTS: return Supports;
+            default: throw new IllegalStateException("Uknown TransactionAttributeType"+ type);
+        }
+    }
 }

Added: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/util/PassthroughFactory.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/util/PassthroughFactory.java?rev=924925&view=auto
==============================================================================
--- openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/util/PassthroughFactory.java (added)
+++ openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/util/PassthroughFactory.java Thu Mar 18 18:09:27 2010
@@ -0,0 +1,42 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.openejb.util;
+
+import org.apache.xbean.recipe.ObjectRecipe;
+import org.apache.openejb.InjectionProcessor;
+
+/**
+ * @version $Rev$ $Date$
+*/
+public class PassthroughFactory {
+
+    public static Object create(Object instance) {
+        return instance;
+    }
+
+    public static ObjectRecipe recipe(Object instance) {
+        ObjectRecipe recipe = new ObjectRecipe(PassthroughFactory.class);
+        recipe.setFactoryMethod("create");
+
+        String param = "instance"+recipe.hashCode();
+
+        recipe.setConstructorArgNames(new String[]{param});
+        recipe.setProperty(param, instance);
+
+        return recipe;
+    }
+}

Propchange: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/util/PassthroughFactory.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/util/Pool.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/util/Pool.java?rev=924925&r1=924924&r2=924925&view=diff
==============================================================================
--- openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/util/Pool.java (original)
+++ openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/util/Pool.java Thu Mar 18 18:09:27 2010
@@ -25,13 +25,15 @@ import java.util.NoSuchElementException;
 import java.util.Timer;
 import java.util.TimerTask;
 import java.util.concurrent.Executor;
-import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.Semaphore;
 import java.util.concurrent.ThreadPoolExecutor;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
+import java.util.concurrent.LinkedBlockingQueue;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicReference;
+import java.util.concurrent.atomic.AtomicInteger;
 
 /**
  * Any successful pop() call requires a corresponding push() or discard() call.
@@ -49,51 +51,123 @@ import java.util.concurrent.atomic.Atomi
 public class Pool<T> {
 
     private final LinkedList<Entry> pool = new LinkedList<Entry>();
-    private final Semaphore maxPolicy;
-    private final Semaphore minPolicy;
-    private final int max;
+    private final Semaphore instances;
+    private final Semaphore available;
+    private final Semaphore minimum;
     private final Executor executor;
+    private final long maxAge;
+    private final AtomicInteger poolVersion = new AtomicInteger();
+    private final Supplier<T> supplier;
 
-    private final Supplier<T> supplier = null;
-    
-    public Pool(int max, int min, boolean strict) {
-        this(max, min, strict, 0, 0, 0, null);
-    }
+    public static class Builder<T> {
 
-    public Pool(int max, int min, boolean strict, long maxAge, long idleTimeout, long interval, Executor executor) {
-        if (min > max) greater("max", max, "min", min);
-        if (maxAge != 0 && idleTimeout > maxAge) greater("MaxAge", maxAge, "IdleTimeout", idleTimeout);
-        this.max = max;
-        this.minPolicy = new Semaphore(min);
-        if (strict) {
-            this.maxPolicy = new Semaphore(max);
-        } else {
-            this.maxPolicy = null;
+        private int max = 10;
+        private int min = 0;
+        private boolean strict = true;
+        private Duration maxAge = new Duration(0, MILLISECONDS);
+        private Duration idleTimeout =  new Duration(0, MILLISECONDS);
+        private Duration interval =  new Duration(5 * 60, TimeUnit.SECONDS);
+        private Supplier<T> supplier;
+        private Executor executor;
+
+        public Builder(Builder<T> that) {
+            this.max = that.max;
+            this.min = that.min;
+            this.strict = that.strict;
+            this.maxAge = that.maxAge;
+            this.idleTimeout = that.idleTimeout;
+            this.interval = that.interval;
+            this.executor = that.executor;
+            this.supplier = that.supplier;
+        }
+
+        public Builder() {
         }
 
-        if (interval == 0) {
-            interval = 60 * 1000; // one minute
+        public int getMin() {
+            return min;
         }
 
-        final boolean timeouts = maxAge > 0 || idleTimeout > 0;
+        public void setPoolMax(int max) {
+            this.max = max;
+        }
 
-        this.executor = timeouts ? (executor != null) ? executor : createExecutor() : null;
+        /**
+         * Alias for pool size
+         * @param max
+         * @return
+         */
+        public void setPoolSize(int max) {
+            setPoolMax(max);
+        }
 
-        if (timeouts) {
+        public void setPoolMin(int min) {
+            this.min = min;
+        }
+
+        public void setStrictPooling(boolean strict) {
+            this.strict = strict;
+        }
 
-            final Timer timer = new Timer("PoolEviction", true);
-            timer.scheduleAtFixedRate(new Eviction(maxAge, idleTimeout), idleTimeout, interval);
+        public void setMaxAge(Duration maxAge) {
+            this.maxAge = maxAge;
+        }
+
+        public void setIdleTimeout(Duration idleTimeout) {
+            this.idleTimeout = idleTimeout;
+        }
+
+        public void setPollInterval(Duration interval) {
+            this.interval = interval;
+        }
+
+        public void setSupplier(Supplier<T> supplier) {
+            this.supplier = supplier;
+        }
+
+        public void setExecutor(Executor executor) {
+            this.executor = executor;
+        }
+
+        public Pool<T> build() {
+            return new Pool(max, min, strict, maxAge.getTime(MILLISECONDS), idleTimeout.getTime(MILLISECONDS), interval.getTime(MILLISECONDS), executor, supplier);
         }
     }
 
-    private ThreadPoolExecutor createExecutor() {
-        return new ThreadPoolExecutor(0, 10, 60 * 60, TimeUnit.SECONDS, new LinkedBlockingQueue());
+    public Pool(int max, int min, boolean strict) {
+        this(max, min, strict, 0, 0, 0, null, null);
+    }
+    
+    public Pool(int max, int min, boolean strict, long maxAge, long idleTimeout, long interval, Executor executor, Supplier<T> supplier) {
+        if (min > max) greater("max", max, "min", min);
+        if (maxAge != 0 && idleTimeout > maxAge) greater("MaxAge", maxAge, "IdleTimeout", idleTimeout);
+        this.executor = executor != null ? executor : createExecutor();
+        this.supplier = supplier != null ? supplier : new NoSupplier();
+        this.available = (strict) ? new Semaphore(max) : new Overdraft();
+        this.minimum = new Semaphore(min);
+        this.instances = new Semaphore(max);
+        this.maxAge = maxAge;
+
+        if (interval == 0) interval = 5 * 60 * 1000; // five minutes
+
+        final Timer timer = new Timer("PoolEviction", true);
+        timer.scheduleAtFixedRate(new Eviction(idleTimeout, max), idleTimeout, interval);
+    }
+
+    private Executor createExecutor() {
+        return new ThreadPoolExecutor(5, 10,
+                                      0L, TimeUnit.SECONDS,
+                                      new LinkedBlockingQueue<Runnable>());
     }
 
     private void greater(String maxName, long max, String minName, long min) {
         throw new IllegalArgumentException(minName + " cannot be greater than " + maxName + ": " + minName + "=" + min + ", " + maxName + "=" + max);
     }
 
+    public void flush() {
+        poolVersion.incrementAndGet();
+    }
+
     /**
      * Any successful pop() call requires a corresponding push() or discard() call
      * <p/>
@@ -107,9 +181,7 @@ public class Pool<T> {
      * @throws TimeoutException      if no instance could be obtained within the timeout
      */
     public Entry<T> pop(long timeout, TimeUnit unit) throws InterruptedException, TimeoutException {
-        if (maxPolicy != null) {
-            if (!maxPolicy.tryAcquire(timeout, unit)) throw new TimeoutException("Waited " + timeout + " " + unit);
-        }
+        if (!available.tryAcquire(timeout, unit)) throw new TimeoutException("Waited " + timeout + " " + unit);
 
         Entry<T> entry = null;
         while (entry == null) {
@@ -144,7 +216,7 @@ public class Pool<T> {
      * @return true of the item as added
      */
     public boolean add(T obj) {
-        return (maxPolicy == null || maxPolicy.tryAcquire()) && push(obj);
+        return add(obj, 0);
     }
 
     /**
@@ -155,7 +227,14 @@ public class Pool<T> {
      * @return true of the item as added
      */
     public boolean add(T obj, int offset) {
-        return (maxPolicy == null || maxPolicy.tryAcquire()) && push(new Entry<T>(obj, offset));
+        if (available.tryAcquire()) {
+
+            if (push(obj, offset)) return true;
+
+            available.release();
+        }
+
+        return false;
     }
 
     /**
@@ -168,7 +247,7 @@ public class Pool<T> {
      * @return false if the pool max size was exceeded
      */
     public boolean push(T obj) {
-        return push(new Entry<T>(obj));
+        return push(obj, 0);
     }
 
     /**
@@ -177,42 +256,61 @@ public class Pool<T> {
      * <p/>
      * Failure to do so will increase the max pool size by one.
      *
-     * @param entry entry that was popped from the pool
-     * @return true of the item as added
+     * @param obj object to push onto the pool
+     * @param offset
+     * @return false if the pool max size was exceeded
      */
+    private boolean push(T obj, int offset) {
+        if (instances.tryAcquire()){
+            return push(new Entry<T>(obj, offset, poolVersion.get()));
+        }
+        return false;
+    }
+
     public boolean push(Entry<T> entry) {
 
         boolean added = false;
+        boolean release = true;
+
+        try {
+            if (entry == null) return added;
 
-        if (entry != null) {
             final T obj = entry.active.getAndSet(null);
 
-            if (entry.hard.get() == null && minPolicy.tryAcquire()) {
-                entry.hard.set(obj);
-                synchronized (pool) {
-                    if (pool.size() < max) {
-                        pool.addFirst(entry);
-                        added = true;
-                    }
-                }
-                if (!added) {
-                    minPolicy.release();
+            final long age = System.currentTimeMillis() - entry.created;
+
+            final boolean aged = maxAge > 0 && age > maxAge;
+            final boolean flushed = entry.version != this.poolVersion.get();
+
+            if (aged || flushed) {
+                if (entry.hasHardReference()) {
+                    // Don't release the lock, this
+                    // entry will be directly replaced
+                    release = false;
+                    executor.execute(new Replace(entry));
                 }
+            } else if (entry.hard.get() == null && minimum.tryAcquire()) {
+                entry.hard.set(obj);
+
+                if (!(added = insert(entry))) minimum.release();
             } else {
-                synchronized (pool) {
-                    if (pool.size() < max) {
-                        pool.addLast(entry);
-                        added = true;
-                    }
-                }
+                added = insert(entry);
             }
+        } finally {
+            if (release) available.release();
         }
 
-        if (maxPolicy != null) maxPolicy.release();
-
         return added;
     }
 
+    private boolean insert(Entry<T> entry) {
+        synchronized (pool) {
+//            if (pool.size() >= max) return false;
+            pool.addFirst(entry);
+        }
+        return true;
+    }
+
     /**
      * Used when a call to pop() was made that returned null
      * indicating that the caller has a permit to create an
@@ -225,14 +323,15 @@ public class Pool<T> {
 
     public void discard(Entry<T> entry) {
         if (entry != null) {
-            final T obj = entry.active.getAndSet(null);
+            final T obj = entry.get();
 
             if (entry.hard.compareAndSet(obj, null)) {
-                minPolicy.release();
+                minimum.release();
             }
+            instances.release();
         }
 
-        if (maxPolicy != null) maxPolicy.release();
+        available.release();
     }
 
     /**
@@ -260,7 +359,7 @@ public class Pool<T> {
     public static class Entry<T> {
         private final long created;
         private long used;
-
+        private final int version;
         private final SoftReference<T> soft;
         private final AtomicReference<T> hard = new AtomicReference<T>();
 
@@ -275,32 +374,19 @@ public class Pool<T> {
          * object wrapped by this Entry.
          * <p/>
          * This helps ensure that when an Entry is returned to the pool it is
-         * always safe to call {@link java.util.concurrent.Semaphore#release()} which increases the
-         * permit size by one.
-         *
-         * @param obj object that this Entry will wrap
-         */
-        private Entry(T obj) {
-            this(obj, 0);
-        }
-
-        /**
-         * Constructor is private so that it is impossible for an Entry object
-         * to exist without there being a corresponding permit issued for the
-         * object wrapped by this Entry.
-         * <p/>
-         * This helps ensure that when an Entry is returned to the pool it is
          * always safe to call {@link Semaphore#release()} which increases the
          * permit size by one.
          *
          * @param obj    object that this Entry will wrap
          * @param offset creation time offset, used for maxAge
+         * @param version
          */
-        private Entry(T obj, int offset) {
+        private Entry(T obj, int offset, int version) {
             this.soft = new SoftReference<T>(obj);
             this.active.set(obj);
             this.created = System.currentTimeMillis() + offset;
             this.used = created;
+            this.version = version;
         }
 
         public T get() {
@@ -319,22 +405,35 @@ public class Pool<T> {
 
     private final class Eviction extends TimerTask {
 
-        private final long maxAge;
+        private final AtomicInteger previousVersion = new AtomicInteger(poolVersion.get());
         private final long idleTimeout;
+        private final boolean timeouts;
+        private final int max;
 
-        private Eviction(long maxAge, long idleTimeout) {
-            this.maxAge = maxAge;
+        private Eviction(long idleTimeout, int max) {
             this.idleTimeout = idleTimeout;
+            timeouts = maxAge > 0 || idleTimeout > 0;
+            this.max = max;
         }
 
         public void run() {
 
+            final int currentVersion = poolVersion.get();
+
+            final boolean isCurrent = previousVersion.getAndSet(currentVersion) == currentVersion;
+
+            // No timeouts to enforce?
+            // Pool version not changed?
+            // Just return
+            if (!timeouts && isCurrent) return;
+            
             final long now = System.currentTimeMillis();
 
             final List<Entry<T>> entries = new ArrayList(max);
 
+            // Pull all the entries from the pool
             try {
-                while (true) entries.add(pop(0, TimeUnit.MILLISECONDS));
+                while (true) entries.add(pop(0, MILLISECONDS));
             } catch (InterruptedException e) {
                 Thread.interrupted();
             } catch (TimeoutException e) {
@@ -342,27 +441,35 @@ public class Pool<T> {
             }
 
 
-            final List<Expired> expiredList = new ArrayList<Expired>(max);
-
-            { // Expire aged instances
-
-                // Any "null" entries are immediately returned
-                // Any non-aged "min" refs are immediately returned
+            { // Immediately return all "null" instances to free up locks
 
                 final Iterator<Entry<T>> iter = entries.iterator();
                 while (iter.hasNext()) {
-                    Entry<T> entry = iter.next();
-
+                    final Entry<T> entry = iter.next();
                     if (entry == null) {
                         // return the lock immediately
                         push(entry);
                         iter.remove();
-                        continue;
                     }
+                }
+
+            }
 
-                    long age = now - entry.created;
+            final List<Expired> expiredList = new ArrayList<Expired>(max);
 
-                    if (maxAge > 0 && age > maxAge) {
+            { // Expire aged instances, enforce pool "versioning"
+
+                // Any non-aged "min" refs are immediately returned
+
+                final Iterator<Entry<T>> iter = entries.iterator();
+                while (iter.hasNext()) {
+                    final Entry<T> entry = iter.next();
+
+                    // is too old || is old version?
+                    final boolean aged = maxAge > 0 && now - entry.created > maxAge;
+                    final boolean flushed = entry.version != currentVersion;
+
+                    if (aged || flushed) {
 
                         // Entry is too old, expire it
 
@@ -419,7 +526,7 @@ public class Pool<T> {
 
                 final long idle = now - entry.used;
 
-                if (idle > idleTimeout) {
+                if (idleTimeout > 0 && idle > idleTimeout) {
                     // too lazy -- timed out 
                     final Expired expired = new Expired(entry);
 
@@ -448,32 +555,32 @@ public class Pool<T> {
 
         }
 
-        private class Expired {
-            private final Entry<T> entry;
-            private final AtomicBoolean discarded = new AtomicBoolean();
+    }
 
-            private Expired(Entry<T> entry) {
-                this.entry = entry;
-            }
+    private class Expired {
+        private final Entry<T> entry;
+        private final AtomicBoolean discarded = new AtomicBoolean();
 
-            public boolean tryDiscard() {
-                if (discarded.getAndSet(true)) return false;
+        private Expired(Entry<T> entry) {
+            this.entry = entry;
+        }
 
-                discard(entry);
+        public boolean tryDiscard() {
+            if (discarded.getAndSet(true)) return false;
 
-                return true;
-            }
+            discard(entry);
 
+            return true;
+        }
 
-            public boolean replaceMinEntry(Entry<T> replacement) {
-                if (!entry.hasHardReference()) return false;
-                if (replacement.hasHardReference()) return false;
-                if (discarded.getAndSet(true)) return false;
+        public boolean replaceMinEntry(Entry<T> replacement) {
+            if (!entry.hasHardReference()) return false;
+            if (replacement.hasHardReference()) return false;
+            if (discarded.getAndSet(true)) return false;
 
-                discardAndReplace(entry, replacement);
+            discardAndReplace(entry, replacement);
 
-                return true;
-            }
+            return true;
         }
     }
 
@@ -487,12 +594,17 @@ public class Pool<T> {
         public void run() {
             try {
                 final T t = supplier.create();
-                final Entry entry = new Entry(t);
-                entry.hard.set(t);
-                push(entry);
+
+                if (t == null) {
+                    discard(expired);
+                } else {
+                    final Entry entry = new Entry(t, 0 , poolVersion.get());
+                    entry.hard.set(t);
+                    push(entry);
+                }
             } catch (Throwable e) {
-                // Possibly re-try
-                // TODO: log creation failure
+                // Retry and logging should be done in
+                // the Supplier implementation
                 discard(expired);
             }
         }
@@ -517,4 +629,77 @@ public class Pool<T> {
         T create();
 
     }
+
+    private static class NoSupplier implements Supplier {
+        public void discard(Object o) {
+        }
+
+        public Object create() {
+            return null;
+        }
+    }
+
+    private static final class Overdraft extends Semaphore {
+        public Overdraft() {
+            super(0);
+        }
+
+        @Override
+        public void acquire() throws InterruptedException {
+        }
+
+        @Override
+        public void acquireUninterruptibly() {
+        }
+
+        @Override
+        public boolean tryAcquire() {
+            return true;
+        }
+
+        @Override
+        public boolean tryAcquire(long timeout, TimeUnit unit) throws InterruptedException {
+            return true;
+        }
+
+        @Override
+        public void release() {
+        }
+
+        @Override
+        public void acquire(int permits) throws InterruptedException {
+        }
+
+        @Override
+        public void acquireUninterruptibly(int permits) {
+        }
+
+        @Override
+        public boolean tryAcquire(int permits) {
+            return true;
+        }
+
+        @Override
+        public boolean tryAcquire(int permits, long timeout, TimeUnit unit) throws InterruptedException {
+            return true;
+        }
+
+        @Override
+        public void release(int permits) {
+        }
+
+        @Override
+        public int availablePermits() {
+            return 0;
+        }
+
+        @Override
+        public int drainPermits() {
+            return 0;
+        }
+
+        @Override
+        protected void reducePermits(int reduction) {
+        }
+    }
 }

Modified: openejb/trunk/openejb3/container/openejb-core/src/main/resources/META-INF/org.apache.openejb.embedded/service-jar.xml
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/resources/META-INF/org.apache.openejb.embedded/service-jar.xml?rev=924925&r1=924924&r2=924925&view=diff
==============================================================================
--- openejb/trunk/openejb3/container/openejb-core/src/main/resources/META-INF/org.apache.openejb.embedded/service-jar.xml (original)
+++ openejb/trunk/openejb3/container/openejb-core/src/main/resources/META-INF/org.apache.openejb.embedded/service-jar.xml Thu Mar 18 18:09:27 2010
@@ -80,17 +80,20 @@
           id="Default Stateless Container"
           service="Container"
           types="STATELESS"
-          constructor="id, securityService, TimeOut, PoolMin, PoolSize, StrictPooling"
-          class-name="org.apache.openejb.core.stateless.StatelessContainer">
+          factory-name="create"
+          class-name="org.apache.openejb.core.stateless.StatelessContainerFactory">
 
     # Specifies the time an invokation should wait for an instance
-    # of the pool to become available. This measured by default in
-    # milliseconds, but other time units can be specified, such as
-    # nanoseconds, microsecons, seconds or minutes.  After the timeout
-    # is reached, if an instance in the pool cannot be obtained, the
-    # method invocation will fail.
+    # of the pool to become available.
+    #
+    # After the timeout is reached, if an instance in the pool cannot
+    # be obtained, the method invocation will fail.
+    #
+    # Usable time units: nanoseconds, microsecons, milliseconds,
+    # seconds, minutes, hours, days.  Or any combination such as
+    # "1 hour and 27 minutes and 10 seconds"
 
-    TimeOut = 0 milliseconds
+    AccessTimeout = 0 milliseconds
 
     # Specifies the minimum number of bean instances that should be
     # in the pool for each bean.  Pools are prefilled to the minimum
@@ -100,28 +103,72 @@
 
     PoolMin 0
 
-    # Specifies the size of the bean pools for this
-    # stateless SessionBean container.  If StrictPooling is not
-    # used, instances will still be created beyond this number if
-    # there is demand, but they will not be returned to the pool
-    # and instead will be immediately destroyed.
+    # Specifies the size of the bean pools for this stateless
+    # SessionBean container.  If StrictPooling is not used, instances
+    # will still be created beyond this number if there is demand, but
+    # they will not be returned to the pool and instead will be
+    # immediately destroyed.
 
     PoolSize 10
 
     # StrictPooling tells the container what to do when the pool
-    # reaches it's maximum size and there are incoming requests
-    # that need instances.
+    # reaches it's maximum size and there are incoming requests that
+    # need instances.
     #
-    # With strict pooling, requests will have to wait for instances
-    # to become available. The pool size will never grow beyond the
-    # the set PoolSize value.
+    # With strict pooling, requests will have to wait for instances to
+    # become available. The pool size will never grow beyond the the
+    # set PoolSize value.  The maximum amount of time a request should
+    # wait is specified via the AccessTimeout setting.
     #
     # Without strict pooling, the container will create temporary
     # instances to meet demand. The instances will last for just one
     # method invocation and then are removed.
+    #
+    # Setting StrictPooling to false and PoolSize to 0 will result in
+    # no pooling. Instead instances will be created on demand and live
+    # for exactly one method call before being removed.
 
     StrictPooling true
 
+    # Specifies the maximum time that an instance should live before
+    # it should be retired and removed from use.  This will happen
+    # gracefully.  Useful for situations where bean instances are
+    # designed to hold potentially expensive resources such as memory
+    # or file handles and need to be periodically cleared out.
+    #
+    # Usable time units: nanoseconds, microsecons, milliseconds,
+    # seconds, minutes, hours, days.  Or any combination such as
+    # "1 hour and 27 minutes and 10 seconds"
+
+    MaxAge = 0 hours
+
+    # Specifies the maximum time that an instance should be allowed to
+    # sit idly in the pool without use before it should be retired and
+    # removed.
+    #
+    # Note that all instances in the pool, excluding the minimum, are
+    # eligible for garbage collection by the virtual machine as per
+    # the rules of java.lang.ref.WeakReference, so the use of an
+    # IdleTimeout is not required to conserve JVM-managed memory or
+    # shrink the pool.
+    #
+    # Usable time units: nanoseconds, microsecons, milliseconds,
+    # seconds, minutes, hours, days.  Or any combination such as
+    # "1 hour and 27 minutes and 10 seconds"
+
+    IdleTimeout = 0 minutes
+
+    # The frequency in which the container will sweep the pool and
+    # evict expired instances.  Eviction is how the IdleTimeout,
+    # MaxAge, and pool "flush" functionality is enforced.  Higher
+    # intervals are better.  Expired instances in use while the pool
+    # is swept will still be evicted upon return to the pool.
+    #
+    # Usable time units: nanoseconds, microsecons, milliseconds,
+    # seconds, minutes, hours, days.  Or any combination such as
+    # "1 hour and 27 minutes and 10 seconds"
+
+    PollInterval = 5 minutes
 
   </ServiceProvider>
 

Modified: openejb/trunk/openejb3/container/openejb-core/src/main/resources/META-INF/org.apache.openejb/service-jar.xml
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/resources/META-INF/org.apache.openejb/service-jar.xml?rev=924925&r1=924924&r2=924925&view=diff
==============================================================================
--- openejb/trunk/openejb3/container/openejb-core/src/main/resources/META-INF/org.apache.openejb/service-jar.xml (original)
+++ openejb/trunk/openejb3/container/openejb-core/src/main/resources/META-INF/org.apache.openejb/service-jar.xml Thu Mar 18 18:09:27 2010
@@ -82,17 +82,20 @@
           id="Default Stateless Container"
           service="Container"
           types="STATELESS"
-          constructor="id, securityService, TimeOut, PoolMin, PoolSize, StrictPooling"
-          class-name="org.apache.openejb.core.stateless.StatelessContainer">
+          factory-name="create"
+          class-name="org.apache.openejb.core.stateless.StatelessContainerFactory">
 
     # Specifies the time an invokation should wait for an instance
-    # of the pool to become available. This measured by default in
-    # milliseconds, but other time units can be specified, such as
-    # nanoseconds, microsecons, seconds or minutes.  After the timeout
-    # is reached, if an instance in the pool cannot be obtained, the
-    # method invocation will fail.
+    # of the pool to become available.
+    #
+    # After the timeout is reached, if an instance in the pool cannot
+    # be obtained, the method invocation will fail.
+    #
+    # Usable time units: nanoseconds, microsecons, milliseconds,
+    # seconds, minutes, hours, days.  Or any combination such as
+    # "1 hour and 27 minutes and 10 seconds"
 
-    TimeOut = 0 milliseconds
+    AccessTimeout = 0 milliseconds
 
     # Specifies the minimum number of bean instances that should be
     # in the pool for each bean.  Pools are prefilled to the minimum
@@ -102,28 +105,72 @@
 
     PoolMin 0
 
-    # Specifies the size of the bean pools for this
-    # stateless SessionBean container.  If StrictPooling is not
-    # used, instances will still be created beyond this number if
-    # there is demand, but they will not be returned to the pool
-    # and instead will be immediately destroyed.
+    # Specifies the size of the bean pools for this stateless
+    # SessionBean container.  If StrictPooling is not used, instances
+    # will still be created beyond this number if there is demand, but
+    # they will not be returned to the pool and instead will be
+    # immediately destroyed.
 
     PoolSize 10
 
     # StrictPooling tells the container what to do when the pool
-    # reaches it's maximum size and there are incoming requests
-    # that need instances.
+    # reaches it's maximum size and there are incoming requests that
+    # need instances.
     #
-    # With strict pooling, requests will have to wait for instances
-    # to become available. The pool size will never grow beyond the
-    # the set PoolSize value.
+    # With strict pooling, requests will have to wait for instances to
+    # become available. The pool size will never grow beyond the the
+    # set PoolSize value.  The maximum amount of time a request should
+    # wait is specified via the AccessTimeout setting.
     #
     # Without strict pooling, the container will create temporary
     # instances to meet demand. The instances will last for just one
     # method invocation and then are removed.
+    #
+    # Setting StrictPooling to false and PoolSize to 0 will result in
+    # no pooling. Instead instances will be created on demand and live
+    # for exactly one method call before being removed.
 
     StrictPooling true
 
+    # Specifies the maximum time that an instance should live before
+    # it should be retired and removed from use.  This will happen
+    # gracefully.  Useful for situations where bean instances are
+    # designed to hold potentially expensive resources such as memory
+    # or file handles and need to be periodically cleared out.
+    #
+    # Usable time units: nanoseconds, microsecons, milliseconds,
+    # seconds, minutes, hours, days.  Or any combination such as
+    # "1 hour and 27 minutes and 10 seconds"
+
+    MaxAge = 0 hours
+
+    # Specifies the maximum time that an instance should be allowed to
+    # sit idly in the pool without use before it should be retired and
+    # removed.
+    #
+    # Note that all instances in the pool, excluding the minimum, are
+    # eligible for garbage collection by the virtual machine as per
+    # the rules of java.lang.ref.WeakReference, so the use of an
+    # IdleTimeout is not required to conserve JVM-managed memory or
+    # shrink the pool.
+    #
+    # Usable time units: nanoseconds, microsecons, milliseconds,
+    # seconds, minutes, hours, days.  Or any combination such as
+    # "1 hour and 27 minutes and 10 seconds"
+
+    IdleTimeout = 0 minutes
+
+    # The frequency in which the container will sweep the pool and
+    # evict expired instances.  Eviction is how the IdleTimeout,
+    # MaxAge, and pool "flush" functionality is enforced.  Higher
+    # intervals are better.  Expired instances in use while the pool
+    # is swept will still be evicted upon return to the pool.
+    #
+    # Usable time units: nanoseconds, microsecons, milliseconds,
+    # seconds, minutes, hours, days.  Or any combination such as
+    # "1 hour and 27 minutes and 10 seconds"
+
+    PollInterval = 5 minutes
 
   </ServiceProvider>
 

Modified: openejb/trunk/openejb3/container/openejb-core/src/main/resources/default.openejb.conf
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/resources/default.openejb.conf?rev=924925&r1=924924&r2=924925&view=diff
==============================================================================
--- openejb/trunk/openejb3/container/openejb-core/src/main/resources/default.openejb.conf (original)
+++ openejb/trunk/openejb3/container/openejb-core/src/main/resources/default.openejb.conf Thu Mar 18 18:09:27 2010
@@ -66,13 +66,16 @@
 <Container id="My Stateless Container" type="STATELESS">
 
   # Specifies the time an invokation should wait for an instance
-  # of the pool to become available. This measured by default in
-  # milliseconds, but other time units can be specified, such as
-  # nanoseconds, microsecons, seconds or minutes.  After the timeout
-  # is reached, if an instance in the pool cannot be obtained, the
-  # method invocation will fail.
+  # of the pool to become available.
+  #
+  # After the timeout is reached, if an instance in the pool cannot
+  # be obtained, the method invocation will fail.
+  #
+  # Usable time units: nanoseconds, microsecons, milliseconds,
+  # seconds, minutes, hours, days.  Or any combination such as
+  # "1 hour and 27 minutes and 10 seconds"
 
-  TimeOut = 0 milliseconds
+  AccessTimeout = 0 milliseconds
 
   # Specifies the minimum number of bean instances that should be
   # in the pool for each bean.  Pools are prefilled to the minimum
@@ -82,28 +85,73 @@
 
   PoolMin 0
 
-  # Specifies the size of the bean pools for this
-  # stateless SessionBean container.  If StrictPooling is not
-  # used, instances will still be created beyond this number if
-  # there is demand, but they will not be returned to the pool
-  # and instead will be immediately destroyed.
+  # Specifies the maximum number of bean instances that should be
+  # in the pool for each bean. If StrictPooling is not used, instances
+  # will still be created beyond this number if there is demand, but
+  # they will not be returned to the pool and instead will be
+  # immediately destroyed.
 
   PoolSize 10
 
   # StrictPooling tells the container what to do when the pool
-  # reaches it's maximum size and there are incoming requests
-  # that need instances.
+  # reaches it's maximum size and there are incoming requests that
+  # need instances.
   #
-  # With strict pooling, requests will have to wait for instances
-  # to become available. The pool size will never grow beyond the
-  # the set PoolSize value.
+  # With strict pooling, requests will have to wait for instances to
+  # become available. The pool size will never grow beyond the the
+  # set PoolSize value.  The maximum amount of time a request should
+  # wait is specified via the AccessTimeout setting.
   #
   # Without strict pooling, the container will create temporary
   # instances to meet demand. The instances will last for just one
   # method invocation and then are removed.
+  #
+  # Setting StrictPooling to false and PoolSize to 0 will result in
+  # no pooling. Instead instances will be created on demand and live
+  # for exactly one method call before being removed.
 
   StrictPooling true
 
+  # Specifies the maximum time that an instance should live before
+  # it should be retired and removed from use.  This will happen
+  # gracefully.  Useful for situations where bean instances are
+  # designed to hold potentially expensive resources such as memory
+  # or file handles and need to be periodically cleared out.
+  #
+  # Usable time units: nanoseconds, microsecons, milliseconds,
+  # seconds, minutes, hours, days.  Or any combination such as
+  # "1 hour and 27 minutes and 10 seconds"
+
+  MaxAge = 0 hours
+
+  # Specifies the maximum time that an instance should be allowed to
+  # sit idly in the pool without use before it should be retired and
+  # removed.
+  #
+  # Note that all instances in the pool, excluding the minimum, are
+  # eligible for garbage collection by the virtual machine as per
+  # the rules of java.lang.ref.WeakReference, so the use of an
+  # IdleTimeout is not required to conserve JVM-managed memory or
+  # shrink the pool.
+  #
+  # Usable time units: nanoseconds, microsecons, milliseconds,
+  # seconds, minutes, hours, days.  Or any combination such as
+  # "1 hour and 27 minutes and 10 seconds"
+
+  IdleTimeout = 0 minutes
+
+  # The frequency in which the container will sweep the pool and
+  # evict expired instances.  Eviction is how the IdleTimeout,
+  # MaxAge, and pool "flush" functionality is enforced.  Higher
+  # intervals are better.  Expired instances in use while the pool
+  # is swept will still be evicted upon return to the pool.
+  #
+  # Usable time units: nanoseconds, microsecons, milliseconds,
+  # seconds, minutes, hours, days.  Or any combination such as
+  # "1 hour and 27 minutes and 10 seconds"
+
+  PollInterval = 5 minutes
+
 </Container>
 
 

Modified: openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/config/ConfigureServiceTest.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/config/ConfigureServiceTest.java?rev=924925&r1=924924&r2=924925&view=diff
==============================================================================
--- openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/config/ConfigureServiceTest.java (original)
+++ openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/config/ConfigureServiceTest.java Thu Mar 18 18:09:27 2010
@@ -113,7 +113,7 @@ public class ConfigureServiceTest extend
         ContainerInfo myStatelessContainer = factory.configureService(container,  ContainerInfo.class);
 
         assertNotNull(myStatelessContainer);
-        assertEquals("org.apache.openejb.core.stateless.StatelessContainer", myStatelessContainer.className);
+        assertEquals("org.apache.openejb.core.stateless.StatelessContainerFactory", myStatelessContainer.className);
     }
 
     public void testConfigureServiceAddedPropertyViaURI() throws Exception {