net.sf.eBus.util.JarFileLoader Maven / Gradle / Ivy
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later
// version.
//
// This library is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU Lesser General Public License for more
// details.
//
// You should have received a copy of the GNU Lesser General
// Public License along with this library; if not, write to the
//
// Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330,
// Boston, MA
// 02111-1307 USA
//
// The Initial Developer of the Original Code is Charles W. Rapp.
// Portions created by Charles W. Rapp are
// Copyright (C) 2013. Charles W. Rapp.
// All Rights Reserved.
//
package net.sf.eBus.util;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLStreamHandlerFactory;
import java.util.Arrays;
/**
* This class extends {@link java.net.URLClassLoader}, providing
* the ability to load a class from a Java jar file introduced
* after JVM starts. This capability is needed by long
* running Java applications which cannot be restarted but need
* to access a new jar file dropped into a well-known location.
* That jar file path may be added to the {@code JarFileLoader}
* via {@link JarFileLoader#addJar(java.lang.String)} and then
* {@link JarFileLoader#packages()} used to determine the newly
* available packages.
*
* @author Charles Rapp
*/
public final class JarFileLoader
extends URLClassLoader
{
//---------------------------------------------------------------
// Member methods.
//
//-----------------------------------------------------------
// Constructors.
//
/**
* Constructs a new JAR class loader for the specified URLs
* and the default {@link java.lang.ClassLoader}. The URLs are searched from index
* zero to {@code urls.length - 1} for classes and resources
* after first delegating the search to
* {@code parent}. Any URL ending in "/" is assumed to refer
* to a directory. Otherwise, the URL is assumed to be a JAR
* file which will be downloaded and opened as necessary.
* @param urls the class and resource load path.
* @throws SecurityException
* if a security manager exists and its
* {@code checkCreateClassLoader} method does not allow
* creation of a class loader.
*/
public JarFileLoader(final URL[] urls)
throws SecurityException
{
super (urls);
} // end of JarFileLoader(URL[])
/**
* Constructs a new JAR class loader for the specified URLs
* and parent class loader. The URLs are searched from index
* zero to {@code urls.length - 1} for classes and resources
* after first delegating the search to
* {@code parent}. Any URL ending in "/" is assumed to refer
* to a directory. Otherwise, the URL is assumed to be a JAR
* file which will be downloaded and opened as necessary.
* @param urls the class and resource load path.
* @param parent the delegate parent class loader.
* @throws SecurityException
* if a security manager exists and its
* {@code checkCreateClassLoader} method does not allow
* creation of a class loader.
*/
public JarFileLoader(final URL[] urls,
final ClassLoader parent)
throws SecurityException
{
super (urls, parent);
} // end of JarFileLoader(URL[], ClassLoader)
/**
* Constructs a new JAR class loader for the specified URLs,
* parent class loader, and URL stream handler factory. The
* {@code parent} argument is the delegate class loader. The
* {@code factory} argument is used to obtain protocol
* handlers when creating new JAR URLs. The search order is:
*
* -
* {@code parent} delegate first.
*
* -
* {@code urls} from index zero to
* {@code urls.length - 1}.
*
*
* @param urls the class and resource load path.
* @param parent the delegate parent class loader.
* @param factory the protocol handler factory.
* @throws SecurityException
* if a security manager exists and its
* {@code checkCreateClassLoader} method does not allow
* creation of a class loader.
*/
public JarFileLoader(final URL[] urls,
final ClassLoader parent,
final URLStreamHandlerFactory factory)
throws SecurityException
{
super (urls, parent, factory);
} // end of JarFileLoader(...)
//
// end of Constructors.
//-----------------------------------------------------------
//-----------------------------------------------------------
// Get Methods.
//
/**
* Returns all the {@link java.lang.Package}s defined by this
* class loader and its ancestors.
* @return the class loader packages.
*/
public Package[] packages()
{
final Package[] pkgs = getPackages();
return (Arrays.copyOf(pkgs, pkgs.length));
} // end of packages()
//
// end of Get Methods.
//-----------------------------------------------------------
/**
* Appends the JAR file path to the URL search list.
* @param path path to a readable JAR file.
* @throws FileNotFoundException
* if {@code path} refers to a non-existent file.
* @throws IOException
* if {@code path} either does not refer to a regular file or
* the file cannot be read.
* @throws MalformedURLException
* if {@code path} could not be parsed by
* {@link java.net.URL}.
*/
public void addJar(final String path)
throws FileNotFoundException,
IOException,
MalformedURLException
{
final File jarFile = new File(path);
// Does this file exist?
if (jarFile.exists() == false)
{
// No.
throw (
new FileNotFoundException(
String.format("%s does not exist", path)));
}
// Does this path refer to a regular file?
else if (jarFile.isFile() == false)
{
// No.
throw (
new IOException(
String.format(
"%s is not a regular file", path)));
}
// Does this path refer to a readble file?
else if (jarFile.canRead() == false)
{
// No.
throw (
new IOException(
String.format("%s cannot be read", path)));
}
// Everything checks out: the path refers to a readable,
// regular file. We *assume* that it is a valid JAR file.
addURL(
new URL(
String.format(
URL_FORMAT, jarFile.getAbsolutePath())));
return;
} // end of addJar(String)
//---------------------------------------------------------------
// Member data.
//
/**
* Place the JAR file path within this string to create the
* JAR URL. The URL format is "jar:file:///<path>!/".
*/
public static final String URL_FORMAT = "jar:file:///%s!/";
} // end of class JarFileLoader