All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sun.enterprise.loader.CurrentBeforeParentClassLoader Maven / Gradle / Ivy

There is a newer version: 7.2024.1.Alpha1
Show newest version
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright [2016-2019] [Payara Foundation and/or its affiliates]
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License.  You can
 * obtain a copy of the License at
 * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
 * or packager/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at packager/legal/LICENSE.txt.
 *
 * GPL Classpath Exception:
 * Oracle designates this particular file as subject to the "Classpath"
 * exception as provided by Oracle in the GPL Version 2 section of the License
 * file that accompanied this code.
 *
 * Modifications:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [year] [name of copyright owner]"
 *
 * Contributor(s):
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */

package com.sun.enterprise.loader;

import com.sun.enterprise.util.CULoggerInfo;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLStreamHandlerFactory;
import java.util.logging.Logger;

/**
 * As the name suggests, loads classes via current class loader ahead of parent class loader
 * by default, classes are loaded from the parent ClassLoader first, thus this class is 
 * needed to allow overriding App Server's Modules / JAR files by placing them
 * into <domain_dir>/lib or EAR lib directory
 * @author lprimak
 */
public class CurrentBeforeParentClassLoader extends URLClassLoader {
    public CurrentBeforeParentClassLoader(URL[] urls, ClassLoader parent) {
        super(urls, parent);
    }

    public CurrentBeforeParentClassLoader(URL[] urls) {
        super(urls);
    }

    public CurrentBeforeParentClassLoader(URL[] urls, ClassLoader parent, URLStreamHandlerFactory factory) {
        super(urls, parent, factory);
    }
    
    
    /**
     * Local-first class loading, instead of parent-first as the ClassLoader.loadClass() does
     * 
     * @param name
     * @param resolve
     * @return Loaded class
     * @throws ClassNotFoundException 
     */
    @Override
    protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException {
        boolean isWhitelisted = isWhitelistEnabled() && isWhiteListed(name);
        if((!currentBeforeParentEnabled && (isWhitelistEnabled()? isWhitelisted : true)) || isAlwaysDelegate(name))
        {
            return super.loadClass(name, resolve);
        }
        synchronized (getClassLoadingLock(name)) {
            // First, check if the class has already been loaded
            Class c = findLoadedClass(name);
            if(c != null) {
                return c;
            }
            try {
                c = findClass(name);
                logger.finest(String.format("Found Locally: %s - %s", name, c.getName()));
            }
            catch(ClassNotFoundException e) {
                if(!isWhitelistEnabled() || isWhitelisted) {
                    logger.finest(String.format("Not Found Locally - Looking in Parent: %s", name));
                    return parent.loadClass(name);
                }
                else {
                    throw new ClassNotFoundException(String.format("Whitelist enabled, but class [%s] is not whitelisted", name), e);
                }
            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }
    }


    /**
     * support for extreme class loading
     *
     * @param className
     * @return true if white-listed
     */
    protected boolean isWhiteListed(String className) {
        return false;
    }


    /**
     * @return true if extreme classloading is enabled
     */
    protected boolean isWhitelistEnabled() {
        return false;
    }
    
    
    /**
     * enable current-first behavior
     * conditional upon PARENT_CLASSLOADER_DELEGATE_PROPERTY system property being turned on
     */
    public final void enableCurrentBeforeParent() {
        String parentClassLoaderDelegateStr = System.getProperty(PARENT_CLASSLOADER_DELEGATE_PROPERTY, "true");
        if(!Boolean.parseBoolean(parentClassLoaderDelegateStr)) {
            currentBeforeParentEnabled = true;
        }
    }
    
    /**
     * enable current-first behavior unconditionally, regardless of system property
     * used by application configuration parser, so if application developer uses the config xml element,
     * they presumably want the behavior regardless of the system property settings
     */
    public final void enableCurrentBeforeParentUnconditional() {
        currentBeforeParentEnabled = true;
    }

    /**
     * disable functionality
     */
    public final void disableCurrentBeforeParent() {
        currentBeforeParentEnabled = false;
    }
    
    private boolean isAlwaysDelegate(String name) {
        return name.startsWith("sun") || name.startsWith("javax") || name.startsWith("jakarta");
    }

    @Override
    public void addURL(URL url){
        super.addURL(url);
    }
    
    protected boolean currentBeforeParentEnabled = false;
    
    private final ClassLoader system = getClass().getClassLoader();
    private final ClassLoader _parent = getParent();
    private final ClassLoader parent = _parent != null? _parent : system;
    private static final Logger logger = CULoggerInfo.getLogger();
    public static final String PARENT_CLASSLOADER_DELEGATE_PROPERTY = "fish.payara.classloading.delegate";
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy