/*
Name:
- ClassLoaderResolver
Description:
-
Requires:
-
Provides:
-
Part of: ProcessPuzzle Framework, Domain and Business Model Ready Architecture. Provides content, workflow and social networking functionality.
http://www.processpuzzle.com
ProcessPuzzle - Content and Workflow Management Integration Business Platform
Author(s):
- Zsolt Zsuffa
Copyright: (C) 2011 This program is free software: you can redistribute it and/or modify it under the terms of the
GNU General Public License as published by the Free Software Foundation, either version 3 of the License,
or (at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.processpuzzle.application.configuration.domain;
// ----------------------------------------------------------------------------
/**
* This non-instantiable non-subclassable class acts as the global point for choosing a ClassLoader for dynamic
* class/resource loading at any point in an application.
*
* @see ResourceLoader
* @see IClassLoadStrategy
* @see DefaultClassLoadStrategy
* @author (C) <a href="http://www.javaworld.com/columns/jw-qna-index.shtml">Vlad Roubtsov</a>, 2003
*/
public abstract class ClassLoaderResolver {
// public: ................................................................
/**
* This method selects the "best" classloader instance to be used for class/resource loading by whoever calls this
* method. The decision typically involves choosing between the caller's current, thread context, system, and other
* classloaders in the JVM and is made by the {@link IClassLoadStrategy} instance established by the last call to
* {@link #setStrategy}.
*
* @return classloader to be used by the caller ['null' indicates the primordial loader]
*/
public static synchronized ClassLoader getClassLoader() {
final Class<?> caller = getCallerClass( 0 );
final ClassLoadContext ctx = new ClassLoadContext( caller );
return s_strategy.getClassLoader( ctx );
}
/**
* Gets the current classloader selection strategy setting.
*/
public static synchronized IClassLoadStrategy getStrategy() {
return s_strategy;
}
/**
* Sets the classloader selection strategy to be used by subsequent calls to {@link #getClassLoader()}. An instance
* of {@link DefaultClassLoadStrategy} is in effect if this method is never called.
*
* @param new strategy [may not be null]
* @return previous setting
*/
public static synchronized IClassLoadStrategy setStrategy( final IClassLoadStrategy strategy ) {
if( strategy == null )
throw new IllegalArgumentException( "null input: strategy" );
final IClassLoadStrategy old = s_strategy;
s_strategy = strategy;
return old;
}
// protected: .............................................................
// package: ...............................................................
/**
* A package-private version of {@link #getClassLoader()} with adjustable caller offset (useful for embedding this
* method in other library classes in this package).
*
* @param callerOffset
* extra call context depth offset to pass into getCallerClass().
*/
static synchronized ClassLoader getClassLoader( final int callerOffset ) {
final Class<?> caller = getCallerClass( callerOffset );
final ClassLoadContext ctx = new ClassLoadContext( caller );
return s_strategy.getClassLoader( ctx );
}
// private: ...............................................................
/**
* A helper class to get the call context. It subclasses SecurityManager to make getClassContext() accessible. An
* instance of CallerResolver only needs to be created, not installed as an actual security manager.
*/
private static final class CallerResolver extends SecurityManager {
protected Class<?>[] getClassContext() {
return super.getClassContext();
}
} // end of nested class
private ClassLoaderResolver() {} // prevent subclassing
/*
* Indexes into the current method call context with a given offset.
*/
private static Class<?> getCallerClass( final int callerOffset ) {
return CALLER_RESOLVER.getClassContext()[CALL_CONTEXT_OFFSET + callerOffset];
}
private static IClassLoadStrategy s_strategy; // initialized in <clinit>
private static final int CALL_CONTEXT_OFFSET = 3; // may need to change if this class is redesigned
private static final CallerResolver CALLER_RESOLVER; // set in <clinit>
static{
try{
// this can fail if the current SecurityManager does not allow
// RuntimePermission ("createSecurityManager"):
CALLER_RESOLVER = new CallerResolver();
}catch( SecurityException se ){
throw new RuntimeException( "ClassLoaderResolver: could not create CallerResolver: " + se );
}
s_strategy = new DefaultClassLoadStrategy();
}
} // end of class
// ----------------------------------------------------------------------------