blob: 8412d6a29b0012fe4b7c4b6f6c56fa49d661cc36 [file] [log] [blame]
/*
* Copyright 2002,2004 The Apache Software Foundation.
*
* 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 org.apache.commons.jelly.impl;
import org.apache.commons.discovery.ResourceClass;
import org.apache.commons.discovery.ResourceClassIterator;
import org.apache.commons.discovery.resource.ClassLoaders;
import org.apache.commons.discovery.resource.classes.DiscoverClasses;
import org.apache.commons.jelly.TagLibrary;
import org.apache.commons.jelly.util.ClassLoaderUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* <p><code>DefaultTagLibraryResolver</code> is a default implemenation
* which attempts to interpret the URI as a String called 'jelly:className'
* and class load the given Java class. Otherwise META-INF/services/jelly/uri
* is searched for on the thread context's class path and, if found, that
* class will be loaded.</p>
*
* @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
* @version $Revision: 1.12 $
*/
public class DefaultTagLibraryResolver implements TagLibraryResolver {
/** The Log to which logging calls will be made. */
private static final Log log = LogFactory.getLog(DefaultTagLibraryResolver.class);
private DiscoverClasses discovery;
/**
* The class loader to use for instantiating application objects.
* If not specified, the context class loader, or the class loader
* used to load this class itself, is used, based on the value of the
* <code>useContextClassLoader</code> variable.
*/
private ClassLoader classLoader;
/**
* Do we want to use the Context ClassLoader when loading classes
* for instantiating new objects? Default is <code>false</code>.
*/
private boolean useContextClassLoader = false;
public DefaultTagLibraryResolver() {
}
// TagLibraryResolver interface
//-------------------------------------------------------------------------
/**
* Attempts to resolve the given URI to be associated with a TagLibrary
* otherwise null is returned to indicate no tag library could be found
* so that the namespace URI should be treated as just vanilla XML.
*/
public TagLibrary resolveTagLibrary(String uri) {
DiscoverClasses discovery = getDiscoverClasses();
String name = uri;
if ( uri.startsWith( "jelly:" ) ) {
name = "jelly." + uri.substring(6);
}
log.info( "Looking up service name: " + name );
/*
ClassLoaders loaders = ClassLoaders.getAppLoaders(TagLibrary.class, getClass(), false);
DiscoverClass discover = new DiscoverClass(loaders);
Class implClass = discover.find(TestInterface2.class);
TagLibrary answer = null;
try {
answer = (TagLibrary) DiscoverSingleton.find(TagLibrary.class, name);
}
catch (Exception e) {
log.error( "Could not load service: " + name );
}
return answer;
*/
ResourceClassIterator iter = discovery.findResourceClasses(name);
while (iter.hasNext()) {
ResourceClass resource = iter.nextResourceClass();
try {
Class typeClass = resource.loadClass();
if ( typeClass != null ) {
return newInstance(uri, typeClass);
}
}
catch (Exception e) {
log.error( "Could not load service: " + resource );
}
}
log.info( "Could not find any services for name: " + name );
return null;
}
// Properties
//-------------------------------------------------------------------------
/**
* Return the class loader to be used for instantiating application objects
* when required. This is determined based upon the following rules:
* <ul>
* <li>The class loader set by <code>setClassLoader()</code>, if any</li>
* <li>The thread context class loader, if it exists and the
* <code>useContextClassLoader</code> property is set to true</li>
* <li>The class loader used to load the XMLParser class itself.
* </ul>
*/
public ClassLoader getClassLoader() {
return ClassLoaderUtils.getClassLoader(classLoader, useContextClassLoader, getClass());
}
/**
* Set the class loader to be used for instantiating application objects
* when required.
*
* @param classLoader The new class loader to use, or <code>null</code>
* to revert to the standard rules
*/
public void setClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
}
/**
* Return the boolean as to whether the context classloader should be used.
*/
public boolean getUseContextClassLoader() {
return useContextClassLoader;
}
/**
* Determine whether to use the Context ClassLoader (the one found by
* calling <code>Thread.currentThread().getContextClassLoader()</code>)
* to resolve/load classes. If not
* using Context ClassLoader, then the class-loading defaults to
* using the calling-class' ClassLoader.
*
* @param boolean determines whether to use JellyContext ClassLoader.
*/
public void setUseContextClassLoader(boolean use) {
useContextClassLoader = use;
}
/**
* @return the DiscoverClasses instance to use to locate services.
* This object is lazily created if it has not been configured.
*/
public DiscoverClasses getDiscoverClasses() {
if ( discovery == null ) {
ClassLoaders loaders = ClassLoaders.getAppLoaders(TagLibrary.class, getClass(), false);
discovery = new DiscoverClasses(loaders);
}
return discovery;
}
/**
* Sets the fully configured DiscoverClasses instance to be used to
* lookup services
*/
public void setDiscoverClasses(DiscoverClasses discovery) {
this.discovery = discovery;
}
// Implementation methods
//-------------------------------------------------------------------------
/**
* Instantiates the given class name. Otherwise an exception is logged
* and null is returned
*/
protected TagLibrary loadClass(String uri, String className) {
try {
Class theClass = getClassLoader().loadClass(className);
if ( theClass != null ) {
return newInstance(uri, theClass);
}
}
catch (ClassNotFoundException e) {
log.error("Could not find the class: " + className + " when trying to resolve URI: " + uri, e);
}
return null;
}
/**
* Creates a new instance of the given TagLibrary class or
* return null if it could not be instantiated.
*/
protected TagLibrary newInstance(String uri, Class theClass) {
try {
Object object = theClass.newInstance();
if (object instanceof TagLibrary) {
return (TagLibrary) object;
}
else {
log.error(
"The tag library object mapped to: "
+ uri
+ " is not a TagLibrary. Object = "
+ object);
}
}
catch (Exception e) {
log.error(
"Could not instantiate instance of class: " + theClass.getName() + ". Reason: " + e,
e);
}
return null;
}
}