changeset 5992:8f7c7ce8f288

RT-32585: Enhance FX loading
author Martin Soch <Martin.Soch@oracle.com>
date Thu, 26 Sep 2013 21:04:03 +0200
parents c0dd6c47fec3
children 90033f25c0a8
files modules/fxml/src/main/java/com/sun/javafx/fxml/BeanAdapter.java modules/fxml/src/main/java/javafx/fxml/FXMLLoader.java
diffstat 2 files changed, 73 insertions(+), 28 deletions(-) [+]
line wrap: on
line diff
--- a/modules/fxml/src/main/java/com/sun/javafx/fxml/BeanAdapter.java	Wed Sep 18 08:09:19 2013 -0700
+++ b/modules/fxml/src/main/java/com/sun/javafx/fxml/BeanAdapter.java	Thu Sep 26 21:04:03 2013 +0200
@@ -58,8 +58,6 @@
 public class BeanAdapter extends AbstractMap<String, Object> {
     private final Object bean;
 
-    private static ClassLoader contextClassLoader;
-    
     private static HashMap<Class<?>, HashMap<String, LinkedList<Method>>> globalMethodCache =
         new HashMap<Class<?>, HashMap<String, LinkedList<Method>>>();
 
@@ -69,14 +67,7 @@
     public static final String PROPERTY_SUFFIX = "Property";
 
     public static final String VALUE_OF_METHOD_NAME = "valueOf";
-    
-    static {
-        contextClassLoader = Thread.currentThread().getContextClassLoader();
 
-        if (contextClassLoader == null) {
-            throw new NullPointerException();
-        }
-    }
     /**
      * Creates a new Bean adapter.
      *
@@ -462,10 +453,11 @@
         } else if (type == Class.class) {
             try {   
                 ReflectUtil.checkPackageAccess(value.toString());
+                final ClassLoader cl = Thread.currentThread().getContextClassLoader();
                 coercedValue = Class.forName(
                         value.toString(), 
                         false, 
-                        BeanAdapter.contextClassLoader);
+                        cl);
             } catch (ClassNotFoundException exception) {
                 throw new IllegalArgumentException(exception);
             }
--- a/modules/fxml/src/main/java/javafx/fxml/FXMLLoader.java	Wed Sep 18 08:09:19 2013 -0700
+++ b/modules/fxml/src/main/java/javafx/fxml/FXMLLoader.java	Thu Sep 26 21:04:03 2013 +0200
@@ -39,6 +39,7 @@
 import java.lang.reflect.Type;
 import java.net.URL;
 import java.nio.charset.Charset;
+import java.security.AllPermission;
 import java.util.AbstractMap;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -52,6 +53,7 @@
 
 import com.sun.javafx.fxml.*;
 import javafx.beans.DefaultProperty;
+import javafx.beans.InvalidationListener;
 import javafx.beans.property.Property;
 import javafx.beans.value.ChangeListener;
 import javafx.beans.value.ObservableValue;
@@ -85,11 +87,13 @@
 import java.util.EnumMap;
 import java.util.Locale;
 import java.util.StringTokenizer;
-import javafx.beans.InvalidationListener;
+import sun.reflect.CallerSensitive;
+import sun.reflect.Reflection;
 import sun.reflect.misc.ConstructorUtil;
 import sun.reflect.misc.FieldUtil;
 import sun.reflect.misc.MethodUtil;
 import sun.reflect.misc.ReflectUtil;
+import sun.security.util.SecurityConstants;
 
 /**
  * Loads an object hierarchy from an XML document.
@@ -381,7 +385,7 @@
                     return aValue;
                 } else {
                         if (aValue.charAt(0) == '/') {
-                            final URL res = classLoader.getResource(aValue.substring(1));
+                            final URL res = getClassLoader().getResource(aValue.substring(1));
                             if (res == null) {
                                 throw new LoadException("Invalid resource: " + aValue + " not found on the classpath");
                             }
@@ -907,7 +911,7 @@
                     if (!staticLoad) {
                         Class<?> type;
                         try {
-                            type = classLoader.loadClass(value);
+                            type = getClassLoader().loadClass(value);
                         } catch (ClassNotFoundException exception) {
                             throw new LoadException(exception);
                         }
@@ -1097,8 +1101,9 @@
             }
 
             URL location;
+            final ClassLoader cl = getClassLoader();
             if (source.charAt(0) == '/') {
-                location = classLoader.getResource(source.substring(1));
+                location = cl.getResource(source.substring(1));
             } else {
                 if (FXMLLoader.this.location == null) {
                     throw new LoadException("Base location is undefined.");
@@ -1119,7 +1124,7 @@
                         fxmlLoader.location.toExternalForm(),
                         FXMLLoader.this.location.toExternalForm()));
             }
-            fxmlLoader.setClassLoader(classLoader);
+            fxmlLoader.setClassLoader(cl);
             fxmlLoader.setStaticLoad(staticLoad);
 
             Object value = fxmlLoader.load();
@@ -1468,9 +1473,10 @@
 
                 String extension = source.substring(i + 1);
                 ScriptEngine scriptEngine;
+                final ClassLoader cl = getClassLoader();
                 ClassLoader oldLoader = Thread.currentThread().getContextClassLoader();
                 try {
-                    Thread.currentThread().setContextClassLoader(classLoader);
+                    Thread.currentThread().setContextClassLoader(cl);
                     ScriptEngineManager scriptEngineManager = getScriptEngineManager();
                     scriptEngine = scriptEngineManager.getEngineByExtension(extension);
                 } finally {
@@ -1485,7 +1491,7 @@
                 try {
                     URL location;
                     if (source.charAt(0) == '/') {
-                        location = classLoader.getResource(source.substring(1));
+                        location = cl.getResource(source.substring(1));
                     } else {
                         if (FXMLLoader.this.location == null) {
                             throw new LoadException("Base location is undefined.");
@@ -1741,7 +1747,7 @@
 
     private final LinkedList<FXMLLoader> loaders;
 
-    private ClassLoader classLoader = defaultClassLoader;
+    private ClassLoader classLoader = null;
     private boolean staticLoad = false;
     private LoadListener loadListener = null;
 
@@ -1762,7 +1768,7 @@
 
     private ScriptEngineManager scriptEngineManager = null;
 
-    private static ClassLoader defaultClassLoader;
+    private static ClassLoader defaultClassLoader = null;
 
     private static final Pattern extraneousWhitespacePattern = Pattern.compile("\\s+");
 
@@ -1873,12 +1879,6 @@
     public static final String FX_NAMESPACE_VERSION = "1";
 
     static {
-        defaultClassLoader = Thread.currentThread().getContextClassLoader();
-
-        if (defaultClassLoader == null) {
-            throw new NullPointerException();
-        }
-
         JAVAFX_VERSION = AccessController.doPrivileged(new PrivilegedAction<String>() {
             @Override
             public String run() {
@@ -2185,7 +2185,15 @@
      * Returns the classloader used by this serializer.
      * @since JavaFX 2.1
      */
+    @CallerSensitive
     public ClassLoader getClassLoader() {
+        if (classLoader == null) {
+            final SecurityManager sm = System.getSecurityManager();
+            final Class caller = (sm != null) ?
+                    Reflection.getCallerClass() :
+                    null;
+            return getDefaultClassLoader(caller);
+        }
         return classLoader;
     }
 
@@ -2778,7 +2786,7 @@
 
     // TODO Rename to loadType() when deprecated static version is removed
     private Class<?> loadTypeForPackage(String packageName, String className) throws ClassNotFoundException {
-        return classLoader.loadClass(packageName + "." + className.replace('.', '$'));
+        return getClassLoader().loadClass(packageName + "." + className.replace('.', '$'));
     }
 
     private Map<String, Field> getControllerFields() throws LoadException {
@@ -2971,15 +2979,56 @@
      */
     public static Class<?> loadType(String className) throws ClassNotFoundException {
         ReflectUtil.checkPackageAccess(className);
-        return Class.forName(className, true, defaultClassLoader);
+        return Class.forName(className, true, getDefaultClassLoader());
+    }
+
+    private static boolean needsClassLoaderPermissionCheck(ClassLoader from, ClassLoader to) {
+        if (from == to) {
+            return false;
+        }
+        if (from == null) {
+            return false;
+        }
+        if (to == null) {
+            return true;
+        }
+        ClassLoader acl = to;
+        do {
+            acl = acl.getParent();
+            if (from == acl) {
+                return false;
+            }
+        } while (acl != null);
+        return true;
+    }
+
+    private static ClassLoader getDefaultClassLoader(Class caller) {
+        if (defaultClassLoader == null) {
+            final SecurityManager sm = System.getSecurityManager();
+            if (sm != null) {
+                final ClassLoader callerClassLoader = (caller != null) ?
+                        caller.getClassLoader() :
+                        null;
+                if (needsClassLoaderPermissionCheck(callerClassLoader, FXMLLoader.class.getClassLoader())) {
+                    sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
+                }
+            }
+            return Thread.currentThread().getContextClassLoader();
+        }
+        return defaultClassLoader;
     }
 
     /**
      * Returns the default class loader.
      * @since JavaFX 2.1
      */
+    @CallerSensitive
     public static ClassLoader getDefaultClassLoader() {
-        return defaultClassLoader;
+        final SecurityManager sm = System.getSecurityManager();
+        final Class caller = (sm != null) ?
+                Reflection.getCallerClass() :
+                null;
+        return getDefaultClassLoader(caller);
     }
 
     /**
@@ -2993,6 +3042,10 @@
         if (defaultClassLoader == null) {
             throw new NullPointerException();
         }
+        final SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkPermission(new AllPermission());
+        }
 
         FXMLLoader.defaultClassLoader = defaultClassLoader;
     }