/** * Copyright (c) 2000-present Liferay, Inc. All rights reserved. * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. */ package com.liferay.portal.kernel.util; import com.liferay.portal.kernel.exception.LoggedExceptionInInitializerError; import com.liferay.portal.kernel.memory.EqualityWeakReference; import java.io.IOException; import java.lang.ref.WeakReference; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.URL; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Enumeration; import java.util.Iterator; import java.util.List; /** * @author Brian Wing Shun Chan * @author Michael C. Han * @author Shuyang Zhou */ public class AggregateClassLoader extends ClassLoader { public static ClassLoader getAggregateClassLoader( ClassLoader parentClassLoader, ClassLoader... classLoaders) { if (ArrayUtil.isEmpty(classLoaders)) { return parentClassLoader; } AggregateClassLoader aggregateClassLoader = null; if (parentClassLoader instanceof AggregateClassLoader) { aggregateClassLoader = (AggregateClassLoader)parentClassLoader; } else { aggregateClassLoader = new AggregateClassLoader(parentClassLoader); } for (ClassLoader classLoader : classLoaders) { aggregateClassLoader.addClassLoader(classLoader); } return aggregateClassLoader; } public static ClassLoader getAggregateClassLoader( ClassLoader[] classLoaders) { if (ArrayUtil.isEmpty(classLoaders)) { return null; } return getAggregateClassLoader(classLoaders[0], classLoaders); } public AggregateClassLoader(ClassLoader classLoader) { super(classLoader); } public void addClassLoader(ClassLoader classLoader) { List<ClassLoader> classLoaders = getClassLoaders(); if (classLoaders.contains(classLoader)) { return; } if ((classLoader instanceof AggregateClassLoader) && classLoader.getParent().equals(getParent())) { AggregateClassLoader aggregateClassLoader = (AggregateClassLoader)classLoader; for (ClassLoader curClassLoader : aggregateClassLoader.getClassLoaders()) { addClassLoader(curClassLoader); } } else { _classLoaderReferences.add( new EqualityWeakReference<>(classLoader)); } } public void addClassLoader(ClassLoader... classLoaders) { for (ClassLoader classLoader : classLoaders) { addClassLoader(classLoader); } } public void addClassLoader(Collection<ClassLoader> classLoaders) { for (ClassLoader classLoader : classLoaders) { addClassLoader(classLoader); } } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!(obj instanceof AggregateClassLoader)) { return false; } AggregateClassLoader aggregateClassLoader = (AggregateClassLoader)obj; if (_classLoaderReferences.equals( aggregateClassLoader._classLoaderReferences) && (((getParent() == null) && (aggregateClassLoader.getParent() == null)) || ((getParent() != null) && getParent().equals(aggregateClassLoader.getParent())))) { return true; } return false; } public List<ClassLoader> getClassLoaders() { List<ClassLoader> classLoaders = new ArrayList<>( _classLoaderReferences.size()); Iterator<EqualityWeakReference<ClassLoader>> itr = _classLoaderReferences.iterator(); while (itr.hasNext()) { WeakReference<ClassLoader> weakReference = itr.next(); ClassLoader classLoader = weakReference.get(); if (classLoader == null) { itr.remove(); } else { classLoaders.add(classLoader); } } return classLoaders; } @Override public URL getResource(String name) { for (ClassLoader classLoader : getClassLoaders()) { URL url = _getResource(classLoader, name); if (url != null) { return url; } } return super.getResource(name); } @Override public Enumeration<URL> getResources(String name) throws IOException { List<URL> urls = new ArrayList<>(); for (ClassLoader classLoader : getClassLoaders()) { urls.addAll(Collections.list(_getResources(classLoader, name))); } urls.addAll(Collections.list(_getResources(getParent(), name))); return Collections.enumeration(urls); } @Override public int hashCode() { if (_classLoaderReferences != null) { return _classLoaderReferences.hashCode(); } else { return 0; } } @Override protected Class<?> findClass(String name) throws ClassNotFoundException { for (ClassLoader classLoader : getClassLoaders()) { try { return _findClass(classLoader, name); } catch (ClassNotFoundException cnfe) { } } throw new ClassNotFoundException("Unable to find class " + name); } @Override protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { Class<?> loadedClass = null; for (ClassLoader classLoader : getClassLoaders()) { try { loadedClass = _loadClass(classLoader, name, resolve); break; } catch (ClassNotFoundException cnfe) { } } if (loadedClass == null) { loadedClass = _loadClass(getParent(), name, resolve); } else if (resolve) { resolveClass(loadedClass); } return loadedClass; } private static Class<?> _findClass(ClassLoader classLoader, String name) throws ClassNotFoundException { try { return (Class<?>)_FIND_CLASS_METHOD.invoke(classLoader, name); } catch (InvocationTargetException ite) { throw new ClassNotFoundException( "Unable to find class " + name, ite.getTargetException()); } catch (Exception e) { throw new ClassNotFoundException("Unable to find class " + name, e); } } private static URL _getResource(ClassLoader classLoader, String name) { try { return (URL)_GET_RESOURCE_METHOD.invoke(classLoader, name); } catch (InvocationTargetException ite) { return null; } catch (Exception e) { return null; } } private static Enumeration<URL> _getResources( ClassLoader classLoader, String name) throws IOException { try { return (Enumeration<URL>)_GET_RESOURCES_METHOD.invoke( classLoader, name); } catch (InvocationTargetException ite) { Throwable t = ite.getTargetException(); throw new IOException(t); } catch (Exception e) { throw new IOException(e); } } private static Class<?> _loadClass( ClassLoader classLoader, String name, boolean resolve) throws ClassNotFoundException { try { return (Class<?>)_LOAD_CLASS_METHOD.invoke( classLoader, name, resolve); } catch (InvocationTargetException ite) { throw new ClassNotFoundException( "Unable to load class " + name, ite.getTargetException()); } catch (Exception e) { throw new ClassNotFoundException("Unable to load class " + name, e); } } private static final Method _FIND_CLASS_METHOD; private static final Method _GET_RESOURCE_METHOD; private static final Method _GET_RESOURCES_METHOD; private static final Method _LOAD_CLASS_METHOD; static { try { _FIND_CLASS_METHOD = ReflectionUtil.getDeclaredMethod( ClassLoader.class, "findClass", String.class); _GET_RESOURCE_METHOD = ReflectionUtil.getDeclaredMethod( ClassLoader.class, "getResource", String.class); _GET_RESOURCES_METHOD = ReflectionUtil.getDeclaredMethod( ClassLoader.class, "getResources", String.class); _LOAD_CLASS_METHOD = ReflectionUtil.getDeclaredMethod( ClassLoader.class, "loadClass", String.class, boolean.class); } catch (Exception e) { throw new LoggedExceptionInInitializerError(e); } } private final List<EqualityWeakReference<ClassLoader>> _classLoaderReferences = new ArrayList<>(); }