1/*
2 * Copyright (c) 2015, 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
24import java.io.File;
25import java.io.IOException;
26import java.net.URL;
27import java.nio.file.Files;
28import java.security.AllPermission;
29import java.security.Permissions;
30import java.security.ProtectionDomain;
31import java.util.Arrays;
32import java.util.HashMap;
33import java.util.List;
34import java.util.Map;
35
36
37/**
38 * A custom ClassLoader to load the concrete LoggerFinder class
39 * with all permissions. The CustomSystemClassLoader class must be
40 * in the BCL, otherwise when system classes - such as
41 * ZoneDateTime try to load their resource bundle a MissingResourceBundle
42 * caused by a SecurityException may be thrown, as the CustomSystemClassLoader
43 * code base will be found in the stack called by doPrivileged.
44 *
45 * @author danielfuchs
46 */
47public class CustomSystemClassLoader extends ClassLoader {
48
49
50    final List<String> finderClassNames =
51            Arrays.asList("LoggerFinderLoaderTest$BaseLoggerFinder",
52                    "LoggerFinderLoaderTest$BaseLoggerFinder2");
53    final Map<String, Class<?>> finderClasses = new HashMap<>();
54    Class<?> testLoggerFinderClass;
55
56    public CustomSystemClassLoader() {
57        super();
58    }
59    public CustomSystemClassLoader(ClassLoader parent) {
60        super(parent);
61    }
62
63    private Class<?> defineFinderClass(String name)
64        throws ClassNotFoundException {
65        final Object obj = getClassLoadingLock(name);
66        synchronized(obj) {
67            if (finderClasses.get(name) != null) return finderClasses.get(name);
68            if (testLoggerFinderClass == null) {
69                // Hack: we  load testLoggerFinderClass to get its code source.
70                //       we can't use this.getClass() since we are in the boot.
71                testLoggerFinderClass = super.loadClass("LoggerFinderLoaderTest$TestLoggerFinder");
72            }
73            URL url = testLoggerFinderClass.getProtectionDomain().getCodeSource().getLocation();
74            File file = new File(url.getPath(), name+".class");
75            if (file.canRead()) {
76                try {
77                    byte[] b = Files.readAllBytes(file.toPath());
78                    Permissions perms = new Permissions();
79                    perms.add(new AllPermission());
80                    Class<?> finderClass = defineClass(
81                            name, b, 0, b.length, new ProtectionDomain(
82                            this.getClass().getProtectionDomain().getCodeSource(),
83                            perms));
84                    System.out.println("Loaded " + name);
85                    finderClasses.put(name, finderClass);
86                    return finderClass;
87                } catch (Throwable ex) {
88                    ex.printStackTrace();
89                    throw new ClassNotFoundException(name, ex);
90                }
91            } else {
92                throw new ClassNotFoundException(name,
93                        new IOException(file.toPath() + ": can't read"));
94            }
95        }
96    }
97
98    @Override
99    public synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
100        if (finderClassNames.contains(name)) {
101            Class<?> c = defineFinderClass(name);
102            if (resolve) {
103                resolveClass(c);
104            }
105            return c;
106        }
107        return super.loadClass(name, resolve);
108    }
109
110    @Override
111    protected Class<?> findClass(String name) throws ClassNotFoundException {
112        if (finderClassNames.contains(name)) {
113            return defineFinderClass(name);
114        }
115        return super.findClass(name);
116    }
117
118}
119