1// © 2016 and later: Unicode, Inc. and others.
2// License & terms of use: http://www.unicode.org/copyright.html#License
3/*
4 *******************************************************************************
5 * Copyright (C) 2015, International Business Machines Corporation and
6 * others. All Rights Reserved.
7 *******************************************************************************
8 */
9package com.ibm.icu.impl;
10
11import java.security.AccessController;
12import java.security.PrivilegedAction;
13
14
15/**
16 * This utility class is used for resolving a right ClassLoader from
17 * a given class. getClassLoader always returns a non-null ClassLoader
18 * even a class is loaded through the bootstrap class loader of JRE.
19 */
20public class ClassLoaderUtil {
21
22    private static class BootstrapClassLoader extends ClassLoader {
23        BootstrapClassLoader() {
24            // Object.class.getClassLoader() may return null.
25            //
26            // On Android, the behavior of super(null) is not guaranteed,
27            // but Object.class.getClassLoader() actually returns the
28            // bootstrap class loader. Note that we probably do not reach
29            // this constructor on Android, because ClassLoaderUtil.getClassLoader()
30            // should get non-null ClassLoader before calling
31            // ClassLoaderUtil.getBootstrapClassLoader().
32            //
33            // On other common JREs (such as Oracle, OpenJDK),
34            // Object.class.getClassLoader() returns null, but
35            // super(null) is commonly used for accessing the bootstrap
36            // class loader.
37            super(Object.class.getClassLoader());
38        }
39    }
40
41    private static volatile ClassLoader BOOTSTRAP_CLASSLOADER;
42
43    /**
44     * Lazily create a singleton BootstrapClassLoader.
45     * This class loader might be necessary when ICU4J classes are
46     * initialized by bootstrap class loader.
47     *
48     * @return The BootStrapClassLoader singleton instance
49     */
50    private static ClassLoader getBootstrapClassLoader() {
51        if (BOOTSTRAP_CLASSLOADER == null) {
52            synchronized(ClassLoaderUtil.class) {
53                if (BOOTSTRAP_CLASSLOADER == null) {
54                    ClassLoader cl = null;
55                    if (System.getSecurityManager() != null) {
56                        cl = AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
57                            @Override
58                            public BootstrapClassLoader run() {
59                                return new BootstrapClassLoader();
60                            }
61                        });
62                    } else {
63                        cl = new BootstrapClassLoader();
64                    }
65                    BOOTSTRAP_CLASSLOADER = cl;
66                }
67            }
68        }
69        return BOOTSTRAP_CLASSLOADER;
70    }
71
72
73    /**
74     * Returns the class loader used for loading the specified class.
75     * @param cls The class
76     * @return the class loader
77     */
78    public static ClassLoader getClassLoader(Class<?> cls) {
79        ClassLoader cl = cls.getClassLoader();
80        if (cl == null) {
81            cl = getClassLoader();
82        }
83        return cl;
84    }
85
86    /**
87     * Returns a fallback class loader.
88     * @return A class loader
89     */
90    public static ClassLoader getClassLoader() {
91        ClassLoader cl = Thread.currentThread().getContextClassLoader();
92        if (cl == null) {
93            cl = ClassLoader.getSystemClassLoader();
94            if (cl == null) {
95                // When this method is called for initializing a ICU4J class
96                // during bootstrap, cl might be still null (other than Android?).
97                // In this case, we want to use the bootstrap class loader.
98                cl = getBootstrapClassLoader();
99            }
100        }
101        return cl;
102    }
103}
104