NashornLoader.java revision 1643:133ea8746b37
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 */
25
26package jdk.nashorn.internal.runtime;
27
28import java.io.File;
29import java.io.IOException;
30import java.net.MalformedURLException;
31import java.net.URL;
32import java.net.URLClassLoader;
33import java.lang.reflect.Module;
34import java.security.CodeSource;
35import java.security.Permission;
36import java.security.PermissionCollection;
37import java.security.Permissions;
38import java.security.SecureClassLoader;
39import java.util.HashSet;
40import java.util.Set;
41import jdk.internal.module.Modules;
42
43/**
44 * Superclass for Nashorn class loader classes.
45 */
46abstract class NashornLoader extends SecureClassLoader {
47    protected static final String OBJECTS_PKG        = "jdk.nashorn.internal.objects";
48    protected static final String RUNTIME_PKG        = "jdk.nashorn.internal.runtime";
49    protected static final String RUNTIME_ARRAYS_PKG = "jdk.nashorn.internal.runtime.arrays";
50    protected static final String RUNTIME_LINKER_PKG = "jdk.nashorn.internal.runtime.linker";
51    protected static final String SCRIPTS_PKG        = "jdk.nashorn.internal.scripts";
52    protected static final String OBJECTS_PKG_INTERNAL        = "jdk/nashorn/internal/objects";
53    protected static final String RUNTIME_PKG_INTERNAL        = "jdk/nashorn/internal/runtime";
54    protected static final String RUNTIME_ARRAYS_PKG_INTERNAL = "jdk/nashorn/internal/runtime/arrays";
55    protected static final String RUNTIME_LINKER_PKG_INTERNAL = "jdk/nashorn/internal/runtime/linker";
56    protected static final String SCRIPTS_PKG_INTERNAL        = "jdk/nashorn/internal/scripts";
57
58    protected static final Module nashornModule = NashornLoader.class.getModule();
59
60    private static final Permission[] SCRIPT_PERMISSIONS;
61
62    private static final Set<String> scriptsPkgSet = new HashSet<>();
63
64    static {
65        scriptsPkgSet.add(SCRIPTS_PKG);
66
67        /*
68         * Generated classes get access to runtime, runtime.linker, objects, scripts packages.
69         * Note that the actual scripts can not access these because Java.type, Packages
70         * prevent these restricted packages. And Java reflection and JSR292 access is prevented
71         * for scripts. In other words, nashorn generated portions of script classes can access
72         * classes in these implementation packages.
73         */
74        SCRIPT_PERMISSIONS = new Permission[] {
75                new RuntimePermission("accessClassInPackage." + RUNTIME_PKG),
76                new RuntimePermission("accessClassInPackage." + RUNTIME_LINKER_PKG),
77                new RuntimePermission("accessClassInPackage." + OBJECTS_PKG),
78                new RuntimePermission("accessClassInPackage." + SCRIPTS_PKG),
79                new RuntimePermission("accessClassInPackage." + RUNTIME_ARRAYS_PKG)
80        };
81    }
82
83    NashornLoader(final ClassLoader parent) {
84        super(parent);
85    }
86
87    protected static Module defineModule(final String moduleName, final ClassLoader loader) {
88        return Modules.defineModule(loader, moduleName, scriptsPkgSet);
89    }
90
91    protected static void addReadsModule(final Module from, final Module to) {
92        Modules.addReads(from, to);
93    }
94
95    protected static void addModuleExports(final Module from, final String pkg, final Module to) {
96        if (to == null) {
97            Modules.addExportsToAll(from, pkg);
98        } else {
99            Modules.addExports(from, pkg, to);
100        }
101    }
102
103    protected static void checkPackageAccess(final String name) {
104        final int i = name.lastIndexOf('.');
105        if (i != -1) {
106            final SecurityManager sm = System.getSecurityManager();
107            if (sm != null) {
108                final String pkgName = name.substring(0, i);
109                switch (pkgName) {
110                    case RUNTIME_PKG:
111                    case RUNTIME_ARRAYS_PKG:
112                    case RUNTIME_LINKER_PKG:
113                    case OBJECTS_PKG:
114                    case SCRIPTS_PKG:
115                        // allow it.
116                        break;
117                    default:
118                        sm.checkPackageAccess(pkgName);
119                }
120            }
121        }
122    }
123
124    @Override
125    protected PermissionCollection getPermissions(final CodeSource codesource) {
126        final Permissions permCollection = new Permissions();
127        for (final Permission perm : SCRIPT_PERMISSIONS) {
128            permCollection.add(perm);
129        }
130        return permCollection;
131    }
132
133    /**
134     * Create a secure URL class loader for the given classpath
135     * @param classPath classpath for the loader to search from
136     * @param parent the parent class loader for the new class loader
137     * @return the class loader
138     */
139    static ClassLoader createClassLoader(final String classPath, final ClassLoader parent) {
140        final URL[] urls = pathToURLs(classPath);
141        return URLClassLoader.newInstance(urls, parent);
142    }
143
144    /*
145     * Utility method for converting a search path string to an array
146     * of directory and JAR file URLs.
147     *
148     * @param path the search path string
149     * @return the resulting array of directory and JAR file URLs
150     */
151    private static URL[] pathToURLs(final String path) {
152        final String[] components = path.split(File.pathSeparator);
153        URL[] urls = new URL[components.length];
154        int count = 0;
155        while(count < components.length) {
156            final URL url = fileToURL(new File(components[count]));
157            if (url != null) {
158                urls[count++] = url;
159            }
160        }
161        if (urls.length != count) {
162            final URL[] tmp = new URL[count];
163            System.arraycopy(urls, 0, tmp, 0, count);
164            urls = tmp;
165        }
166        return urls;
167    }
168
169    /*
170     * Returns the directory or JAR file URL corresponding to the specified
171     * local file name.
172     *
173     * @param file the File object
174     * @return the resulting directory or JAR file URL, or null if unknown
175     */
176    private static URL fileToURL(final File file) {
177        String name;
178        try {
179            name = file.getCanonicalPath();
180        } catch (final IOException e) {
181            name = file.getAbsolutePath();
182        }
183        name = name.replace(File.separatorChar, '/');
184        if (!name.startsWith("/")) {
185            name = "/" + name;
186        }
187        // If the file does not exist, then assume that it's a directory
188        if (!file.isFile()) {
189            name += "/";
190        }
191        try {
192            return new URL("file", "", name);
193        } catch (final MalformedURLException e) {
194            throw new IllegalArgumentException("file");
195        }
196    }
197}
198
199