Tue, 12 Mar 2013 18:12:42 +0530
8009757: Package access clean up and refactoring
Reviewed-by: jlaskey, lagergren, attila
1 /*
2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
26 package jdk.nashorn.internal.runtime;
28 import java.io.File;
29 import java.io.IOException;
30 import java.net.MalformedURLException;
31 import java.net.URL;
32 import java.net.URLClassLoader;
33 import java.security.CodeSource;
34 import java.security.Permission;
35 import java.security.PermissionCollection;
36 import java.security.Permissions;
37 import java.security.SecureClassLoader;
38 import jdk.nashorn.tools.Shell;
40 /**
41 * Superclass for Nashorn class loader classes. This stores Context
42 * instance as an instance field. The current context can be
43 * efficiently accessed from a given Class via it's ClassLoader.
44 *
45 */
46 abstract class NashornLoader extends SecureClassLoader {
47 private static final String OBJECTS_PKG = "jdk.nashorn.internal.objects";
48 private static final String RUNTIME_PKG = "jdk.nashorn.internal.runtime";
49 private static final String RUNTIME_LINKER_PKG = "jdk.nashorn.internal.runtime.linker";
50 private static final String SCRIPTS_PKG = "jdk.nashorn.internal.scripts";
52 private static final Permission[] SCRIPT_PERMISSIONS;
53 static {
54 SCRIPT_PERMISSIONS = new Permission[4];
56 /*
57 * Generated classes get access to runtime, runtime.linker, objects, scripts packages.
58 * Note that the actual scripts can not access these because Java.type, Packages
59 * prevent these restricted packages. And Java reflection and JSR292 access is prevented
60 * for scripts. In other words, nashorn generated portions of script classes can access
61 * clases in these implementation packages.
62 */
63 SCRIPT_PERMISSIONS[0] = new RuntimePermission("accessClassInPackage." + RUNTIME_PKG);
64 SCRIPT_PERMISSIONS[1] = new RuntimePermission("accessClassInPackage." + RUNTIME_LINKER_PKG);
65 SCRIPT_PERMISSIONS[2] = new RuntimePermission("accessClassInPackage." + OBJECTS_PKG);
66 SCRIPT_PERMISSIONS[3] = new RuntimePermission("accessClassInPackage." + SCRIPTS_PKG);
67 }
69 private final Context context;
71 final Context getContext() {
72 return context;
73 }
75 NashornLoader(final ClassLoader parent, final Context context) {
76 super(parent);
77 this.context = context;
78 }
81 /**
82 * Called by subclass after package access check is done
83 * @param name name of the class to be loaded
84 * @param resolve whether the class should be resolved or not
85 * @return Class object
86 * @throws ClassNotFoundException if class cannot be loaded
87 */
88 protected final Class<?> loadClassTrusted(final String name, final boolean resolve) throws ClassNotFoundException {
89 return super.loadClass(name, resolve);
90 }
92 protected static void checkPackageAccess(final String name) {
93 final int i = name.lastIndexOf('.');
94 if (i != -1) {
95 final SecurityManager sm = System.getSecurityManager();
96 if (sm != null) {
97 final String pkgName = name.substring(0, i);
98 switch (pkgName) {
99 case RUNTIME_PKG:
100 case RUNTIME_LINKER_PKG:
101 case OBJECTS_PKG:
102 case SCRIPTS_PKG:
103 // allow it.
104 break;
105 default:
106 sm.checkPackageAccess(pkgName);
107 }
108 }
109 }
110 }
112 @Override
113 protected PermissionCollection getPermissions(CodeSource codesource) {
114 final Permissions permCollection = new Permissions();
115 for (final Permission perm : SCRIPT_PERMISSIONS) {
116 permCollection.add(perm);
117 }
118 return permCollection;
119 }
121 /**
122 * Create a secure URL class loader for the given classpath
123 * @param classPath classpath for the loader to search from
124 * @return the class loader
125 */
126 static ClassLoader createClassLoader(final String classPath) {
127 final ClassLoader parent = Shell.class.getClassLoader();
128 final URL[] urls = pathToURLs(classPath);
129 return URLClassLoader.newInstance(urls, parent);
130 }
132 /*
133 * Utility method for converting a search path string to an array
134 * of directory and JAR file URLs.
135 *
136 * @param path the search path string
137 * @return the resulting array of directory and JAR file URLs
138 */
139 private static URL[] pathToURLs(final String path) {
140 final String[] components = path.split(File.pathSeparator);
141 URL[] urls = new URL[components.length];
142 int count = 0;
143 while(count < components.length) {
144 final URL url = fileToURL(new File(components[count]));
145 if (url != null) {
146 urls[count++] = url;
147 }
148 }
149 if (urls.length != count) {
150 final URL[] tmp = new URL[count];
151 System.arraycopy(urls, 0, tmp, 0, count);
152 urls = tmp;
153 }
154 return urls;
155 }
157 /*
158 * Returns the directory or JAR file URL corresponding to the specified
159 * local file name.
160 *
161 * @param file the File object
162 * @return the resulting directory or JAR file URL, or null if unknown
163 */
164 private static URL fileToURL(final File file) {
165 String name;
166 try {
167 name = file.getCanonicalPath();
168 } catch (final IOException e) {
169 name = file.getAbsolutePath();
170 }
171 name = name.replace(File.separatorChar, '/');
172 if (!name.startsWith("/")) {
173 name = "/" + name;
174 }
175 // If the file does not exist, then assume that it's a directory
176 if (!file.isFile()) {
177 name = name + "/";
178 }
179 try {
180 return new URL("file", "", name);
181 } catch (final MalformedURLException e) {
182 throw new IllegalArgumentException("file");
183 }
184 }
185 }