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