Author: alessio.soldano(a)jboss.com
Date: 2009-09-18 12:02:44 -0400 (Fri, 18 Sep 2009)
New Revision: 10713
Removed:
spi/trunk/src/main/java/org/jboss/wsf/spi/util/ResourceCachingClassLoader.java
Modified:
spi/trunk/src/main/java/org/jboss/wsf/spi/util/ServiceLoader.java
Log:
[JBWS-2763] Store service api cache in a synchronized weak hash map in ServiceLoader and
do not change classloaders
Deleted: spi/trunk/src/main/java/org/jboss/wsf/spi/util/ResourceCachingClassLoader.java
===================================================================
---
spi/trunk/src/main/java/org/jboss/wsf/spi/util/ResourceCachingClassLoader.java 2009-09-18
08:56:42 UTC (rev 10712)
+++
spi/trunk/src/main/java/org/jboss/wsf/spi/util/ResourceCachingClassLoader.java 2009-09-18
16:02:44 UTC (rev 10713)
@@ -1,59 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * Copyright 2009, Red Hat Middleware LLC, and individual contributors
- * as indicated by the @author tags. See the copyright.txt file in the
- * distribution for a full listing of individual contributors.
- *
- * This is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
- */
-package org.jboss.wsf.spi.util;
-
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-
-/**
- * A ClassLoader with caches for resource lookup through services (META-INF/services)
- *
- * @author alessio.soldano(a)jboss.com
- * @since 18-Sep-2009
- *
- */
-public class ResourceCachingClassLoader extends ClassLoader
-{
- private ConcurrentMap<String, String> servicesMap = new
ConcurrentHashMap<String, String>();
-
- public ResourceCachingClassLoader(ClassLoader parent)
- {
- super(parent);
- //clear maps to same memory, as this constructor is also called when this
classloader becomes a father (hence the cache is not useful anymore)
- servicesMap.clear();
- }
-
- public boolean hasResourceNameFromServices(String key)
- {
- return servicesMap.containsKey(key);
- }
-
- public String getResourceNameFromServices(String key)
- {
- return servicesMap.get(key);
- }
-
- public void setResourceNameFromServices(String key, String value)
- {
- servicesMap.put(key, value);
- }
-}
Modified: spi/trunk/src/main/java/org/jboss/wsf/spi/util/ServiceLoader.java
===================================================================
--- spi/trunk/src/main/java/org/jboss/wsf/spi/util/ServiceLoader.java 2009-09-18 08:56:42
UTC (rev 10712)
+++ spi/trunk/src/main/java/org/jboss/wsf/spi/util/ServiceLoader.java 2009-09-18 16:02:44
UTC (rev 10713)
@@ -29,7 +29,11 @@
import java.io.InputStreamReader;
import java.security.AccessController;
import java.security.PrivilegedAction;
+import java.util.Collections;
+import java.util.Map;
import java.util.Properties;
+import java.util.WeakHashMap;
+import java.util.concurrent.ConcurrentHashMap;
/**
* Load a service class using this ordered lookup procedure
@@ -41,6 +45,12 @@
public abstract class ServiceLoader
{
/**
+ * A synchronized weak hash map that keeps factory names retrieved using Service API
(META-INF/services/*) for each classloader.
+ * Weak keys are used to remove entries when classloaders are garbage collected;
values are service-property-name -> factory name maps.
+ */
+ private static Map<ClassLoader, Map<String, String>> serviceMap =
Collections.synchronizedMap(new WeakHashMap<ClassLoader, Map<String,
String>>());
+
+ /**
* This method uses the algorithm below using the JAXWS Provider as an example.
*
* 1. If a resource with the name of META-INF/services/javax.xml.ws.spi.Provider
exists, then
@@ -75,61 +85,25 @@
{
Object factory = null;
String factoryName = null;
- ClassLoader cl = SecurityActions.getContextClassLoader();
- ResourceCachingClassLoader loader;
+ ClassLoader loader = SecurityActions.getContextClassLoader();
- if (cl instanceof ResourceCachingClassLoader)
- {
- loader = (ResourceCachingClassLoader)cl;
- }
- else
- {
- loader = new ResourceCachingClassLoader(cl);
- SecurityActions.setContextClassLoader(loader);
- }
-
// Use the Services API (as detailed in the JAR specification), if available, to
determine the classname.
String filename = "META-INF/services/" + propertyName;
- if (loader.hasResourceNameFromServices(filename))
+
+ try
{
- factoryName = loader.getResourceNameFromServices(filename);
- try
+ factoryName = getServiceNameUsingCache(loader, filename);
+ if (factoryName != null)
{
- if (factoryName != null)
- {
- Class factoryClass = SecurityActions.loadClass(loader, factoryName);
- factory = factoryClass.newInstance();
- }
+ Class factoryClass = SecurityActions.loadClass(loader, factoryName);
+ factory = factoryClass.newInstance();
}
- catch (Throwable t)
- {
- throw new IllegalStateException("Failed to load " + propertyName +
": " + factoryName, t);
- }
}
- else
+ catch (Throwable t)
{
- InputStream inStream = SecurityActions.getResourceAsStream(loader, filename);
- if (inStream != null)
- {
- try
- {
- BufferedReader br = new BufferedReader(new InputStreamReader(inStream,
"UTF-8"));
- factoryName = br.readLine();
- br.close();
- loader.setResourceNameFromServices(filename, factoryName);
- if (factoryName != null)
- {
- Class factoryClass = SecurityActions.loadClass(loader, factoryName);
- factory = factoryClass.newInstance();
- }
- }
- catch (Throwable t)
- {
- throw new IllegalStateException("Failed to load " + propertyName
+ ": " + factoryName, t);
- }
- }
+ throw new IllegalStateException("Failed to load " + propertyName +
": " + factoryName, t);
}
-
+
// Use the default factory implementation class.
if (factory == null && defaultFactory != null)
{
@@ -139,6 +113,33 @@
return factory;
}
+ private static String getServiceNameUsingCache(ClassLoader loader, String filename)
throws IOException
+ {
+ Map<String, String> map = serviceMap.get(loader);
+ if (map != null && map.containsKey(filename))
+ {
+ return map.get(filename);
+ }
+ else
+ {
+ if (map == null)
+ {
+ map = new ConcurrentHashMap<String, String>();
+ serviceMap.put(loader, map);
+ }
+ InputStream inStream = SecurityActions.getResourceAsStream(loader, filename);
+ String factoryName = null;
+ if (inStream != null)
+ {
+ BufferedReader br = new BufferedReader(new InputStreamReader(inStream,
"UTF-8"));
+ factoryName = br.readLine();
+ br.close();
+ map.put(filename, factoryName);
+ }
+ return factoryName;
+ }
+ }
+
/** Use the system property
*/
public static Object loadFromSystemProperty(String propertyName, String
defaultFactory)