Author: bimargulies
Date: Sat Dec  4 13:19:44 2010
New Revision: 1042166

URL: http://svn.apache.org/viewvc?rev=1042166&view=rev
Log:
CXF-3142

Modified:
    cxf/trunk/api/src/main/java/org/apache/cxf/BusFactory.java

Modified: cxf/trunk/api/src/main/java/org/apache/cxf/BusFactory.java
URL: 
http://svn.apache.org/viewvc/cxf/trunk/api/src/main/java/org/apache/cxf/BusFactory.java?rev=1042166&r1=1042165&r2=1042166&view=diff
==============================================================================
--- cxf/trunk/api/src/main/java/org/apache/cxf/BusFactory.java (original)
+++ cxf/trunk/api/src/main/java/org/apache/cxf/BusFactory.java Sat Dec  4 
13:19:44 2010
@@ -22,7 +22,8 @@ package org.apache.cxf;
 import java.io.BufferedReader;
 import java.io.InputStream;
 import java.io.InputStreamReader;
-import java.lang.ref.WeakReference;
+import java.lang.ref.Reference;
+import java.lang.ref.SoftReference;
 import java.util.Iterator;
 import java.util.Map;
 import java.util.WeakHashMap;
@@ -33,15 +34,15 @@ import org.apache.cxf.common.classloader
 import org.apache.cxf.common.logging.LogUtils;
 
 /**
- * Factory to create CXF Bus objects. 
+ * Factory to create CXF Bus objects.
  * <p>CXF includes a large number of components that provide services, such
- * as WSDL parsing, and message processing. To avoid creating these objects 
over and over, and to 
+ * as WSDL parsing, and message processing. To avoid creating these objects 
over and over, and to
  * allow them to be shared easily, they are associated with a data structure 
called a bus.
  * </p>
  * <p>
  * You don't ever have to explicitly create or manipulate bus objects. If you 
simply use the CXF
- * or JAX-WS APIs to create clients or servers, CXF will create an default bus 
for you. You would create a bus
- * explicitly if you need to customize components on the bus or maintain 
several independent buses 
+ * or JAX-WS APIs to create clients or servers, CXF will create a default bus 
for you. You can create a bus
+ * explicitly if you need to customize components on the bus or maintain 
several independent buses
  * with independent configurations.
  * </p>
  * <p>
@@ -53,8 +54,8 @@ import org.apache.cxf.common.logging.Log
  * If you create a bus when there is no default bus in effect, that bus will 
become the default bus.
  * </p>
  * <p>
- * This class holds <strong>weak</strong> references to the global default bus 
and the per-thread default
- * busses. Thus, if you create and customize a bus, you must retain a 
reference to it if you want it to be
+ * This class holds <strong>soft</strong> references to the global default bus.
+ * Thus, if you create and customize a bus, you must retain a reference to it 
if you want it to be
  * protected from garbage collection. If you do not, you might experience the 
following unexpected chain of
  * events, especially in a client:
  * <ol>
@@ -64,6 +65,11 @@ import org.apache.cxf.common.logging.Log
  * <li>Create a new CXF object.</li>
  * <li>Implicitly create a new, default, bus.</li>
  * </ol>
+ * Note that the per-thread default busses are maintained in a WeakHashMap 
from threads to busses.
+ * Thus, so long as the thread remains alive
+ * there will be a strong reference to the bus, and it will not get 
garbage-collected.
+ * If you want to recover memory used CXF, you can set
+ * the per-thread default bus to null, explicitly.
  * </p>
  */
 public abstract class BusFactory {
@@ -71,22 +77,22 @@ public abstract class BusFactory {
     public static final String BUS_FACTORY_PROPERTY_NAME = 
"org.apache.cxf.bus.factory";
     public static final String DEFAULT_BUS_FACTORY = 
"org.apache.cxf.bus.CXFBusFactory";
 
-    protected static WeakReference<Bus> defaultBus;
-    protected static Map<Thread, Bus> threadBusses = new WeakHashMap<Thread, 
Bus>();
+    protected static Reference<Bus> defaultBus;
+    protected static Map<Thread, Reference<Bus>> threadBusses = new 
WeakHashMap<Thread, Reference<Bus>>();
 
     private static final Logger LOG = LogUtils.getL7dLogger(BusFactory.class, 
"APIMessages");
 
     /**
      * Creates a new bus. While concrete <code>BusFactory</code> may offer 
differently parameterized methods
      * for creating a bus, all factories support this no-arg factory method.
-     * 
+     *
      * @return the newly created bus.
      */
     public abstract Bus createBus();
 
     /**
      * Returns the default bus, creating it if necessary.
-     * 
+     *
      * @return the default bus.
      */
     public static synchronized Bus getDefaultBus() {
@@ -95,13 +101,13 @@ public abstract class BusFactory {
 
     /**
      * Returns the default bus
-     * 
+     *
      * @param createIfNeeded Set to true to create a default bus if one 
doesn't exist
      * @return the default bus.
      */
     public static synchronized Bus getDefaultBus(boolean createIfNeeded) {
         if ((defaultBus == null || defaultBus.get() == null) && 
createIfNeeded) {
-            defaultBus = new WeakReference<Bus>(newInstance().createBus());
+            defaultBus = new SoftReference<Bus>(newInstance().createBus());
         }
         if (defaultBus == null) {
             // never set up.
@@ -113,32 +119,32 @@ public abstract class BusFactory {
 
     /**
      * Sets the default bus.
-     * 
+     *
      * @param bus the default bus.
      */
     public static synchronized void setDefaultBus(Bus bus) {
         if (bus == null) {
             defaultBus = null;
         } else {
-            defaultBus = new WeakReference<Bus>(bus);
+            defaultBus = new SoftReference<Bus>(bus);
         }
         setThreadDefaultBus(bus);
     }
 
     /**
      * Sets the default bus for the thread.
-     * 
+     *
      * @param bus the default bus.
      */
     public static void setThreadDefaultBus(Bus bus) {
         synchronized (threadBusses) {
-            threadBusses.put(Thread.currentThread(), bus);
+            threadBusses.put(Thread.currentThread(), new 
SoftReference<Bus>(bus));
         }
     }
 
     /**
      * Gets the default bus for the thread.
-     * 
+     *
      * @return the default bus.
      */
     public static Bus getThreadDefaultBus() {
@@ -147,39 +153,45 @@ public abstract class BusFactory {
 
     /**
      * Gets the default bus for the thread, creating if needed
-     * 
+     *
      * @param createIfNeeded Set to true to create a default bus if one 
doesn't exist
      * @return the default bus.
      */
     public static Bus getThreadDefaultBus(boolean createIfNeeded) {
-        Bus threadBus;
+        Reference<Bus> threadBus;
         synchronized (threadBusses) {
             if (createIfNeeded) {
                 threadBus = threadBusses.get(Thread.currentThread());
-                if (createIfNeeded && threadBus == null) {
-                    threadBus = getDefaultBus(createIfNeeded);
+                if (createIfNeeded && (threadBus == null || threadBus.get() == 
null)) {
+                    threadBus = new SoftReference<Bus>(getDefaultBus(true));
                     threadBusses.put(Thread.currentThread(), threadBus);
                 }
             } else {
                 threadBus = threadBusses.get(Thread.currentThread());
             }
         }
-        return threadBus;
+        if (threadBus == null) {
+            return null;
+        } else {
+            return threadBus.get();
+        }
     }
 
     /**
      * Removes a bus from being a thread default bus for any thread.
      * <p>
-     * This is tipically done when a bus has ended its lifecycle (i.e.: a call 
to
+     * This is typically done when a bus has ended its lifecycle (i.e.: a call 
to
      * {...@link Bus#shutdown(boolean)} was invoked) and it wants to remove 
any reference to itself for any
      * thread.
-     * 
+     *
      * @param bus the bus to remove
      */
     public static void clearDefaultBusForAnyThread(final Bus bus) {
         synchronized (threadBusses) {
-            for (final Iterator<Bus> iterator = 
threadBusses.values().iterator(); iterator.hasNext();) {
-                if (bus == null || bus.equals(iterator.next())) {
+            for (final Iterator<Reference<Bus>> iterator = 
threadBusses.values().iterator();
+                iterator.hasNext();) {
+                Bus itBus = iterator.next().get();
+                if (bus == null || itBus == null || bus.equals(itBus)) {
                     iterator.remove();
                 }
             }
@@ -188,20 +200,20 @@ public abstract class BusFactory {
 
     /**
      * Sets the default bus if a default bus is not already set.
-     * 
+     *
      * @param bus the default bus.
      * @return true if the bus was not set and is now set
      */
     public static synchronized boolean possiblySetDefaultBus(Bus bus) {
         synchronized (threadBusses) {
             if (threadBusses.get(Thread.currentThread()) == null) {
-                threadBusses.put(Thread.currentThread(), bus);
+                threadBusses.put(Thread.currentThread(), new 
SoftReference<Bus>(bus));
             }
         }
         // The default bus may have gc-ed itself out of existence, in which 
case we
         // take over for it.
         if (defaultBus == null || defaultBus.get() == null) {
-            defaultBus = new WeakReference<Bus>(bus);
+            defaultBus = new SoftReference<Bus>(bus);
             return true;
         }
         return false;
@@ -211,7 +223,7 @@ public abstract class BusFactory {
      * Create a new BusFactory The class of the BusFactory is determined by 
looking for the system propery:
      * org.apache.cxf.bus.factory or by searching the classpath for:
      * META-INF/services/org.apache.cxf.bus.factory
-     * 
+     *
      * @return a new BusFactory to be used to create Bus objects
      */
     public static BusFactory newInstance() {
@@ -220,7 +232,7 @@ public abstract class BusFactory {
 
     /**
      * Create a new BusFactory
-     * 
+     *
      * @param className The class of the BusFactory to create. If null, uses 
the default search algorithm.
      * @return a new BusFactory to be used to create Bus objects
      */


Reply via email to