You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tomee.apache.org by da...@apache.org on 2008/08/28 04:49:45 UTC

svn commit: r689703 - in /openejb/trunk/openejb3: assembly/openejb-tomcat/openejb-tomcat-webapp/src/main/resources/META-INF/org.apache.openejb.tomcat/ container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/ container/openejb-core/src...

Author: dain
Date: Wed Aug 27 19:49:45 2008
New Revision: 689703

URL: http://svn.apache.org/viewvc?rev=689703&view=rev
Log:
Stateful cache is now choosed by the StatefulContainer "Cache" property. 
Cache instance is built using xbean-reflect in the StatefulContainerFactory using all unset properties on the container.

Added:
    openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateful/StatefulContainerFactory.java
Modified:
    openejb/trunk/openejb3/assembly/openejb-tomcat/openejb-tomcat-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/assembler/classic/Assembler.java
    openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/AutoConfig.java
    openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateful/Cache.java
    openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateful/SimpleCache.java
    openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateful/StatefulContainer.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/server/openejb-ejbd/src/main/java/org/apache/openejb/server/ejbd/KeepAliveServer.java

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=689703&r1=689702&r2=689703&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 Wed Aug 27 19:49:45 2008
@@ -146,8 +146,16 @@
           id="Default Stateful Container"
           service="Container"
           types="STATEFUL"
-          constructor="id, securityService, Passivator, TimeOut, PoolSize, BulkPassivate"
-          class-name="org.apache.openejb.core.stateful.StatefulContainer">
+          factory-name="create"
+          class-name="org.apache.openejb.core.stateful.StatefulContainerFactory">
+
+    # The cache is responsible for managing stateful bean
+    # instances.  The cache can page instances to disk as memory
+    # is filled and can destroy abandoned instances.  A different
+    # cache implementation can be used by setting this property
+    # to the fully qualified class name of the Cache implementation.
+
+    Cache org.apache.openejb.core.stateful.SimpleCache
 
     # The passivator is responsible for writing beans to disk
     # at passivation time. Different passivators can be used

Modified: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java?rev=689703&r1=689702&r2=689703&view=diff
==============================================================================
--- openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java (original)
+++ openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java Wed Aug 27 19:49:45 2008
@@ -933,6 +933,7 @@
         serviceRecipe.setProperty("id", serviceInfo.id);
         serviceRecipe.setProperty("transactionManager", props.get(TransactionManager.class.getName()));
         serviceRecipe.setProperty("securityService", props.get(SecurityService.class.getName()));
+        serviceRecipe.setProperty("properties", new UnsetPropertiesRecipe());
 
         // MDB container has a resource adapter string name that
         // must be replaced with the real resource adapter instance

Modified: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/AutoConfig.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/AutoConfig.java?rev=689703&r1=689702&r2=689703&view=diff
==============================================================================
--- openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/AutoConfig.java (original)
+++ openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/AutoConfig.java Wed Aug 27 19:49:45 2008
@@ -275,9 +275,14 @@
 
                     List<String> possibleUnits = new ArrayList<String>();
                     for (PersistenceUnit persistenceUnit : persistenceUnits.values()) {
-                        URI unitURI = URI.create(persistenceUnit.getId());
-                        unitURI = URISupport.relativize(moduleURI, unitURI);
-                        possibleUnits.add(unitURI.toString());
+                        try {
+                            URI unitURI = URI.create(persistenceUnit.getId());
+                            unitURI = URISupport.relativize(moduleURI, unitURI);
+                            possibleUnits.add(unitURI.toString());
+                        } catch (Exception e) {
+                            // id is typically not a valid URI
+                            possibleUnits.add(persistenceUnit.getId());
+                        }
                     }
 
                     Collections.sort(possibleUnits);

Modified: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateful/Cache.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateful/Cache.java?rev=689703&r1=689702&r2=689703&view=diff
==============================================================================
--- openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateful/Cache.java (original)
+++ openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateful/Cache.java Wed Aug 27 19:49:45 2008
@@ -19,6 +19,17 @@
 
 public interface Cache<K, V> {
     /**
+     * Gets the listener for cache events.
+     */
+    CacheListener<V> getListener();
+
+    /**
+     * Sets the listener for cache events.  This should be called by the
+     * container before using the cache.
+     */
+    void setListener(CacheListener<V> listener);
+
+    /**
      * Add a new entry to the cache.  The entry is marked checked-out and can
      * not be accessed again until checked-in.
      *

Modified: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateful/SimpleCache.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateful/SimpleCache.java?rev=689703&r1=689702&r2=689703&view=diff
==============================================================================
--- openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateful/SimpleCache.java (original)
+++ openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateful/SimpleCache.java Wed Aug 27 19:49:45 2008
@@ -46,29 +46,32 @@
     /**
      * Notified when values are loaded, stored, or timedOut
      */
-    private final CacheListener<V> listener;
+    private CacheListener<V> listener;
 
     /**
      * Used to load and store values
      */
-    private final PassivationStrategy passivator;
+    private PassivationStrategy passivator;
 
     /**
      * Maximum number of values that should be in the LRU
      */
-    private final int capacity;
+    private int capacity;
 
     /**
      * When the LRU is exceeded, this is the is the number of beans stored.
      * This helps to avoid passivating a bean at a time.
      */
-    private final int bulkPassivate;
+    private int bulkPassivate;
 
     /**
      * A bean may be destroyed if it isn't used in this length of time (in
      * milliseconds).
      */
-    private final long timeOut;
+    private long timeOut;
+
+    public SimpleCache() {
+    }
 
     public SimpleCache(CacheListener<V> listener, PassivationStrategy passivator, int capacity, int bulkPassivate, long timeOut) {
         this.listener = listener;
@@ -78,6 +81,55 @@
         this.timeOut = timeOut;
     }
 
+    public synchronized CacheListener<V> getListener() {
+        return listener;
+    }
+
+    public synchronized void setListener(CacheListener<V> listener) {
+        this.listener = listener;
+    }
+
+    public synchronized PassivationStrategy getPassivator() {
+        return passivator;
+    }
+
+    public synchronized void setPassivator(PassivationStrategy passivator) {
+        this.passivator = passivator;
+    }
+
+    public synchronized void setPassivator(Class<? extends PassivationStrategy> passivatorClass) throws Exception {
+        this.passivator = passivatorClass.newInstance();
+    }
+
+    public synchronized int getCapacity() {
+        return capacity;
+    }
+
+    public synchronized void setCapacity(int capacity) {
+        this.capacity = capacity;
+    }
+
+    // Old configurations use "PoolSize" to configure max cache size
+    public synchronized void setPoolSize(int capacity) {
+        this.capacity = capacity;
+    }
+
+    public synchronized int getBulkPassivate() {
+        return bulkPassivate;
+    }
+
+    public synchronized void setBulkPassivate(int bulkPassivate) {
+        this.bulkPassivate = bulkPassivate;
+    }
+
+    public synchronized long getTimeOut() {
+        return timeOut;
+    }
+
+    public synchronized void setTimeOut(long timeOut) {
+        this.timeOut = timeOut * 60 * 1000;
+    }
+
     public void add(K key, V value) {
         // find the existing entry
         Entry entry = cache.get(key);
@@ -234,6 +286,8 @@
     }
 
     public void processLRU() {
+        CacheListener<V> listener = this.getListener();
+
         // check for timed out entries
         Iterator<Entry> iterator = lru.iterator();
         while (iterator.hasNext()) {
@@ -263,10 +317,12 @@
                     entry.setState(EntryState.REMOVED);
 
                     // notify listener that the entry has been removed
-                    try {
-                        listener.timedOut(entry.getValue());
-                    } catch (Exception e) {
-                        logger.error("An unexpected exception occured from timedOut callback", e);
+                    if (listener != null) {
+                        try {
+                            listener.timedOut(entry.getValue());
+                        } catch (Exception e) {
+                            logger.error("An unexpected exception occured from timedOut callback", e);
+                        }
                     }
                 } else {
                     // entries are in order of last updates, so if this bean isn't timed out
@@ -280,10 +336,12 @@
 
         // if there are to many beans in the lru, shink is by on bulkPassivate size
         // bulkPassivate size is just an estimate, as locked or timed out beans are skipped
-        if (lru.size() >= capacity) {
+        if (lru.size() >= getCapacity()) {
             Map<K, V> valuesToStore = new LinkedHashMap<K, V>();
             List<Entry> entries = new ArrayList<Entry>();
 
+            int bulkPassivate = getBulkPassivate();
+            if (bulkPassivate < 1) bulkPassivate = 1;
             for (int i = 0; i < bulkPassivate; i++) {
                 Entry entry = lru.poll();
                 if (entry == null) {
@@ -323,10 +381,12 @@
                     // if the entry is actually timed out we just destroy it; othewise it is written to disk
                     if (entry.isTimedOut()) {
                         entry.setState(EntryState.REMOVED);
-                        try {
-                            listener.timedOut(entry.getValue());
-                        } catch (Exception e) {
-                            logger.error("An unexpected exception occured from timedOut callback", e);
+                        if (listener != null) {
+                            try {
+                                listener.timedOut(entry.getValue());
+                            } catch (Exception e) {
+                                logger.error("An unexpected exception occured from timedOut callback", e);
+                            }
                         }
                     } else {
                         // entry will be passivated, so we need to obtain an additional lock until the passivation is complete
@@ -352,10 +412,14 @@
                 }
             }
         }
-
     }
 
     private Entry loadEntry(K key) throws Exception {
+        PassivationStrategy passivator = getPassivator();
+        if (passivator == null) {
+            return null;
+        }
+
         V value = null;
         try {
             value = (V) passivator.activate(key);
@@ -367,25 +431,36 @@
             return null;
         }
 
-        listener.afterLoad(value);
+        CacheListener<V> listener = this.getListener();
+        if (listener != null) {
+            listener.afterLoad(value);
+        }
         Entry entry = new Entry(key, value, EntryState.AVAILABLE);
         cache.put(key, entry);
         return entry;
     }
 
     private void storeEntries(Map<K, V> entriesToStore) {
+        CacheListener<V> listener = this.getListener();
         for (Iterator<java.util.Map.Entry<K, V>> iterator = entriesToStore.entrySet().iterator(); iterator.hasNext();) {
             java.util.Map.Entry<K, V> entry = iterator.next();
 
-            try {
-                listener.beforeStore(entry.getValue());
-            } catch (Exception e) {
-                iterator.remove();
-                logger.error("An unexpected exception occured from beforeStore callback", e);
+            if (listener != null) {
+                try {
+                    listener.beforeStore(entry.getValue());
+                } catch (Exception e) {
+                    iterator.remove();
+                    logger.error("An unexpected exception occured from beforeStore callback", e);
+                }
             }
 
         }
 
+        PassivationStrategy passivator = getPassivator();
+        if (passivator == null) {
+            return;
+        }
+
         try {
             passivator.passivate(entriesToStore);
         } catch (Exception e) {
@@ -434,6 +509,7 @@
         private boolean isTimedOut() {
             assertLockHeld();
 
+            long timeOut = getTimeOut();
             if (timeOut == 0) {
                 return false;
             }
@@ -444,7 +520,7 @@
         private void resetTimeOut() {
             assertLockHeld();
 
-            if (timeOut > 0) {
+            if (getTimeOut() > 0) {
                 lastAccess = System.currentTimeMillis();
             }
         }
@@ -455,5 +531,4 @@
             }
         }
     }
-
 }

Modified: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateful/StatefulContainer.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateful/StatefulContainer.java?rev=689703&r1=689702&r2=689703&view=diff
==============================================================================
--- openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateful/StatefulContainer.java (original)
+++ openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateful/StatefulContainer.java Wed Aug 27 19:49:45 2008
@@ -93,32 +93,11 @@
     protected final Cache<Object, Instance> cache;
     private final ConcurrentHashMap<Object, Instance> checkedOutInstances = new ConcurrentHashMap<Object, Instance>();
 
-
-    public StatefulContainer(Object id,
-            SecurityService securityService,
-            Class<? extends PassivationStrategy> passivatorClass,
-            int timeOut,
-            int poolSize,
-            int bulkPassivate) throws OpenEJBException {
+    public StatefulContainer(Object id, SecurityService securityService, Cache<Object, Instance> cache) {
         this.containerID = id;
         this.securityService = securityService;
-
-        cache = createCache(passivatorClass, timeOut, poolSize, bulkPassivate);
-    }
-
-    protected Cache<Object, Instance> createCache(Class<? extends PassivationStrategy> passivatorClass, int timeOut, int poolSize, int bulkPassivate) throws OpenEJBException {
-        PassivationStrategy passivator;
-        if (passivatorClass != null) {
-            try {
-                passivator = passivatorClass.newInstance();
-            } catch (Exception e) {
-                throw new OpenEJBException("Could not create the passivator " + passivatorClass.getName(), e);
-            }
-        } else {
-            passivator = new SimplePassivater();
-        }
-
-        return new SimpleCache<Object, Instance>(new StatefulCacheListener(), passivator, poolSize, bulkPassivate, timeOut * 60 * 1000);
+        this.cache = cache;
+        cache.setListener(new StatefulCacheListener());
     }
 
     private Map<Method, MethodType> getLifecycleMethodsOfInterface(CoreDeploymentInfo deploymentInfo) {

Added: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateful/StatefulContainerFactory.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateful/StatefulContainerFactory.java?rev=689703&view=auto
==============================================================================
--- openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateful/StatefulContainerFactory.java (added)
+++ openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateful/StatefulContainerFactory.java Wed Aug 27 19:49:45 2008
@@ -0,0 +1,115 @@
+/**
+ *
+ * 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.stateful;
+
+import java.util.Properties;
+import java.util.Map.Entry;
+
+import org.apache.openejb.spi.SecurityService;
+import org.apache.xbean.recipe.ObjectRecipe;
+import org.apache.xbean.recipe.Option;
+
+public class StatefulContainerFactory {
+    private Object id;
+    private SecurityService securityService;
+    private Cache<Object, Instance> cache;
+    private Properties properties;
+
+    public Object getId() {
+        return id;
+    }
+
+    public void setId(Object id) {
+        this.id = id;
+    }
+
+    public SecurityService getSecurityService() {
+        return securityService;
+    }
+
+    public void setSecurityService(SecurityService securityService) {
+        this.securityService = securityService;
+    }
+
+    public Cache<Object, Instance> getCache() {
+        return cache;
+    }
+
+    public void setCache(Cache<Object, Instance> cache) {
+        this.cache = cache;
+    }
+
+    public Properties getProperties() {
+        return properties;
+    }
+
+    public void setProperties(Properties properties) {
+        this.properties = properties;
+    }
+
+    public StatefulContainer create() throws Exception {
+        // if a live cache was not assigned, build one
+        if (cache == null) {
+            buildCache();
+        }
+        return new StatefulContainer(id, securityService, cache);
+    }
+
+    private void buildCache() throws Exception {
+        if (properties == null) {
+            throw new IllegalArgumentException("No cache defined for StatefulContainer " + id);
+        }
+
+        // get the cache property
+        Object cache = getProperty("Cache");
+        if (cache == null) {
+            throw new IllegalArgumentException("No cache defined for StatefulContainer " + id);
+        }
+
+        // if property contains a live cache instance, just use it
+        if (cache instanceof Cache) {
+            this.cache = (Cache<Object, Instance>) cache;
+            return;
+        }
+
+        // build the object recipe
+        ObjectRecipe serviceRecipe = new ObjectRecipe((String) cache);
+        serviceRecipe.allow(Option.CASE_INSENSITIVE_PROPERTIES);
+        serviceRecipe.allow(Option.IGNORE_MISSING_PROPERTIES);
+        serviceRecipe.allow(Option.NAMED_PARAMETERS);
+        serviceRecipe.setAllProperties(properties);
+
+        // invoke recipe
+        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
+        if (classLoader == null) getClass().getClassLoader();
+        cache = serviceRecipe.create(classLoader);
+
+        // assign value
+        this.cache = (Cache<Object, Instance>) cache;
+    }
+
+    private Object getProperty(String name) {
+        for (Entry<Object, Object> entry : properties.entrySet()) {
+            Object key = entry.getKey();
+            if (key instanceof String && name.equalsIgnoreCase((String) key)) {
+                return entry.getValue();
+            }
+        }
+        return null;
+    }
+}

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=689703&r1=689702&r2=689703&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 Wed Aug 27 19:49:45 2008
@@ -138,8 +138,16 @@
           id="Default Stateful Container"
           service="Container"
           types="STATEFUL"
-          constructor="id, securityService, Passivator, TimeOut, PoolSize, BulkPassivate"
-          class-name="org.apache.openejb.core.stateful.StatefulContainer">
+          factory-name="create"
+          class-name="org.apache.openejb.core.stateful.StatefulContainerFactory">
+
+    # The cache is responsible for managing stateful bean
+    # instances.  The cache can page instances to disk as memory
+    # is filled and can destroy abandoned instances.  A different
+    # cache implementation can be used by setting this property
+    # to the fully qualified class name of the Cache implementation.
+
+    Cache org.apache.openejb.core.stateful.SimpleCache
 
     # The passivator is responsible for writing beans to disk
     # at passivation time. Different passivators can be used

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=689703&r1=689702&r2=689703&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 Wed Aug 27 19:49:45 2008
@@ -141,8 +141,16 @@
           id="Default Stateful Container"
           service="Container"
           types="STATEFUL"
-          constructor="id, securityService, Passivator, TimeOut, PoolSize, BulkPassivate"
-          class-name="org.apache.openejb.core.stateful.StatefulContainer">
+          factory-name="create"
+          class-name="org.apache.openejb.core.stateful.StatefulContainerFactory">
+
+    # The cache is responsible for managing stateful bean
+    # instances.  The cache can page instances to disk as memory
+    # is filled and can destroy abandoned instances.  A different
+    # cache implementation can be used by setting this property
+    # to the fully qualified class name of the Cache implementation.
+
+    Cache org.apache.openejb.core.stateful.SimpleCache
 
     # The passivator is responsible for writing beans to disk
     # at passivation time. Different passivators can be used

Modified: openejb/trunk/openejb3/server/openejb-ejbd/src/main/java/org/apache/openejb/server/ejbd/KeepAliveServer.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/server/openejb-ejbd/src/main/java/org/apache/openejb/server/ejbd/KeepAliveServer.java?rev=689703&r1=689702&r2=689703&view=diff
==============================================================================
--- openejb/trunk/openejb3/server/openejb-ejbd/src/main/java/org/apache/openejb/server/ejbd/KeepAliveServer.java (original)
+++ openejb/trunk/openejb3/server/openejb-ejbd/src/main/java/org/apache/openejb/server/ejbd/KeepAliveServer.java Wed Aug 27 19:49:45 2008
@@ -74,8 +74,10 @@
         }
 
         public void run() {
-            int backlog = getQueue().size();
+            BlockingQueue<Runnable> queue = getQueue();
+            if (queue == null) return;
 
+            int backlog = queue.size();
             if (backlog <= 0) return;
 
             long now = System.currentTimeMillis();
@@ -102,7 +104,9 @@
 
         private BlockingQueue<Runnable> getQueue() {
             if (queue == null){
+                // this can be null if timer fires before service is fully initialized
                 ServicePool incoming = SystemInstance.get().getComponent(ServicePool.class);
+                if (incoming == null) return null;
                 ThreadPoolExecutor threadPool = incoming.getThreadPool();
                 queue = threadPool.getQueue();
             }