// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html#License
/*
 *******************************************************************************
 * Copyright (C) 2015, International Business Machines Corporation and
 * others. All Rights Reserved.
 *******************************************************************************
 */
package com.ibm.icu.impl;

import java.security.AccessController;
import java.security.PrivilegedAction;


/**
 * This utility class is used for resolving a right ClassLoader from
 * a given class. getClassLoader always returns a non-null ClassLoader
 * even a class is loaded through the bootstrap class loader of JRE.
 */
public class ClassLoaderUtil {

    private static class BootstrapClassLoader extends ClassLoader {
        BootstrapClassLoader() {
            // Object.class.getClassLoader() may return null.
            //
            // On Android, the behavior of super(null) is not guaranteed,
            // but Object.class.getClassLoader() actually returns the
            // bootstrap class loader. Note that we probably do not reach
            // this constructor on Android, because ClassLoaderUtil.getClassLoader()
            // should get non-null ClassLoader before calling
            // ClassLoaderUtil.getBootstrapClassLoader().
            //
            // On other common JREs (such as Oracle, OpenJDK),
            // Object.class.getClassLoader() returns null, but
            // super(null) is commonly used for accessing the bootstrap
            // class loader.
            super(Object.class.getClassLoader());
        }
    }

    private static volatile ClassLoader BOOTSTRAP_CLASSLOADER;

    /**
     * Lazily create a singleton BootstrapClassLoader.
     * This class loader might be necessary when ICU4J classes are
     * initialized by bootstrap class loader.
     *
     * @return The BootStrapClassLoader singleton instance
     */
    private static ClassLoader getBootstrapClassLoader() {
        if (BOOTSTRAP_CLASSLOADER == null) {
            synchronized(ClassLoaderUtil.class) {
                if (BOOTSTRAP_CLASSLOADER == null) {
                    ClassLoader cl = null;
                    if (System.getSecurityManager() != null) {
                        cl = AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
                            @Override
                            public BootstrapClassLoader run() {
                                return new BootstrapClassLoader();
                            }
                        });
                    } else {
                        cl = new BootstrapClassLoader();
                    }
                    BOOTSTRAP_CLASSLOADER = cl;
                }
            }
        }
        return BOOTSTRAP_CLASSLOADER;
    }


    /**
     * Returns the class loader used for loading the specified class.
     * @param cls The class
     * @return the class loader
     */
    public static ClassLoader getClassLoader(Class<?> cls) {
        ClassLoader cl = cls.getClassLoader();
        if (cl == null) {
            cl = getClassLoader();
        }
        return cl;
    }

    /**
     * Returns a fallback class loader.
     * @return A class loader
     */
    public static ClassLoader getClassLoader() {
        ClassLoader cl = Thread.currentThread().getContextClassLoader();
        if (cl == null) {
            cl = ClassLoader.getSystemClassLoader();
            if (cl == null) {
                // When this method is called for initializing a ICU4J class
                // during bootstrap, cl might be still null (other than Android?).
                // In this case, we want to use the bootstrap class loader.
                cl = getBootstrapClassLoader();
            }
        }
        return cl;
    }
}
