You are viewing a plain text version of this content. The canonical link for it is here.
Posted to axis-cvs@ws.apache.org by sc...@apache.org on 2008/04/21 17:42:35 UTC

svn commit: r650177 - in /webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2: datasource/jaxb/JAXBDSContext.java jaxws/message/databinding/JAXBUtils.java

Author: scheu
Date: Mon Apr 21 08:42:32 2008
New Revision: 650177

URL: http://svn.apache.org/viewvc?rev=650177&view=rev
Log:
AXIS2-3758
Contributor:Rich Scheuerle
Use WeakReference objects to allow gc() to reclaim JAXBContext and related objects.

Modified:
    webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/datasource/jaxb/JAXBDSContext.java
    webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/message/databinding/JAXBUtils.java

Modified: webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/datasource/jaxb/JAXBDSContext.java
URL: http://svn.apache.org/viewvc/webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/datasource/jaxb/JAXBDSContext.java?rev=650177&r1=650176&r2=650177&view=diff
==============================================================================
--- webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/datasource/jaxb/JAXBDSContext.java (original)
+++ webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/datasource/jaxb/JAXBDSContext.java Mon Apr 21 08:42:32 2008
@@ -45,6 +45,7 @@
 import javax.xml.ws.Holder;
 import javax.xml.ws.WebServiceException;
 import java.io.OutputStream;
+import java.lang.ref.WeakReference;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.security.PrivilegedAction;
@@ -64,17 +65,22 @@
     public static final boolean DEBUG_ENABLED = log.isDebugEnabled();
 
     private TreeSet<String> contextPackages;  // List of packages needed by the context
-    private String contextPackagesKey;        // Unique key that represents the set of contextPackages (usually toString)
-    private JAXBContext jaxbContext = null;   // JAXBContext
+    private String contextPackagesKey;        // Unique key that represents the set of packages
+    
+    private JAXBContext customerJAXBContext;      // JAXBContext provided by the customer api
+    //  JAXBContext loaded by the engine.  It is weakref'd to allow GC
+    private WeakReference<JAXBContext> autoJAXBContext = null;   
     private JAXBUtils.CONSTRUCTION_TYPE       // How the JAXBContext is constructed
             constructionType = JAXBUtils.CONSTRUCTION_TYPE.UNKNOWN;
     private MessageContext msgContext;    
 
-    // There are two modes of marshalling and unmarshalling: "by java type" and "by schema element".
+    // There are two modes of marshalling and unmarshalling: 
+    //   "by java type" and "by schema element".
     // The prefered mode is "by schema element" because it is safe and xml-centric.
     // However there are some circumstances when "by schema element" is not available.
     //    Examples: RPC Lit processing (the wire element is defined by a wsdl:part...not schema)
-    //              Doc/Lit Bare "Minimal" Processing (JAXB ObjectFactories are missing...and thus we must use "by type" for primitives/String)
+    //              Doc/Lit Bare "Minimal" Processing (JAXB ObjectFactories are missing...
+    //                   and thus we must use "by type" for primitives/String)
     // Please don't use "by java type" processing to get around errors.
     private Class processType = null;
     private boolean isxmlList =false;
@@ -111,13 +117,14 @@
     }
 
     /**
-     * "Dispatch" Constructor Use this full constructor when the JAXBContent is provided by the
+     * "Dispatch" Constructor 
+     * Use this full constructor when the JAXBContent is provided by the
      * customer.
      *
      * @param jaxbContext
      */
     public JAXBDSContext(JAXBContext jaxbContext) {
-        this.jaxbContext = jaxbContext;
+        this.customerJAXBContext = jaxbContext;
     }
 
     /** @return Class representing type of the element */
@@ -134,22 +141,33 @@
      * @throws JAXBException
      */
     public JAXBContext getJAXBContext(ClassLoader cl) throws JAXBException {
-        if (jaxbContext == null) {
+        if (customerJAXBContext != null) {
+            return customerJAXBContext;
+        }
+        
+        // Get the weakly cached JAXBContext
+        JAXBContext jc = null;
+        if (autoJAXBContext != null) {
+            jc = autoJAXBContext.get();
+        }
+        
+        if (jc == null) {
             if (log.isDebugEnabled()) {
                 log.debug(
                         "A JAXBContext did not exist, creating a new one with the context packages.");
             }
             Holder<JAXBUtils.CONSTRUCTION_TYPE> constructType =
                     new Holder<JAXBUtils.CONSTRUCTION_TYPE>();
-            jaxbContext =
+            jc =
                     JAXBUtils.getJAXBContext(contextPackages, constructType, contextPackagesKey, cl);
             constructionType = constructType.value;
+            autoJAXBContext = new WeakReference<JAXBContext>(jc);
         } else {
             if (log.isDebugEnabled()) {
                 log.debug("Using an existing JAXBContext");
             }
         }
-        return jaxbContext;
+        return jc;
     }
 
     /** @return RPC Declared Type */

Modified: webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/message/databinding/JAXBUtils.java
URL: http://svn.apache.org/viewvc/webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/message/databinding/JAXBUtils.java?rev=650177&r1=650176&r2=650177&view=diff
==============================================================================
--- webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/message/databinding/JAXBUtils.java (original)
+++ webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/message/databinding/JAXBUtils.java Mon Apr 21 08:42:32 2008
@@ -59,9 +59,15 @@
 
     private static final Log log = LogFactory.getLog(JAXBUtils.class);
 
-    // Create a concurrent map to get the JAXBObject: keys are ClassLoader and String (package names).
-    private static Map<ClassLoader, Map<String, JAXBContextValue>> jaxbMap =
-            new ConcurrentHashMap<ClassLoader, Map<String, JAXBContextValue>>();
+    // Create a concurrent map to get the JAXBObject: 
+    //    key is the String (sorted packages)
+    //    value is a WeakReference to a ConcurrentHashMap of Classloader keys and JAXBContextValue objects
+    //               It is a weak map to encourage GC in low memory situations
+    private static Map<
+        String, 
+        WeakReference<ConcurrentHashMap<ClassLoader, JAXBContextValue>>> jaxbMap =
+            new ConcurrentHashMap<String, 
+                WeakReference<ConcurrentHashMap<ClassLoader, JAXBContextValue>>>();
 
     private static Pool<JAXBContext, Marshaller>       mpool = new Pool<JAXBContext, Marshaller>();
     private static Pool<JAXBContext, Unmarshaller>     upool = new Pool<JAXBContext, Unmarshaller>();
@@ -151,59 +157,115 @@
             }
         }
         JAXBUtilsMonitor.addPackageKey(key);
-        
-         // The JAXBContexts are keyed by ClassLoader and the set of Strings
-        ClassLoader cl = getContextClassLoader();
 
-        // Get the innerMap 
-        Map<String, JAXBContextValue> innerMap = null;
-        innerMap = getInnerMap(cacheKey, cl);
+        // Get or Create The InnerMap using the package key
+        ConcurrentHashMap<ClassLoader, JAXBContextValue> innerMap = null;
+        WeakReference<ConcurrentHashMap<ClassLoader, JAXBContextValue>> 
+            weakRef = jaxbMap.get(key);
+        
+        if (weakRef != null) {
+            innerMap = weakRef.get();
+        }
+        
         if (innerMap == null) {
             synchronized(jaxbMap) {
-                innerMap = getInnerMap(cacheKey, cl);
-                if(innerMap==null) {
-                    adjustPoolSize(jaxbMap);
-                    innerMap = new ConcurrentHashMap<String, JAXBContextValue>();
-                    if (cacheKey != null) {
-                        jaxbMap.put(cacheKey, innerMap);
-                    }
+                weakRef = jaxbMap.get(key);
+                if (weakRef != null) {
+                    innerMap = weakRef.get();
+                }
+                if (innerMap == null) {
+                    innerMap = new ConcurrentHashMap<ClassLoader, JAXBContextValue>();
+                    weakRef = 
+                        new WeakReference<ConcurrentHashMap<ClassLoader, JAXBContextValue>>(innerMap);
+                    jaxbMap.put(key, weakRef);
                 }
             }
         }
+        
+        // Now get the contextValue using either the classloader key or 
+        // the current Classloader
+        ClassLoader cl = getContextClassLoader();
+        JAXBContextValue contextValue = null;
+        if(cacheKey != null) {
+            if(log.isDebugEnabled()) {
+                log.debug("Using supplied classloader to retrieve JAXBContext: " + 
+                          cacheKey);
+            }
+            contextValue = innerMap.get(cacheKey);
+        } else {
+            if(log.isDebugEnabled()) {
+                log.debug("Using classloader from Thread to retrieve JAXBContext: " + 
+                          cl);
+            }
+            contextValue = innerMap.get(cl);
+        }
+      
+        
 
         if (contextPackages == null) {
             contextPackages = new TreeSet<String>();
         }
-
-        JAXBContextValue contextValue = innerMap.get(key);
         if (contextValue == null) {
             synchronized (innerMap) {
-                contextValue = innerMap.get(key);
-                if(contextValue==null) {
-                    adjustPoolSize(innerMap);
-
+                // Try to get the contextValue once more since sync was temporarily exited.
+                ClassLoader clKey = (cacheKey != null) ? cacheKey:cl;
+                contextValue = innerMap.get(clKey);
+                adjustPoolSize(innerMap);
+                if (contextValue==null) {
                     // Create a copy of the contextPackages.  This new TreeSet will
                     // contain only the valid contextPackages.
                     // Note: The original contextPackage set is accessed by multiple 
                     // threads and should not be altered.
 
-                    TreeSet<String> validContextPackages = new TreeSet<String>(contextPackages);  
+                    TreeSet<String> validContextPackages = new TreeSet<String>(contextPackages); 
+                    
+                    ClassLoader tryCl = cl;
                     contextValue = createJAXBContextValue(validContextPackages, cl);
 
                     // If we don't get all the classes, try the cached classloader 
                     if (cacheKey != null && validContextPackages.size() != contextPackages.size()) {
+                        tryCl = cacheKey;
                         validContextPackages = new TreeSet<String>(contextPackages);
                         contextValue = createJAXBContextValue(validContextPackages, cacheKey);
                     }
+                    synchronized (jaxbMap) {
+                        // Add the context value with the original package set
+                        ConcurrentHashMap<ClassLoader, JAXBContextValue> map1 = null;
+                        WeakReference<ConcurrentHashMap<ClassLoader, JAXBContextValue>> 
+                        weakRef1 = jaxbMap.get(key);
+                        if (weakRef1 != null) {
+                            map1 = weakRef.get();
+                        }
+                        if (map1 == null) {
+                            map1 = new ConcurrentHashMap<ClassLoader, JAXBContextValue>();
+                            weakRef1 = 
+                                new WeakReference<ConcurrentHashMap<ClassLoader, JAXBContextValue>>(map1);
+                            jaxbMap.put(key, weakRef1);
+                        }
+                        map1.put(clKey, contextValue);
 
-                    // Put the new context in the map keyed by both the original and valid list of packages
-                    String validPackagesKey = validContextPackages.toString();
-                    innerMap.put(key, contextValue);
-                    innerMap.put(validPackagesKey, contextValue);
-                    if (log.isDebugEnabled()) {
-                        log.debug("JAXBContext [created] for " + key);
-                        log.debug("JAXBContext also stored by the list of valid packages:" + validPackagesKey);
-                    }
+                        String validPackagesKey = validContextPackages.toString();
+
+                        // Add the context value with the new package set
+                        ConcurrentHashMap<ClassLoader, JAXBContextValue> map2 = null;
+                        WeakReference<ConcurrentHashMap<ClassLoader, JAXBContextValue>> 
+                        weakRef2 = jaxbMap.get(validPackagesKey);
+                        if (weakRef2 != null) {
+                            map2 = weakRef.get();
+                        }
+                        if (map2 == null) {
+                            map2 = new ConcurrentHashMap<ClassLoader, JAXBContextValue>();
+                            weakRef2 = 
+                                new WeakReference<ConcurrentHashMap<ClassLoader, JAXBContextValue>>(map2);
+                            jaxbMap.put(key, weakRef2);
+                        }
+                        map2.put(clKey, contextValue);
+                        
+                        if (log.isDebugEnabled()) {
+                            log.debug("JAXBContext [created] for " + key);
+                            log.debug("JAXBContext also stored by the list of valid packages:" + validPackagesKey);
+                        }
+                    }        
                 }
             }
         } else {
@@ -215,24 +277,6 @@
         return contextValue.jaxbContext;
     }
 
-    private static Map<String, JAXBContextValue> getInnerMap(ClassLoader cacheKey, ClassLoader cl) {
-        Map<String, JAXBContextValue> innerMap;
-        if(cacheKey != null) {
-            if(log.isDebugEnabled()) {
-                log.debug("Using supplied classloader to retrieve JAXBContext: " + 
-                          cacheKey);
-            }
-            innerMap = jaxbMap.get(cacheKey);
-        }else {
-            if(log.isDebugEnabled()) {
-                log.debug("Using classloader from Thread to retrieve JAXBContext: " + 
-                          cl);
-            }
-            innerMap = jaxbMap.get(cl);
-        }
-        return innerMap;
-    }
-
     /**
      * Create a JAXBContext using the contextPackages
      *
@@ -354,9 +398,15 @@
 
         // The code above may have removed some packages from the list. 
         // Retry our lookup with the updated list
-        Map<String, JAXBContextValue> innerMap = jaxbMap.get(cl);
+        String key = contextPackages.toString();
+        ConcurrentHashMap<ClassLoader, JAXBContextValue> innerMap = null;
+        WeakReference<ConcurrentHashMap<ClassLoader, JAXBContextValue>> weakRef = jaxbMap.get(key);
+        if (weakRef != null) {
+            innerMap = weakRef.get();
+        }
+        
         if (innerMap != null) {
-            contextValue = innerMap.get(contextPackages.toString());
+            contextValue = innerMap.get(cl);
             if (contextValue != null) {
                 if (log.isDebugEnabled()) {
                     log.debug("Successfully found JAXBContext with updated context list:" +
@@ -1012,7 +1062,9 @@
      * @param <V> Pooled object
      */
     private static class Pool<K,V> {
-        private Map<K,List<WeakReference<V>>> map = new ConcurrentHashMap<K, List<WeakReference<V>>>();
+        private WeakReference<Map<K,List<V>>> weakMap = 
+            new WeakReference<Map<K,List<V>>>(
+                    new ConcurrentHashMap<K, List<V>>());
 
         // The maps are freed up when a LOAD FACTOR is hit
         private static int MAX_LIST_FACTOR = 10;
@@ -1022,16 +1074,12 @@
          * @return removed item from pool or null.
          */
         public V get(K key) {
-            List<WeakReference<V>> values = getValues(key);
+            List<V> values = getValues(key);
             synchronized (values) {
-                while (values.size()>0) {
-                    // Get the WeakReference, and return the actual value if it is not
-                    // GC'd.  Otherwise try the next WeakReference
-                    WeakReference<V> wr = values.remove(values.size()-1);
-                    V v = wr.get();
-                    if (v != null) {
-                        return v;
-                    }
+                if (values.size()>0) {
+                    V v = values.remove(values.size()-1);
+                    return v;
+                    
                 }
             }
             return null;
@@ -1044,12 +1092,10 @@
          */
         public void put(K key, V value) {
             adjustSize();
-            List<WeakReference<V>> values = getValues(key);
+            List<V> values = getValues(key);
             synchronized (values) {
                 if (values.size() < MAX_LIST_FACTOR) {
-                    // Add a WeakReference to the value so that it can be GC'd
-                    WeakReference<V> wr = new WeakReference<V>(value);
-                    values.add(wr);
+                    values.add(value);
                 }
             }
         }
@@ -1059,16 +1105,28 @@
          * @param key
          * @return list of values.
          */
-        private List<WeakReference<V>> getValues(K key) {
-            List<WeakReference<V>> values = map.get(key);
-            if(values !=null) {
-                return values;
+        private List<V> getValues(K key) {
+            Map<K,List<V>> map = weakMap.get();
+            List<V> values = null;
+            if (map != null) {
+                values = map.get(key);
+                if(values !=null) {
+                    return values;
+                }
             }
             synchronized (this) {
-                values = map.get(key);
-                if(values==null) {
-                    values = new ArrayList<WeakReference<V>>();
+                if (map != null) {
+                    values = map.get(key);
+                }
+                if (values == null) {
+                    if (map == null) {
+                        map = new ConcurrentHashMap<K, List<V>>();
+                        weakMap = 
+                            new WeakReference<Map<K,List<V>>>(map);
+                    }
+                    values = new ArrayList<V>();
                     map.put(key, values);
+
                 }
                 return values;
             }
@@ -1083,7 +1141,8 @@
          * a large footprint.
          */
         private void adjustSize() {
-            if (map.size() > MAX_LOAD_FACTOR) {
+            Map<K,List<V>> map = weakMap.get();
+            if (map != null && map.size() > MAX_LOAD_FACTOR) {
                 // Remove every other Entry in the map.
                 Iterator it = map.entrySet().iterator();
                 boolean removeIt = false;



---------------------------------------------------------------------
To unsubscribe, e-mail: axis-cvs-unsubscribe@ws.apache.org
For additional commands, e-mail: axis-cvs-help@ws.apache.org