com.wavemaker.commons.classloader.ThrowawayFileClassLoader Maven / Gradle / Ivy
/**
* Copyright (C) 2020 WaveMaker, Inc.
*
* 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 com.wavemaker.commons.classloader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.List;
import java.util.jar.JarFile;
import java.util.zip.ZipEntry;
import org.apache.commons.io.IOUtils;
import org.springframework.core.io.Resource;
import com.wavemaker.commons.MessageResource;
import com.wavemaker.commons.WMRuntimeException;
/**
* A ClassLoader that takes a File (as the root to search in), and searches for classes within that root. This does
* everything to avoid ever loading classes into any other classloader. It takes a parent classloader as an option, but
* only delegates to it if the class cannot be found in the local paths.
*
* @author Matt Small
* @author Jeremy Grelle
*/
public class ThrowawayFileClassLoader extends ClassLoader {
private final List classPath;
private final ClassLoader parentClassLoader;
public ThrowawayFileClassLoader(List classPath, ClassLoader parent) {
super(null);
this.classPath = classPath;
this.parentClassLoader = parent;
}
@Override
protected Class> findClass(String name) throws ClassNotFoundException {
if (this.classPath == null) {
throw new ClassNotFoundException("invalid search root: " + this.classPath);
} else if (name == null) {
throw new ClassNotFoundException(MessageResource.NULL_CLASS.getMessage());
}
String classNamePath = name.replace('.', '/') + ".class";
byte[] fileBytes = null;
try {
InputStream is = null;
JarFile jarFile = null;
try {
for (Resource entry : this.classPath) {
if (entry.getFilename().toLowerCase().endsWith(".jar")) {
jarFile = new JarFile(entry.getFile());
ZipEntry ze = jarFile.getEntry(classNamePath);
if (ze != null) {
is = jarFile.getInputStream(ze);
break;
} else {
jarFile.close();
}
} else {
Resource classFile = entry.createRelative(classNamePath);
if (classFile.exists()) {
is = classFile.getInputStream();
break;
}
}
}
if (is != null) {
try {
fileBytes = IOUtils.toByteArray(is);
} finally {
is.close();
}
}
} finally {
if (jarFile != null) {
jarFile.close();
}
}
} catch (IOException e) {
throw new ClassNotFoundException(e.getMessage(), e);
}
if (name.contains(".")) {
String packageName = name.substring(0, name.lastIndexOf('.'));
if (getPackage(packageName) == null) {
definePackage(packageName, "", "", "", "", "", "", null);
}
}
Class> ret;
if (fileBytes == null) {
ret = ClassLoaderUtils.loadClass(name, this.parentClassLoader);
} else {
ret = defineClass(name, fileBytes, 0, fileBytes.length);
}
if (ret == null) {
throw new ClassNotFoundException("Couldn't find class " + name + " in expected classpath: " + this.classPath);
}
return ret;
}
@Override
protected URL findResource(String name) {
URL ret = null;
JarFile jarFile = null;
try {
for (Resource entry : this.classPath) {
if (entry.getFilename().toLowerCase().endsWith(".jar")) {
jarFile = new JarFile(entry.getFile());
ZipEntry ze = jarFile.getEntry(name);
jarFile.close();
if (ze != null) {
ret = new URL("jar:" + entry.getURL() + "!/" + name);
break;
}
} else {
Resource file = entry.createRelative(name);
if (file.exists()) {
ret = file.getURL();
break;
}
}
}
} catch (IOException e) {
throw new WMRuntimeException(e);
}
return ret;
}
@Override
public InputStream getResourceAsStream(String name) {
URL url = getResource(name);
if (url == null) {
return null;
}
try {
InputStream is = null;
byte[] b;
try {
is = url.openStream();
b = IOUtils.toByteArray(is);
} finally {
if (is != null) {
is.close();
}
url = null;
is = null;
}
return new ByteArrayInputStream(b);
} catch (IOException e) {
return null;
}
}
}