ClassLoaderProvider.java revision 62ecec3a82a8b838ee76c1f6610902d8fd7015cb
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at
* trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
* add the following below this CDDL HEADER, with the fields enclosed
* by brackets "[]" replaced with your own identifying information:
* Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*
*
* Copyright 2008-2009 Sun Microsystems, Inc.
*/
/**
* Manages the class loader which should be used for loading
* configuration definition classes and associated extensions.
* <p>
* For extensions which define their own extended configuration
* definitions, the class loader will make sure that the configuration
* definition classes are loaded and initialized.
* <p>
* Initially the class loader provider is disabled, and calls to the
* {@link #getClassLoader()} will return the system default class
* loader.
* <p>
* Applications <b>MUST NOT</b> maintain persistent references to the
* class loader as it can change at run-time.
*/
public final class ClassLoaderProvider {
/**
* The tracer object for the debug logger.
*/
/**
* Private URLClassLoader implementation. This is only required so
* that we can provide access to the addURL method.
*/
private static final class MyURLClassLoader extends URLClassLoader {
/**
* Create a class loader with the default parent class loader.
*/
public MyURLClassLoader() {
super(new URL[0]);
}
/**
* Create a class loader with the provided parent class loader.
*
* @param parent
* The parent class loader.
*/
}
/**
* Add a Jar file to this class loader.
*
* @param jarFile
* The name of the Jar file.
* @throws MalformedURLException
* If a protocol handler for the URL could not be found,
* or if some other error occurred while constructing
* the URL.
* @throws SecurityException
* If a required system property value cannot be
* accessed.
*/
}
}
// The name of the manifest file listing the core configuration
// definition classes.
// The name of the manifest file listing a extension's configuration
// definition classes.
// The name of the lib directory.
// The name of the extensions directory.
// The singleton instance.
// Attribute name in jar's MANIFEST corresponding to the revision number.
// The attribute names for build information is name, version and revision
// number
private static final String[] BUILD_INFORMATION_ATTRIBUTE_NAMES =
/**
* Get the single application wide class loader provider instance.
*
* @return Returns the single application wide class loader provider
* instance.
*/
public static ClassLoaderProvider getInstance() {
return INSTANCE;
}
// Set of registered Jar files.
// Underlying class loader used to load classes and resources (null
// if disabled).
//
// We contain a reference to the URLClassLoader rather than
// sub-class it so that it is possible to replace the loader at
// run-time. For example, when removing or replacing extension Jar
// files (the URLClassLoader only supports adding new
// URLs, not removal).
// Private constructor.
private ClassLoaderProvider() {
// No implementation required.
}
/**
* Add the named extensions to this class loader provider.
*
* @param extensions
* The names of the extensions to be loaded. The names
* should not contain any path elements and must be located
* within the extensions folder.
* @throws InitializationException
* If one of the extensions could not be loaded and
* initialized.
* @throws IllegalStateException
* If this class loader provider is disabled.
* @throws IllegalArgumentException
* If one of the extension names was not a single relative
* path name element or was an absolute path.
*/
throw new IllegalStateException(
"Class loader provider is disabled.");
}
// For security reasons we need to make sure that the file name
// passed in did not contain any path elements and names a file
// in the extensions folder.
// Can handle potential null parent.
throw new IllegalArgumentException("Illegal file name: "
+ extension);
}
// The file is valid.
}
// Add the extensions.
}
/**
* Disable this class loader provider and removed any registered
* extensions.
*
* @throws IllegalStateException
* If this class loader provider is already disabled.
*/
public synchronized void disable() throws IllegalStateException {
throw new IllegalStateException(
"Class loader provider already disabled.");
}
}
/**
* Enable this class loader provider using the application's
* class loader as the parent class loader.
*
* @throws InitializationException
* If the class loader provider could not initialize
* successfully.
* @throws IllegalStateException
* If this class loader provider is already enabled.
*/
public synchronized void enable() throws InitializationException,
}
/**
* Enable this class loader provider using the provided parent class
* loader.
*
* @param parent
* The parent class loader.
* @throws InitializationException
* If the class loader provider could not initialize
* successfully.
* @throws IllegalStateException
* If this class loader provider is already enabled.
*/
throws InitializationException, IllegalStateException {
throw new IllegalStateException(
"Class loader provider already enabled.");
}
} else {
loader = new MyURLClassLoader();
}
// Forcefully load all configuration definition classes in
// OpenDS.jar.
// Put extensions jars into the class loader and load all
// configuration definition classes in that they contain.
// First load the extension from the install directory, then
// from the instance directory.
// load install dir extension
try
{
}
catch (Exception e)
{
}
// load instance dir extension
try
{
}
catch (Exception e)
{
}
{
}
}
/**
* Gets the class loader which should be used for loading classes
* and resources. When this class loader provider is disabled, the
* system default class loader will be returned by default.
* <p>
* Applications <b>MUST NOT</b> maintain persistent references to
* the class loader as it can change at run-time.
*
* @return Returns the class loader which should be used for loading
* classes and resources.
*/
public synchronized ClassLoader getClassLoader() {
return loader;
} else {
return ClassLoader.getSystemClassLoader();
}
}
/**
* Indicates whether this class loader provider is enabled.
*
* @return Returns <code>true</code> if this class loader provider
* is enabled.
*/
public synchronized boolean isEnabled() {
}
/**
* Add the named extensions to this class loader.
*
* @param extensions
* The names of the extensions to be loaded.
* @throws InitializationException
* If one of the extensions could not be loaded and
* initialized.
*/
throws InitializationException {
// First add the Jar files to the class loader.
// Skip this file as it is already loaded.
continue;
}
// Attempt to load it.
// Register the Jar file with the class loader.
try {
} catch (Exception e) {
if (debugEnabled()) {
}
throw new InitializationException(message);
}
}
// Now forcefully load the configuration definition classes.
}
}
/**
* Prints out all information about extensions.
*
* @return a String instance representing all information about extensions;
* <code>null</code> if there is no information available.
*/
public String printExtensionInformation() {
toString());
// no extensions' directory
return null;
}
// only files with names ending with ".jar"
}
});
return null;
}
// prints:
// --
// Name Build number Revision number
EOL,
"Name",
"Build number",
"Revision number",
EOL);
// retrieve MANIFEST entry and display name, build number and revision
// number
try {
{
continue;
}
boolean addBlank = false;
if ( addBlank ) {
} else {
addBlank = true;
}
}
} catch(Exception e) {
// ignore extra information for this extension
}
}
}
/**
* Returns a String array with the following information :
* <br>index 0: the name of the extension.
* <br>index 1: the build number of the extension.
* <br>index 2: the revision number of the extension.
*
* @param extension the jar file of the extension
* @return a String array containing the name, the build number and the
* revision number of the extension given in argument
* @throws java.io.IOException thrown if the jar file has been closed.
*/
// retrieve MANIFEST entry and display name, version and revision
int index = 0;
value = "<unknown>";
}
}
}
return result;
}
/**
* Put extensions jars into the class loader and load all
* configuration definition classes in that they contain.
* @param extensionsPath Indicates where extensions are located.
*
* @throws InitializationException
* If the extensions folder could not be accessed or if a
* extension jar file could not be accessed or if one of
* the configuration definition classes could not be
* initialized.
*/
throws InitializationException {
try {
if (!extensionsPath.exists()) {
// The extensions directory does not exist. This is not a
// critical problem.
return;
}
if (!extensionsPath.isDirectory()) {
// The extensions directory is not a directory. This is more
// critical.
throw new InitializationException(message);
}
// Get each extension file name.
/**
* Must be a Jar file.
*/
return false;
}
}
};
// Add and initialize the extensions.
} catch (InitializationException e) {
if (debugEnabled()) {
}
throw e;
} catch (Exception e) {
if (debugEnabled()) {
}
throw new InitializationException(message, e);
}
}
/**
* Make sure all core configuration definitions are loaded.
*
* @throws InitializationException
* If the core manifest file could not be read or if one
* of the configuration definition classes could not be
* initialized.
*/
private void initializeCoreComponents()
throws InitializationException {
+ CORE_MANIFEST);
throw new InitializationException(message);
}
try {
} catch (InitializationException e) {
if (debugEnabled()) {
}
throw new InitializationException(message);
}
}
/**
* Make sure all the configuration definition classes in a extension
* are loaded.
*
* @param jarFile
* The extension's Jar file.
* @throws InitializationException
* If the extension jar file could not be accessed or if
* one of the configuration definition classes could not
* be initialized.
*/
throws InitializationException {
try {
} catch (Exception e) {
if (debugEnabled()) {
}
throw new InitializationException(message);
}
try {
} catch (InitializationException e) {
if (debugEnabled()) {
}
throw new InitializationException(message);
}
try {
// Log build information of extensions in the error log
"$SERVER_ROOT"),
information[1],
information[2]));
} catch(Exception e) {
// Do not log information for that extension
}
}
}
/**
* Forcefully load configuration definition classes named in a
* manifest file.
*
* @param is
* The manifest file input stream.
* @throws InitializationException
* If the definition classes could not be loaded and
* initialized.
*/
throws InitializationException {
is));
new LinkedList<AbstractManagedObjectDefinition<?,?>>();
while (true) {
try {
} catch (IOException e) {
.valueOf(e.getMessage()));
throw new InitializationException(msg, e);
}
// Break out when the end of the manifest is reached.
break;
}
// Skip blank lines.
continue;
}
// Skip lines beginning with #.
continue;
}
// Load the class and get an instance of it if it is a definition.
try {
} catch (Exception e) {
.valueOf(e.getMessage()));
throw new InitializationException(msg, e);
}
// We need to instantiate it using its getInstance() static method.
try {
} catch (Exception e) {
throw new InitializationException(msg, e);
}
// Get the definition instance.
AbstractManagedObjectDefinition<?, ?> d;
try {
} catch (Exception e) {
throw new InitializationException(msg, e);
}
definitions.add(d);
}
}
// Initialize any definitions that were loaded.
for (AbstractManagedObjectDefinition<?, ?> d : definitions) {
try {
d.initialize();
} catch (Exception e) {
throw new InitializationException(msg, e);
}
}
}
/**
* Load the named Jar file.
*
* @param jar
* The name of the Jar file to load.
* @return Returns the loaded Jar file.
* @throws InitializationException
* If the Jar file could not be loaded.
*/
throws InitializationException {
try {
// Load the extension jar file.
} catch (Exception e) {
if (debugEnabled()) {
}
throw new InitializationException(message);
}
return jarFile;
}
}