1/*
2 * Copyright (c) 2005, 2008, 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.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
24
25package sun.jvm.hotspot;
26
27import java.io.*;
28import java.net.*;
29import java.util.*;
30import java.security.*;
31
32/**
33 * SA uses native debugger back-end library - libsaproc.so on Unix platforms.
34 * Starting from 5.0, in Solaris & Linux JDK "libsaproc.so" is shipped with JDK
35 * and is kept jre/lib/cpu directory (where all other JDK platform libraries
36 * are kept). This implies that always that jre copy of libsaproc.so will be
37 * used and the copy of libsaproc.so built from SA sources here will not
38 * be used at all. We can override libsaproc.so using this class loader
39 * as System class loader using "java.system.class.loader" property. This
40 * class loader loads classes paths specified paths using the System property
41 * "java.class.path". Because, this class loader loads SA debugger classes
42 * (among other classes), JVM calls findLibrary override here. In this
43 * findLibrary, we first check the library in the directories specified through
44 * "sa.library.path" System property. This way updated/latest SA native library
45 * can be loaded instead of the one from JDK's jre/lib directory.
46 */
47public class SALauncherLoader extends URLClassLoader {
48
49    /**
50     * Checks native libraries under directories specified using
51     * the System property "sa.library.path".
52     */
53    public String findLibrary(String name) {
54        name = System.mapLibraryName(name);
55        for (int i = 0; i < libpaths.length; i++) {
56            File file = new File(new File(libpaths[i]), name);
57            if (file.exists()) {
58                return file.getAbsolutePath();
59            }
60        }
61        return null;
62    }
63
64    public SALauncherLoader(ClassLoader parent) {
65        super(getClassPath(), parent);
66        String salibpath = System.getProperty("sa.library.path");
67        if (salibpath != null) {
68            libpaths = salibpath.split(File.pathSeparator);
69        } else {
70            libpaths = new String[0];
71        }
72    }
73
74    /**
75     * Override loadClass so we can checkPackageAccess.
76     */
77    public synchronized Class loadClass(String name, boolean resolve)
78            throws ClassNotFoundException {
79        int i = name.lastIndexOf('.');
80        if (i != -1) {
81            SecurityManager sm = System.getSecurityManager();
82            if (sm != null) {
83                sm.checkPackageAccess(name.substring(0, i));
84            }
85        }
86
87        Class clazz = findLoadedClass(name);
88        if (clazz != null) return clazz;
89
90        /*
91         * NOTE: Unlike 'usual' class loaders, we do *not* delegate to
92         * the parent loader first. We attempt to load the class
93         * ourselves first and use parent loader only if we can't load.
94         * This is because the parent of this loader is 'default'
95         * System loader that can 'see' all SA classes in classpath and
96         * so will load those if delegated. And if parent loads SA classes,
97         * then JVM won't call findNative override in this class.
98         */
99        try {
100            return findClass(name);
101        } catch (ClassNotFoundException cnfe) {
102            return (super.loadClass(name, resolve));
103        }
104    }
105
106    /**
107     * allow any classes loaded from classpath to exit the VM.
108     */
109    protected PermissionCollection getPermissions(CodeSource codesource) {
110        PermissionCollection perms = super.getPermissions(codesource);
111        perms.add(new RuntimePermission("exitVM"));
112        return perms;
113    }
114
115    //-- Internals only below this point
116
117    private String[] libpaths;
118
119    private static URL[] getClassPath() {
120        final String s = System.getProperty("java.class.path");
121        final File[] path = (s == null) ? new File[0] : getClassPath(s);
122
123        return pathToURLs(path);
124    }
125
126    private static URL[] pathToURLs(File[] path) {
127        URL[] urls = new URL[path.length];
128        for (int i = 0; i < path.length; i++) {
129            urls[i] = getFileURL(path[i]);
130        }
131        return urls;
132    }
133
134    private static File[] getClassPath(String cp) {
135        String[] tmp = cp.split(File.pathSeparator);
136        File[] paths = new File[tmp.length];
137        for (int i = 0; i < paths.length; i++) {
138            paths[i] = new File(tmp[i].equals("")? "." : tmp[i]);
139        }
140        return paths;
141    }
142
143    private static URL getFileURL(File file) {
144        try {
145            file = file.getCanonicalFile();
146        } catch (IOException e) {
147            e.printStackTrace();
148        }
149
150        try {
151            return file.toURI().toURL();
152        } catch (MalformedURLException mue) {
153            throw new InternalError(mue.getMessage());
154        }
155    }
156}
157