blob: 605503e6d85b93a90888430b394b34068bdfab03 [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.ignite.testframework;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.jetbrains.annotations.Nullable;
/**
* Utility classloader that has ability to load classes from external resources.
*/
@SuppressWarnings({"CustomClassloader"})
public class GridTestExternalClassLoader extends URLClassLoader {
/** */
private Set<String> excludeClassNames;
/** */
private Map<String, byte[]> resourceMap;
/** */
private long timeout;
/**
* Constructor.
* @param urls the URLs from which to load classes and resources.
* @param excludeClassNames list of excluded classes.
*/
public GridTestExternalClassLoader(URL[] urls, String... excludeClassNames) {
this(urls, Collections.<String, byte[]>emptyMap(), excludeClassNames);
}
/**
* Constructor.
* @param urls the URLs from which to load classes and resources.
* @param resourceMap mapped resources.
*/
public GridTestExternalClassLoader(URL[] urls, Map<String, byte[]> resourceMap) {
this(urls, resourceMap, Collections.<String>emptySet());
}
/**
* Constructor.
* @param urls the URLs from which to load classes and resources.
* @param resourceMap Resource map.
* @param excludeClassNames list of excluded classes.
*/
public GridTestExternalClassLoader(URL[] urls, Map<String, byte[]> resourceMap, String... excludeClassNames) {
this(urls, resourceMap, new HashSet<>(Arrays.asList(excludeClassNames)));
}
/**
* Constructor.
* @param urls the URLs from which to load classes and resources.
* @param resourceMap Resource map.
* @param excludeClassNames list of excluded classes.
*/
public GridTestExternalClassLoader(URL[] urls, Map<String, byte[]> resourceMap, Set<String> excludeClassNames) {
super(urls, GridTestExternalClassLoader.class.getClassLoader());
this.excludeClassNames = excludeClassNames;
assert resourceMap != null;
this.resourceMap = resourceMap;
}
/**
* Sets set of excluded resource paths.
* @param excludeClassNames excluded resource paths.
*/
public void setExcludeClassNames(Set<String> excludeClassNames) {
this.excludeClassNames = excludeClassNames;
}
/**
* Sets set of excluded resource paths.
* @param excludeClassNames excluded resource paths.
*/
public void setExcludeClassNames(String... excludeClassNames) {
setExcludeClassNames(new HashSet<>(Arrays.asList(excludeClassNames)));
}
/**
* @param timeout Timeout.
*/
public void setTimeout(long timeout) {
this.timeout = timeout;
}
/**
* Sleep {@code timeout} period of time.
*/
private void doTimeout() {
try {
Thread.sleep(timeout);
}
catch (InterruptedException e) {
throw new RuntimeException("Thread was interrupted", e);
}
}
/**
* @param resName Resource name.
* @return Class name.
*/
private String resNameToClassName(String resName) {
if (resName.endsWith(".class"))
resName = resName.substring(0, resName.length() - ".class".length());
return resName.replace('/', '.');
}
/** {@inheritDoc} */
@Override protected Class<?> findClass(String name) throws ClassNotFoundException {
for (String s : excludeClassNames)
if (s.equals(name))
throw new ClassNotFoundException(name);
return super.findClass(name);
}
/** {@inheritDoc} */
@Override protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
if (excludeClassNames.contains(name))
throw new ClassNotFoundException(name);
return super.loadClass(name, resolve);
}
/** {@inheritDoc} */
@Nullable @Override public URL findResource(String name) {
if (excludeClassNames.contains(resNameToClassName(name)))
return null;
return super.findResource(name);
}
/** {@inheritDoc} */
@Override public InputStream getResourceAsStream(String name) {
doTimeout();
byte[] res = resourceMap.get(name);
return res == null ? super.getResourceAsStream(name) : new ByteArrayInputStream(res);
}
/**
* @param resourceMap mapped resources.
*/
public void setResourceMap(Map<String, byte[]> resourceMap) {
this.resourceMap = resourceMap;
}
/**
* Returns an Enumeration of URLs representing all of the resources on the URL search path having the specified name.
*
* @param name the resource name.
* @return an {@code Enumeration} of {@code URL}s.
* @throws IOException if an I/O exception occurs.
*/
@Override public Enumeration<URL> findResources(String name) throws IOException {
if (excludeClassNames.contains(resNameToClassName(name))) {
return new Enumeration<URL>() {
@Override public boolean hasMoreElements() {
return false;
}
@Override public URL nextElement() {
throw new UnsupportedOperationException();
}
};
}
return super.findResources(name);
}
}