/*
* Copyright 2013, The Sporting Exchange Limited
*
* 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.betfair.cougar.codegen.resource;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.List;
import com.betfair.cougar.codegen.except.PluginException;
/**
* Responsible for getting resources. Does what we'd normally expect a {@link ClassLoader} to do,
* but internally is clever enough to look at the classpaths of both the plugin, as well as the
* runtime classpath of the project itself. We need this because of the problems caused by
* declaring dependencies as part of the plugin (see our mojo's javadoc for more detail).
* <p>
* See http://old.nabble.com/How-to-get-files-from-JAR-dependencies-in-a-plugin---td21914851.html
* and http://maven.apache.org/guides/mini/guide-maven-classloading.html.
*/
public class ResourceLoader {
/**
* A classloader which recognises the runtime classpath of the project. Initialised by passing
* in a list of URLs (the runtime classpath). Null means 'don't use me'
*/
private final ClassLoader runtimeClassLoader;
/**
* Util constructor for a loader which will NOT look at the runtime classpath.
*/
public ResourceLoader() {
this(null);
}
/**
* Constructor
*
* @param classpath the runtime classpath (obtained from the Mojo). If non-null, this classpath
* will be consulted for resources which could not be found under the plugin's
* classpath.
*/
public ResourceLoader(List<String> classpath) {
if (classpath != null) {
try {
runtimeClassLoader = urlClassLoader(classpath);
} catch (MalformedURLException e) {
throw new PluginException("Error initialising resource loader: " + e, e);
}
}
else {
runtimeClassLoader = null;
}
}
/**
* Same as {@link ClassLoader#getResourceAsStream(String)} except it will look at the runtime
* classpath if not in the plugin ClassLoader's classpath.
*/
public InputStream getResourceAsStream(String resourceName) {
URL url = getResource(resourceName);
try {
return url != null ? url.openStream() : null;
} catch (IOException e) {
return null; // this is what a normal ClassLoader does
}
}
private URL getResource(String resourceName) {
URL url = getClass().getClassLoader().getResource(resourceName);
if (url == null) {
// try the run time class path
url = runtimeClassLoader.getResource(resourceName);
}
return url;
}
private ClassLoader urlClassLoader(List<String> runtimeClassPath) throws MalformedURLException {
URL[] urls = new URL[runtimeClassPath.size()];
int i = 0;
for(String s : runtimeClassPath) {
urls[i++] = new File(s).toURI().toURL();
}
return new URLClassLoader(urls);
}
}