blob: 946db694555444f6bb78e3abd887c0f19f7dec66 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.apache.openjpa.lib.util;
import java.io.IOException;
import java.net.URL;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;
/**
* Class loader type that can be configured to delegate to multiple
* internal class loaders.
* The {@link #THREAD_LOADER} constant is a marker that will be replaced
* with the context loader of the current thread.
*
* @author Abe White
*/
public class MultiClassLoader extends ClassLoader {
/**
* Marker that will be replaced with the context loader of the current
* thread whenever it is discovered in the class loader list.
*/
public static final ClassLoader THREAD_LOADER = null;
/**
* The standard system class loader.
*/
public static final ClassLoader SYSTEM_LOADER =
AccessController.doPrivileged(
J2DoPrivHelper.getSystemClassLoaderAction());
private List<ClassLoader> _loaders = new ArrayList<>(5);
/**
* Constructor; initializes the loader with an empty list of delegates.
*/
public MultiClassLoader() {
super(null);
}
/**
* Construct with the class loaders of another multi loader.
*/
public MultiClassLoader(MultiClassLoader other) {
super(null);
addClassLoaders(other);
}
public MultiClassLoader(ClassLoader... loaders) {
for (ClassLoader loader : loaders) {
addClassLoader(loader);
}
}
/**
* Returns true if the list contains the given class loader or marker.
*/
public boolean containsClassLoader(ClassLoader loader) {
return _loaders.contains(loader);
}
/**
* Return an array of all contained class loaders.
*/
public ClassLoader[] getClassLoaders() {
ClassLoader[] loaders = new ClassLoader[size()];
ClassLoader loader;
Iterator<ClassLoader> itr = _loaders.iterator();
for (int i = 0; i < loaders.length; i++) {
loader = itr.next();
if (loader == THREAD_LOADER)
loader = AccessController.doPrivileged(
J2DoPrivHelper.getContextClassLoaderAction());
loaders[i] = loader;
}
return loaders;
}
/**
* Return the class loader at the given index.
*/
public ClassLoader getClassLoader(int index) {
ClassLoader loader = (ClassLoader) _loaders.get(index);
if (loader == THREAD_LOADER)
loader = AccessController.doPrivileged(
J2DoPrivHelper.getContextClassLoaderAction());
return loader;
}
/**
* Add the given class loader to the set of loaders that will be tried.
*
* @return true if the loader was added, false if already in the list
*/
public boolean addClassLoader(ClassLoader loader) {
if (_loaders.contains(loader))
return false;
return _loaders.add(loader);
}
/**
* Add the given class loader at the specified index.
*
* @return true if the loader was added, false if already in the list
*/
public boolean addClassLoader(int index, ClassLoader loader) {
if (_loaders.contains(loader))
return false;
_loaders.add(index, loader);
return true;
}
/**
* Set the class loaders of this loader to those of the given loader.
*/
public void setClassLoaders(MultiClassLoader multi) {
clear();
addClassLoaders(multi);
}
/**
* Adds all class loaders from the given multi loader starting at the
* given index.
*
* @return true if any loaders were added, false if all already in list
*/
public boolean addClassLoaders(int index, MultiClassLoader multi) {
if (multi == null)
return false;
// use iterator so that the thread loader is not resolved
boolean added = false;
for (ClassLoader loader : multi._loaders) {
if (addClassLoader(index, loader)) {
index++;
added = true;
}
}
return added;
}
/**
* Adds all the class loaders from the given multi loader.
*
* @return true if any loaders were added, false if all already in list
*/
public boolean addClassLoaders(MultiClassLoader multi) {
if (multi == null)
return false;
// use iterator so that the thread loader is not resolved
boolean added = false;
for (ClassLoader loader : multi._loaders) {
added = addClassLoader(loader) || added;
}
return added;
}
/**
* Remove the given loader from the list.
*
* @return true if removed, false if not in list
*/
public boolean removeClassLoader(ClassLoader loader) {
return _loaders.remove(loader);
}
/**
* Clear the list of class loaders.
*/
public void clear() {
_loaders.clear();
}
/**
* Return the number of internal class loaders.
*/
public int size() {
return _loaders.size();
}
/**
* Return true if there are no internal class laoders.
*/
public boolean isEmpty() {
return _loaders.isEmpty();
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
ClassLoader loader;
for (ClassLoader classLoader : _loaders) {
loader = classLoader;
if (loader == THREAD_LOADER)
loader = AccessController.doPrivileged(
J2DoPrivHelper.getContextClassLoaderAction());
try {
return Class.forName(name, false, loader);
}
catch (Throwable t) {
}
}
throw new ClassNotFoundException(name);
}
@Override
protected URL findResource(String name) {
ClassLoader loader;
URL rsrc;
for (ClassLoader classLoader : _loaders) {
loader = classLoader;
if (loader == THREAD_LOADER)
loader = AccessController.doPrivileged(
J2DoPrivHelper.getContextClassLoaderAction());
if (loader == null) // skip
continue;
rsrc = AccessController.doPrivileged(
J2DoPrivHelper.getResourceAction(loader, name));
if (rsrc != null)
return rsrc;
}
return null;
}
@Override
protected Enumeration<URL> findResources(String name) throws IOException {
ClassLoader loader;
Enumeration<URL> rsrcs;
URL rsrc;
Vector<URL> all = new Vector<>();
for (ClassLoader classLoader : _loaders) {
loader = classLoader;
if (loader == THREAD_LOADER)
loader = AccessController.doPrivileged(
J2DoPrivHelper.getContextClassLoaderAction());
if (loader == null) // skip
continue;
try {
rsrcs = AccessController.doPrivileged(
J2DoPrivHelper.getResourcesAction(loader, name));
while (rsrcs.hasMoreElements()) {
rsrc = rsrcs.nextElement();
if (!all.contains(rsrc))
all.addElement(rsrc);
}
}
catch (PrivilegedActionException pae) {
throw (IOException) pae.getException();
}
}
return all.elements();
}
@Override
public boolean equals(Object other) {
if (other == this)
return true;
if (!(other instanceof MultiClassLoader))
return false;
return ((MultiClassLoader) other)._loaders.equals(_loaders);
}
@Override
public int hashCode() {
return _loaders.hashCode();
}
}