NashornLoader.java revision 1502:752ca580b176
1143247Sphantom/*
2143247Sphantom * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
3143247Sphantom * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4143247Sphantom *
5143247Sphantom * This code is free software; you can redistribute it and/or modify it
6143247Sphantom * under the terms of the GNU General Public License version 2 only, as
7143247Sphantom * published by the Free Software Foundation.  Oracle designates this
8143247Sphantom * particular file as subject to the "Classpath" exception as provided
9143247Sphantom * by Oracle in the LICENSE file that accompanied this code.
10143247Sphantom *
11143247Sphantom * This code is distributed in the hope that it will be useful, but WITHOUT
12143247Sphantom * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13143247Sphantom * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14143247Sphantom * version 2 for more details (a copy is included in the LICENSE file that
15143247Sphantom * accompanied this code).
16143247Sphantom *
17143247Sphantom * You should have received a copy of the GNU General Public License version
18143247Sphantom * 2 along with this work; if not, write to the Free Software Foundation,
19143247Sphantom * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20143247Sphantom *
21143247Sphantom * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22143247Sphantom * or visit www.oracle.com if you need additional information or have any
23143247Sphantom * questions.
24143247Sphantom */
25143247Sphantom
26143247Sphantompackage jdk.nashorn.internal.runtime;
27143247Sphantom
28143247Sphantomimport java.io.File;
29143247Sphantomimport java.io.IOException;
30143247Sphantomimport java.net.MalformedURLException;
31143247Sphantomimport java.net.URL;
32143247Sphantomimport java.net.URLClassLoader;
33143247Sphantomimport java.security.CodeSource;
34143247Sphantomimport java.security.Permission;
35143247Sphantomimport java.security.PermissionCollection;
36143247Sphantomimport java.security.Permissions;
37143247Sphantomimport java.security.SecureClassLoader;
38143247Sphantom
39143247Sphantom/**
40143247Sphantom * Superclass for Nashorn class loader classes.
41143247Sphantom */
42143247Sphantomabstract class NashornLoader extends SecureClassLoader {
43143247Sphantom    private static final String OBJECTS_PKG        = "jdk.nashorn.internal.objects";
44143247Sphantom    private static final String RUNTIME_PKG        = "jdk.nashorn.internal.runtime";
45143247Sphantom    private static final String RUNTIME_ARRAYS_PKG = "jdk.nashorn.internal.runtime.arrays";
46143247Sphantom    private static final String RUNTIME_LINKER_PKG = "jdk.nashorn.internal.runtime.linker";
47143247Sphantom    private static final String SCRIPTS_PKG        = "jdk.nashorn.internal.scripts";
48143247Sphantom
49143247Sphantom    private static final Permission[] SCRIPT_PERMISSIONS;
50143247Sphantom
51143247Sphantom    static {
52143247Sphantom        /*
53143247Sphantom         * Generated classes get access to runtime, runtime.linker, objects, scripts packages.
54143247Sphantom         * Note that the actual scripts can not access these because Java.type, Packages
55143247Sphantom         * prevent these restricted packages. And Java reflection and JSR292 access is prevented
56143247Sphantom         * for scripts. In other words, nashorn generated portions of script classes can access
57143247Sphantom         * classes in these implementation packages.
58143247Sphantom         */
59143247Sphantom        SCRIPT_PERMISSIONS = new Permission[] {
60143247Sphantom                new RuntimePermission("accessClassInPackage." + RUNTIME_PKG),
61143247Sphantom                new RuntimePermission("accessClassInPackage." + RUNTIME_LINKER_PKG),
62143247Sphantom                new RuntimePermission("accessClassInPackage." + OBJECTS_PKG),
63143247Sphantom                new RuntimePermission("accessClassInPackage." + SCRIPTS_PKG),
64143247Sphantom                new RuntimePermission("accessClassInPackage." + RUNTIME_ARRAYS_PKG)
65143247Sphantom        };
66143247Sphantom    }
67143247Sphantom
68143247Sphantom    NashornLoader(final ClassLoader parent) {
69143247Sphantom        super(parent);
70143247Sphantom    }
71143247Sphantom
72143247Sphantom    protected static void checkPackageAccess(final String name) {
73143247Sphantom        final int i = name.lastIndexOf('.');
74143247Sphantom        if (i != -1) {
75143247Sphantom            final SecurityManager sm = System.getSecurityManager();
76143247Sphantom            if (sm != null) {
77143247Sphantom                final String pkgName = name.substring(0, i);
78143247Sphantom                switch (pkgName) {
79143247Sphantom                    case RUNTIME_PKG:
80143247Sphantom                    case RUNTIME_ARRAYS_PKG:
81143247Sphantom                    case RUNTIME_LINKER_PKG:
82143247Sphantom                    case OBJECTS_PKG:
83143247Sphantom                    case SCRIPTS_PKG:
84143247Sphantom                        // allow it.
85143247Sphantom                        break;
86143247Sphantom                    default:
87143247Sphantom                        sm.checkPackageAccess(pkgName);
88143247Sphantom                }
89143247Sphantom            }
90143247Sphantom        }
91143247Sphantom    }
92143247Sphantom
93143247Sphantom    @Override
94143247Sphantom    protected PermissionCollection getPermissions(final CodeSource codesource) {
95143247Sphantom        final Permissions permCollection = new Permissions();
96143247Sphantom        for (final Permission perm : SCRIPT_PERMISSIONS) {
97143247Sphantom            permCollection.add(perm);
98143247Sphantom        }
99143247Sphantom        return permCollection;
100143247Sphantom    }
101143247Sphantom
102143247Sphantom    /**
103143247Sphantom     * Create a secure URL class loader for the given classpath
104143247Sphantom     * @param classPath classpath for the loader to search from
105143247Sphantom     * @param parent the parent class loader for the new class loader
106143247Sphantom     * @return the class loader
107143247Sphantom     */
108143247Sphantom    static ClassLoader createClassLoader(final String classPath, final ClassLoader parent) {
109143247Sphantom        final URL[] urls = pathToURLs(classPath);
110143247Sphantom        return URLClassLoader.newInstance(urls, parent);
111143247Sphantom    }
112143247Sphantom
113143247Sphantom    /*
114143247Sphantom     * Utility method for converting a search path string to an array
115143247Sphantom     * of directory and JAR file URLs.
116143247Sphantom     *
117143247Sphantom     * @param path the search path string
118143247Sphantom     * @return the resulting array of directory and JAR file URLs
119143247Sphantom     */
120143247Sphantom    private static URL[] pathToURLs(final String path) {
121143247Sphantom        final String[] components = path.split(File.pathSeparator);
122143247Sphantom        URL[] urls = new URL[components.length];
123143247Sphantom        int count = 0;
124143247Sphantom        while(count < components.length) {
125143247Sphantom            final URL url = fileToURL(new File(components[count]));
126143247Sphantom            if (url != null) {
127143247Sphantom                urls[count++] = url;
128143247Sphantom            }
129143247Sphantom        }
130143247Sphantom        if (urls.length != count) {
131143247Sphantom            final URL[] tmp = new URL[count];
132143247Sphantom            System.arraycopy(urls, 0, tmp, 0, count);
133143247Sphantom            urls = tmp;
134143247Sphantom        }
135143247Sphantom        return urls;
136143247Sphantom    }
137143247Sphantom
138143247Sphantom    /*
139143247Sphantom     * Returns the directory or JAR file URL corresponding to the specified
140143247Sphantom     * local file name.
141143247Sphantom     *
142143247Sphantom     * @param file the File object
143143247Sphantom     * @return the resulting directory or JAR file URL, or null if unknown
144143247Sphantom     */
145143247Sphantom    private static URL fileToURL(final File file) {
146143247Sphantom        String name;
147143247Sphantom        try {
148143247Sphantom            name = file.getCanonicalPath();
149143247Sphantom        } catch (final IOException e) {
150143247Sphantom            name = file.getAbsolutePath();
151143247Sphantom        }
152143247Sphantom        name = name.replace(File.separatorChar, '/');
153143247Sphantom        if (!name.startsWith("/")) {
154143247Sphantom            name = "/" + name;
155143247Sphantom        }
156143247Sphantom        // If the file does not exist, then assume that it's a directory
157143247Sphantom        if (!file.isFile()) {
158143247Sphantom            name += "/";
159143247Sphantom        }
160143247Sphantom        try {
161143247Sphantom            return new URL("file", "", name);
162143247Sphantom        } catch (final MalformedURLException e) {
163143247Sphantom            throw new IllegalArgumentException("file");
164143247Sphantom        }
165143247Sphantom    }
166143247Sphantom}
167143247Sphantom
168143247Sphantom