Switch to double check idiom for runtime delegate singleton; adopt EE 6 recommended class loading strategy.
svn path=/trunk/; revision=558
diff --git a/src/jsr311-api/src/javax/ws/rs/ext/FactoryFinder.java b/src/jsr311-api/src/javax/ws/rs/ext/FactoryFinder.java
index a9ee62c..cb92624 100644
--- a/src/jsr311-api/src/javax/ws/rs/ext/FactoryFinder.java
+++ b/src/jsr311-api/src/javax/ws/rs/ext/FactoryFinder.java
@@ -23,9 +23,24 @@
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
import java.util.Properties;
class FactoryFinder {
+
+ static ClassLoader getContextClassLoader() {
+ return AccessController.doPrivileged(
+ new PrivilegedAction<ClassLoader>() {
+ public ClassLoader run() {
+ ClassLoader cl = null;
+ try {
+ cl = Thread.currentThread().getContextClassLoader();
+ } catch (SecurityException ex) { }
+ return cl;
+ }
+ });
+ }
/**
* Creates an instance of the specified class using the specified
@@ -41,7 +56,11 @@
if (classLoader == null) {
spiClass = Class.forName(className);
} else {
- spiClass = classLoader.loadClass(className);
+ try {
+ spiClass = Class.forName(className, false, classLoader);
+ } catch (ClassNotFoundException ex) {
+ spiClass = Class.forName(className);
+ }
}
return spiClass.newInstance();
} catch (ClassNotFoundException x) {
@@ -74,12 +93,7 @@
* @exception WebServiceException if there is an error
*/
static Object find(String factoryId, String fallbackClassName) throws ClassNotFoundException {
- ClassLoader classLoader;
- try {
- classLoader = Thread.currentThread().getContextClassLoader();
- } catch (Exception x) {
- throw new ClassNotFoundException(x.toString(), x);
- }
+ ClassLoader classLoader = getContextClassLoader();
String serviceId = "META-INF/services/" + factoryId;
// try to find services in CLASSPATH
diff --git a/src/jsr311-api/src/javax/ws/rs/ext/RuntimeDelegate.java b/src/jsr311-api/src/javax/ws/rs/ext/RuntimeDelegate.java
index 7ee70dc..1fbed8f 100644
--- a/src/jsr311-api/src/javax/ws/rs/ext/RuntimeDelegate.java
+++ b/src/jsr311-api/src/javax/ws/rs/ext/RuntimeDelegate.java
@@ -21,7 +21,6 @@
import java.lang.reflect.ReflectPermission;
import java.net.URL;
-import java.util.concurrent.atomic.AtomicReference;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.Response.ResponseBuilder;
import javax.ws.rs.core.Variant.VariantListBuilder;
@@ -42,13 +41,12 @@
private static final String JAXRS_DEFAULT_RUNTIME_DELEGATE
= "com.sun.ws.rs.ext.RuntimeDelegateImpl";
- private static AtomicReference<RuntimeDelegate> rdr =
- new AtomicReference<RuntimeDelegate>();
-
private static ReflectPermission rp = new ReflectPermission("suppressAccessChecks");
protected RuntimeDelegate() {
}
+
+ private static volatile RuntimeDelegate rd;
/**
* Obtain a RuntimeDelegate instance. If an instance had not already been
@@ -84,39 +82,48 @@
* @return an instance of RuntimeDelegate
*/
public static RuntimeDelegate getInstance() {
- RuntimeDelegate rd = rdr.get();
- if (rd != null)
- return rd;
- synchronized(rdr) {
- rd = rdr.get();
- if (rd != null)
- return rd;
- try {
- Object delegate =
- FactoryFinder.find(JAXRS_RUNTIME_DELEGATE_PROPERTY,
- JAXRS_DEFAULT_RUNTIME_DELEGATE);
- if (!(delegate instanceof RuntimeDelegate)) {
- Class pClass = RuntimeDelegate.class;
- String classnameAsResource = pClass.getName().replace('.', '/') + ".class";
- ClassLoader loader = pClass.getClassLoader();
- if(loader == null) {
- loader = ClassLoader.getSystemClassLoader();
- }
- URL targetTypeURL = loader.getResource(classnameAsResource);
- throw new LinkageError("ClassCastException: attempting to cast" +
- delegate.getClass().getClassLoader().getResource(classnameAsResource) +
- "to" + targetTypeURL.toString() );
- }
- rd = (RuntimeDelegate) delegate;
- } catch (Exception ex) {
- throw new RuntimeException(ex);
- }
- rdr.compareAndSet(null,rd);
- }
- return rdr.get();
+ // Double-check idiom for lazy initialization of fields.
+ RuntimeDelegate result = rd;
+ if (result == null) { // First check (no locking)
+ synchronized(RuntimeDelegate.class) {
+ result = rd;
+ if (result == null) { // Second check (with locking)
+ rd = result = findDelegate();
+ }
+ }
+ }
+ return result;
}
/**
+ * Obtain a RuntimeDelegate instance using the method described in
+ * {@link #getInstance}.
+ * @return an instance of RuntimeDelegate
+ */
+ private static RuntimeDelegate findDelegate() {
+ try {
+ Object delegate =
+ FactoryFinder.find(JAXRS_RUNTIME_DELEGATE_PROPERTY,
+ JAXRS_DEFAULT_RUNTIME_DELEGATE);
+ if (!(delegate instanceof RuntimeDelegate)) {
+ Class pClass = RuntimeDelegate.class;
+ String classnameAsResource = pClass.getName().replace('.', '/') + ".class";
+ ClassLoader loader = pClass.getClassLoader();
+ if(loader == null) {
+ loader = ClassLoader.getSystemClassLoader();
+ }
+ URL targetTypeURL = loader.getResource(classnameAsResource);
+ throw new LinkageError("ClassCastException: attempting to cast" +
+ delegate.getClass().getClassLoader().getResource(classnameAsResource) +
+ "to" + targetTypeURL.toString() );
+ }
+ return (RuntimeDelegate) delegate;
+ } catch (Exception ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ /**
* Set the runtime delegate that will be used by JAX-RS classes. If this method
* is not called prior to {@link #getInstance} then an implementation will
* be sought as described in {@link #getInstance}.
@@ -129,7 +136,9 @@
if (security != null) {
security.checkPermission(rp);
}
- rdr.set(rd);
+ synchronized(RuntimeDelegate.class) {
+ RuntimeDelegate.rd = rd;
+ }
}
/**