8019622: (sl) ServiceLoader.next incorrect when creation and usages are in different contexts
authoralanb
Thu, 04 Jul 2013 14:38:44 +0100
changeset 18777 cb1cc62972b8
parent 18776 c17100862d86
child 18778 7214a903b084
8019622: (sl) ServiceLoader.next incorrect when creation and usages are in different contexts Reviewed-by: mchung, ahgross, forax, psandoz
jdk/src/share/classes/java/util/ServiceLoader.java
--- a/jdk/src/share/classes/java/util/ServiceLoader.java	Wed Jul 03 17:08:14 2013 -0700
+++ b/jdk/src/share/classes/java/util/ServiceLoader.java	Thu Jul 04 14:38:44 2013 +0100
@@ -30,6 +30,9 @@
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.net.URL;
+import java.security.AccessController;
+import java.security.AccessControlContext;
+import java.security.PrivilegedAction;
 import java.util.ArrayList;
 import java.util.Enumeration;
 import java.util.Iterator;
@@ -185,10 +188,13 @@
     private static final String PREFIX = "META-INF/services/";
 
     // The class or interface representing the service being loaded
-    private Class<S> service;
+    private final Class<S> service;
 
     // The class loader used to locate, load, and instantiate providers
-    private ClassLoader loader;
+    private final ClassLoader loader;
+
+    // The access control context taken when the ServiceLoader is created
+    private final AccessControlContext acc;
 
     // Cached providers, in instantiation order
     private LinkedHashMap<String,S> providers = new LinkedHashMap<>();
@@ -215,6 +221,7 @@
     private ServiceLoader(Class<S> svc, ClassLoader cl) {
         service = Objects.requireNonNull(svc, "Service interface cannot be null");
         loader = (cl == null) ? ClassLoader.getSystemClassLoader() : cl;
+        acc = (System.getSecurityManager() != null) ? AccessController.getContext() : null;
         reload();
     }
 
@@ -327,7 +334,7 @@
             this.loader = loader;
         }
 
-        public boolean hasNext() {
+        private boolean hasNextService() {
             if (nextName != null) {
                 return true;
             }
@@ -352,10 +359,9 @@
             return true;
         }
 
-        public S next() {
-            if (!hasNext()) {
+        private S nextService() {
+            if (!hasNextService())
                 throw new NoSuchElementException();
-            }
             String cn = nextName;
             nextName = null;
             Class<?> c = null;
@@ -381,6 +387,28 @@
             throw new Error();          // This cannot happen
         }
 
+        public boolean hasNext() {
+            if (acc == null) {
+                return hasNextService();
+            } else {
+                PrivilegedAction<Boolean> action = new PrivilegedAction<Boolean>() {
+                    public Boolean run() { return hasNextService(); }
+                };
+                return AccessController.doPrivileged(action, acc);
+            }
+        }
+
+        public S next() {
+            if (acc == null) {
+                return nextService();
+            } else {
+                PrivilegedAction<S> action = new PrivilegedAction<S>() {
+                    public S run() { return nextService(); }
+                };
+                return AccessController.doPrivileged(action, acc);
+            }
+        }
+
         public void remove() {
             throw new UnsupportedOperationException();
         }