/*
* SoapUI, Copyright (C) 2004-2016 SmartBear Software
*
* Licensed under the EUPL, Version 1.1 or - as soon as they will be approved by the European Commission - subsequent
* versions of the EUPL (the "Licence");
* You may not use this work except in compliance with the Licence.
* You may obtain a copy of the Licence at:
*
* http://ec.europa.eu/idabc/eupl
*
* Unless required by applicable law or agreed to in writing, software distributed under the Licence is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the Licence for the specific language governing permissions and limitations
* under the Licence.
*/
package com.eviware.soapui.plugins;
import com.eviware.soapui.support.Tools;
import groovy.lang.GroovyClassLoader;
import org.apache.commons.io.FileUtils;
import org.apache.log4j.Logger;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Collection;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
public class JarClassLoader extends URLClassLoader implements PluginClassLoader {
private static final Logger log = Logger.getLogger(JarClassLoader.class);
public static final String LIB_PREFIX = "lib/";
private final ClassLoader parent;
private Collection<JarClassLoader> dependencyClassLoaders;
private GroovyClassLoader scriptClassLoader;
public JarClassLoader(File jarFile, ClassLoader parent, Collection<JarClassLoader> dependencyClassLoaders) throws IOException {
super(new URL[]{jarFile.toURI().toURL()}, null);
this.parent = parent;
this.dependencyClassLoaders = dependencyClassLoaders;
JarFile file = new JarFile(jarFile);
addLibrariesIn(file);
addScriptsIn(file);
}
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
try {
return super.loadClass(name);
} catch (ClassNotFoundException e) {
for (JarClassLoader dependencyClassLoader : dependencyClassLoaders) {
try {
return dependencyClassLoader.loadClass(name);
}
catch (ClassNotFoundException ignore) {
}
catch (NoClassDefFoundError ignore) {
}
}
return parent.loadClass(name);
}
catch (NoClassDefFoundError e) {
for (JarClassLoader dependencyClassLoader : dependencyClassLoaders) {
try {
return dependencyClassLoader.loadClass(name);
}
catch (ClassNotFoundException ignore) {
}
catch (NoClassDefFoundError ignore) {
}
}
return parent.loadClass(name);
}
}
private void addLibrariesIn(JarFile jarFile) throws IOException {
if (containsLibraries(jarFile)) {
File libDirectory = Tools.createTemporaryDirectory();
Enumeration<JarEntry> entries = jarFile.entries();
while (entries.hasMoreElements()) {
JarEntry jarEntry = entries.nextElement();
if (isLibrary(jarEntry)) {
String fileName = jarEntry.getName().substring(LIB_PREFIX.length());
File outputFile = new File(libDirectory, fileName);
FileUtils.copyInputStreamToFile(jarFile.getInputStream(jarEntry), outputFile);
this.addURL(outputFile.toURI().toURL());
}
}
}
}
private void addScriptsIn(JarFile jarFile) throws IOException {
boolean hasScripts = false;
if (containsScripts(jarFile)) {
File scriptsDirectory = Tools.createTemporaryDirectory();
Enumeration<JarEntry> entries = jarFile.entries();
while (entries.hasMoreElements()) {
JarEntry jarEntry = entries.nextElement();
if (isScript(jarEntry)) {
String pathToScript = jarEntry.getName();
File outputFile = null;
int lastSlashIndex = pathToScript.lastIndexOf('/');
if (lastSlashIndex >= 0) {
File packageDirectory = new File(scriptsDirectory, pathToScript.substring(0, lastSlashIndex));
if (!packageDirectory.exists() || !packageDirectory.isDirectory()) {
if (!packageDirectory.mkdirs()) {
log.error("Failed to create directory for [" + pathToScript + "]");
packageDirectory = null;
}
}
if (packageDirectory != null) {
outputFile = new File(packageDirectory, pathToScript.substring(lastSlashIndex + 1));
}
}
if (outputFile != null) {
FileUtils.copyInputStreamToFile(jarFile.getInputStream(jarEntry), outputFile);
hasScripts = true;
}
}
}
/*
if (hasScripts) {
URL scriptsUrl = scriptsDirectory.toURI().toURL();
SoapUIPro.getSoapUIGroovyClassLoader().addURL(scriptsUrl);
scriptClassLoader = new GroovyClassLoader(SoapUIPro.getSoapUIGroovyClassLoader());
scriptClassLoader.addURL(scriptsUrl);
}
*/
}
}
private boolean containsLibraries(JarFile jarFile) {
Enumeration<JarEntry> entries = jarFile.entries();
while (entries.hasMoreElements()) {
JarEntry jarEntry = entries.nextElement();
if (isLibrary(jarEntry)) {
return true;
}
}
return false;
}
private boolean containsScripts(JarFile jarFile) {
Enumeration<JarEntry> entries = jarFile.entries();
while (entries.hasMoreElements()) {
JarEntry jarEntry = entries.nextElement();
if (isScript(jarEntry)) {
return true;
}
}
return false;
}
private boolean isLibrary(JarEntry jarEntry) {
return jarEntry.getName().startsWith(LIB_PREFIX) && jarEntry.getName().endsWith(".jar");
}
private boolean isScript(JarEntry jarEntry) {
return jarEntry.getName().endsWith(".groovy");
}
public boolean hasScripts() {
return scriptClassLoader != null;
}
public Class loadScriptClass(String path) throws ClassNotFoundException {
path = path.substring(0, path.length() - ".groovy".length());
return scriptClassLoader.loadClass(path, true, true, true);
}
public GroovyClassLoader getScriptClassLoader() {
return scriptClassLoader;
}
}