You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@abdera.apache.org by jm...@apache.org on 2006/08/22 20:29:50 UTC

svn commit: r433716 - in /incubator/abdera/java/trunk/core/src/main/java/org/apache/abdera/util: ConfigProperties.java ServiceUtil.java

Author: jmsnell
Date: Tue Aug 22 11:29:49 2006
New Revision: 433716

URL: http://svn.apache.org/viewvc?rev=433716&view=rev
Log:
Thread safety and classpath improvements.

 * Don't store the class loader in a static variable, ServiceUtil.getClassLoader() always
   returns the context class loader

 * Cache resolved implementation classes for various ids (thread local)

 * Attempt to fallback to classpath if classes and resources cannot be loaded from the 
   context class loader

 * Use the context class loader to load the config bundle (allows webapps to provide their
   own abdera configurations even if the abdera jars are in the server classpath instead
   of the webapp classpath.

 * Don't store config options in static variables. Since we're caching resolved classes, 
   we don't need this anyway


Modified:
    incubator/abdera/java/trunk/core/src/main/java/org/apache/abdera/util/ConfigProperties.java
    incubator/abdera/java/trunk/core/src/main/java/org/apache/abdera/util/ServiceUtil.java

Modified: incubator/abdera/java/trunk/core/src/main/java/org/apache/abdera/util/ConfigProperties.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/core/src/main/java/org/apache/abdera/util/ConfigProperties.java?rev=433716&r1=433715&r2=433716&view=diff
==============================================================================
--- incubator/abdera/java/trunk/core/src/main/java/org/apache/abdera/util/ConfigProperties.java (original)
+++ incubator/abdera/java/trunk/core/src/main/java/org/apache/abdera/util/ConfigProperties.java Tue Aug 22 11:29:49 2006
@@ -24,18 +24,29 @@
   
   ConfigProperties() {}
   
-  private static ResourceBundle BUNDLE = null;
-  private static String parser = null;
-  private static String factory = null;
-  private static String xpath = null;
+  private static ThreadLocal bundleStore = new ThreadLocal();
+  
+  @SuppressWarnings("unchecked")
+  private static void storeBundle(ResourceBundle bundle) {
+    bundleStore.set(bundle);
+  }
+  
+  private static ResourceBundle retrieveBundle() {
+    return (ResourceBundle) bundleStore.get();
+  }
   
   private static ResourceBundle getBundle() {
-    if (BUNDLE == null) {
+    ResourceBundle bundle = retrieveBundle();
+    if (bundle == null) {
       try {
-        BUNDLE = ResourceBundle.getBundle("abdera");
+        bundle = ResourceBundle.getBundle(
+          "abdera", 
+          java.util.Locale.getDefault(), 
+          ServiceUtil.getClassLoader());
+        storeBundle(bundle);
       } catch (Exception e) {}
     } 
-    return BUNDLE;
+    return bundle;
   }
 
   public static String getConfigurationOption(String id) {
@@ -48,20 +59,17 @@
   }
   
   public static String getDefaultXPath() {
-    if (xpath == null)
-      xpath = getConfigurationOption(CONFIG_XPATH);
+    String xpath = getConfigurationOption(CONFIG_XPATH);
     return (xpath != null) ? xpath : DEFAULT_XPATH;
   }
   
   public static String getDefaultParser() {
-    if (parser == null)
-      parser = getConfigurationOption(CONFIG_PARSER);
+    String parser = getConfigurationOption(CONFIG_PARSER);
     return (parser != null) ? parser : DEFAULT_PARSER;
   }
   
   public static String getDefaultFactory() {
-    if (factory == null)
-      factory = getConfigurationOption(CONFIG_FACTORY);
+    String factory = getConfigurationOption(CONFIG_FACTORY);
     return (factory != null) ? factory : DEFAULT_FACTORY;
   }
   

Modified: incubator/abdera/java/trunk/core/src/main/java/org/apache/abdera/util/ServiceUtil.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/core/src/main/java/org/apache/abdera/util/ServiceUtil.java?rev=433716&r1=433715&r2=433716&view=diff
==============================================================================
--- incubator/abdera/java/trunk/core/src/main/java/org/apache/abdera/util/ServiceUtil.java (original)
+++ incubator/abdera/java/trunk/core/src/main/java/org/apache/abdera/util/ServiceUtil.java Tue Aug 22 11:29:49 2006
@@ -24,97 +24,180 @@
 import java.net.URL;
 import java.util.ArrayList;
 import java.util.Enumeration;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 import org.apache.abdera.factory.ExtensionFactory;
 import org.apache.abdera.factory.Factory;
 import org.apache.abdera.parser.Parser;
 import org.apache.abdera.xpath.XPath;
 
-
 public final class ServiceUtil 
   implements Constants {
 
   ServiceUtil() {}
-
-  static private ClassLoader classLoader = null;
   
+  private static ThreadLocal cache = new ThreadLocal();
+  
+  @SuppressWarnings("unchecked")
+  private static Map<String,Class> getCache() {
+    Map<String,Class> map;
+    if (cache.get() == null) {
+      map = new HashMap<String,Class>();
+      cache.set(map);
+    } else {
+      map = (Map<String, Class>) cache.get();
+    }
+    return map;
+  }
+  
+  /**
+   * Get the cached Class for a given id.  The cache is contained
+   * in Thread Local storage
+   */
+  private static Class getClass(String id) {
+    return getCache().get(id);
+  }
+  
+  /**
+   * Cache the class resolved for a particular ID so we don't have to 
+   * go looking for it again later.  It's highly unlikely that the 
+   * configured class will change within the context of a given thread
+   */
+  private static void setClass(String id, Class _class) {
+    getCache().put(id,_class);
+  }
+  
+  /**
+   * Returns a new instance of the identified object class.  This will use
+   * the Abdera configuration mechanism to look up the implementation class
+   * for the specified id.  Several places will be checked: the abdera.properties
+   * file, the /META-INF/services directory, and the System properties.  If 
+   * no instance is configured, the default class name will be used.  Returns
+   * null if no instance can be created.
+   */
   public static Object newInstance(String id, String _default) {
     return ServiceUtil.locate(id, _default);
   }
 
+  /**
+   * Utility method for returning an instance of the default Abdera XPath instance
+   */
   public static XPath newXPathInstance() {
     return (XPath) newInstance(
       CONFIG_XPATH,
       ConfigProperties.getDefaultXPath());
   }
   
+  /**
+   * Utility method for returning an instance of the default Abdera Parser instance
+   */
   public static Parser newParserInstance() {
     return (Parser) newInstance(
       CONFIG_PARSER, 
       ConfigProperties.getDefaultParser());
   }
 
+  /**
+   * Utility method for returning an instance of the defaul Abdera Factory instance
+   */
   public static Factory newFactoryInstance() {
     return (Factory) newInstance(
       CONFIG_FACTORY, 
       ConfigProperties.getDefaultFactory());
   }
   
+  /**
+   * Get the context class loader for this thread
+   */
   public static ClassLoader getClassLoader() {
-    if (classLoader == null) {
-      classLoader = Thread.currentThread().getContextClassLoader();
-    }
-    return classLoader;
-  }
-
-  public static void setClassLoader(ClassLoader classLoader) {
-    ServiceUtil.classLoader = classLoader;
+    return Thread.currentThread().getContextClassLoader();
   }
   
   public static Object locate(String id, String _default) {
     Object object = locate(id);
     if (object == null && _default != null) {
-      try {
-        object = getClassLoader().loadClass(_default).newInstance();
-      } catch (Exception e) {
-        // Nothing
-      }
+      object = locateInstance(getClassLoader(), _default);
     }
     return object;
   }
-  
+
+  /**
+   * Locate a class instance for the given id
+   */
   public static Object locate(String id) {
-    Object service = checkConfigProperties(id);
+    Object service = checkCache(id);
+    if (service == null) service = checkConfigProperties(id);
     return ((service != null) ? service : checkMetaInfServices(id));
   }
   
-  static Object checkConfigProperties(String id) {
-    Object object = null;
+  @SuppressWarnings("unchecked")
+  private static <T>T locateInstance(ClassLoader loader, String id) {
+    try {
+      Class _class = loader.loadClass(id);
+      setClass(id, _class);
+      return (T) _class.newInstance();
+    } catch (Exception e) {
+      // Nothing
+    }
+    try {
+      Class _class = ClassLoader.getSystemClassLoader().loadClass(id);
+      setClass(id, _class);
+      return (T) _class.newInstance();
+    } catch (Exception e) {
+      // Nothing
+    }
+    return null;
+  }
+  
+  private static InputStream locateStream(ClassLoader loader, String id) {
+    InputStream in = loader.getResourceAsStream(id);
+    return (in != null) ? in : ClassLoader.getSystemResourceAsStream(id);
+  }
+  
+  private static Enumeration<URL> locateResources(ClassLoader loader, String id) {
+    try {
+      return loader.getResources(id);
+    } catch (Exception e) {
+      // Nothing
+    }
+    try {
+      return ClassLoader.getSystemResources(id);
+    } catch (Exception e) {
+      // Nothing
+    }
+    return null;
+  }
+  
+  private static Object checkCache(String id) {
+    try {
+      Class _class = getClass(id);
+      return (_class != null) ? _class.newInstance() : null;
+    } catch (Exception e) {
+      // Nothing
+    }
+    return null;
+  }
+  
+  private static Object checkConfigProperties(String id) {
     String s = ConfigProperties.getConfigurationOption(id);
-    if (s != null) {
-      try {
-        object = getClassLoader().loadClass(s).newInstance();
-      } catch (Exception e) {
-        // Nothing
-      }
-    } 
-    return object;
+    return (s != null) ? locateInstance(getClassLoader(), id) : null;
   }
   
-  static Object checkMetaInfServices(String id) {
+  private static Object checkMetaInfServices(String id) {
     Object object = null;
     String sid = "META-INF/services/" + id;
     ClassLoader loader = getClassLoader();
     BufferedReader buf = null;
     try {
-      InputStream is = loader.getResourceAsStream(sid);
+      InputStream is = locateStream(loader,sid);
       if (is != null) {
         buf = new BufferedReader(new InputStreamReader(is));
         String line = buf.readLine();
         if (line != null) {
           String s = line.split("#",2)[0].trim();
-          object = loader.loadClass(s).newInstance();
+          object = locateInstance(loader,s);
         }
       }
     } catch (Exception e) {
@@ -146,7 +229,7 @@
     List<T> impls = new ArrayList<T>();
     ClassLoader loader = getClassLoader();
     try {
-      Enumeration e = loader.getResources(sid);
+      Enumeration<URL> e = locateResources(loader,sid);
       for (;e.hasMoreElements();) {
         BufferedReader buf = null;
         try {
@@ -158,8 +241,9 @@
             while ((line = buf.readLine()) != null) {
               String s = line.split("#",2)[0].trim();
               if (!"".equals(s)) { 
-                T impl = (T) loader.loadClass(s).newInstance();
-                impls.add(impl);
+                T impl = (T) locateInstance(loader,s);
+                if (impl != null)
+                  impls.add(impl);
               }
             }
           }