/* * Copyright 2016 Red Hat, Inc. and/or its affiliates * and other contributors as indicated by the @author tags. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.keycloak.connections.jpa.entityprovider; import java.net.URL; import java.util.Collection; import java.util.HashSet; import java.util.Set; /** * @author <a href="mailto:erik.mulder@docdatapayments.com">Erik Mulder</a> * * Classloader implementation to facilitate loading classes and resources from a collection of other classloaders. * Effectively it forms a proxy to one or more other classloaders. * * The way it works: * - Get all (unique) classloaders from all provided classes * - For each class or resource that is 'requested': * - First try all provided classloaders and if we have a match, return that * - If no match was found: proceed with 'normal' classloading in 'current classpath' scope * * In this particular context: only loadClass and getResource overrides are needed, since those * are the methods that a classloading and resource loading process will need. */ public class ProxyClassLoader extends ClassLoader { private Set<ClassLoader> classloaders; public ProxyClassLoader(Collection<Class<?>> classes, ClassLoader parentClassLoader) { super(parentClassLoader); init(classes); } public ProxyClassLoader(Collection<Class<?>> classes) { init(classes); } private void init(Collection<Class<?>> classes) { classloaders = new HashSet<>(); for (Class<?> clazz : classes) { classloaders.add(clazz.getClassLoader()); } } @Override public Class<?> loadClass(String name) throws ClassNotFoundException { for (ClassLoader classloader : classloaders) { try { return classloader.loadClass(name); } catch (ClassNotFoundException e) { // This particular class loader did not find the class. It's expected behavior that // this can happen, so we'll just ignore the exception and let the next one try. } } // We did not find the class in the proxy class loaders, so proceed with 'normal' behavior. return super.loadClass(name); } @Override public URL getResource(String name) { for (ClassLoader classloader : classloaders) { URL resource = classloader.getResource(name); if (resource != null) { return resource; } // Resource == null means not found, so let the next one try. } // We could not get the resource from the proxy class loaders, so proceed with 'normal' behavior. return super.getResource(name); } }