View Javadoc

    1   /*
    2    * Copyright 2002,2004 The Apache Software Foundation.
    3    *
    4    * Licensed under the Apache License, Version 2.0 (the "License");
    5    * you may not use this file except in compliance with the License.
    6    * You may obtain a copy of the License at
    7    *
    8    *      http://www.apache.org/licenses/LICENSE-2.0
    9    *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  package org.apache.commons.jelly.impl;
    17
    18  import org.apache.commons.discovery.ResourceClass;
    19  import org.apache.commons.discovery.ResourceClassIterator;
    20  import org.apache.commons.discovery.resource.ClassLoaders;
    21  import org.apache.commons.discovery.resource.classes.DiscoverClasses;
    22  import org.apache.commons.jelly.TagLibrary;
    23  import org.apache.commons.jelly.util.ClassLoaderUtils;
    24  import org.apache.commons.logging.Log;
    25  import org.apache.commons.logging.LogFactory;
    26
    27
    28  /***
    29   * <p><code>DefaultTagLibraryResolver</code> is a default implemenation
    30   * which attempts to interpret the URI as a String called 'jelly:className'
    31   * and class load the given Java class. Otherwise META-INF/services/jelly/uri
    32   * is searched for on the thread context's class path and, if found, that
    33   * class will be loaded.</p>
    34   *
    35   * @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
    36   * @version $Revision: 155420 $
    37   */
    38  public class DefaultTagLibraryResolver implements TagLibraryResolver {
    39
    40      /*** The Log to which logging calls will be made. */
    41      private static final Log log = LogFactory.getLog(DefaultTagLibraryResolver.class);
    42
    43      private DiscoverClasses discovery;
    44
    45      /***
    46       * The class loader to use for instantiating application objects.
    47       * If not specified, the context class loader, or the class loader
    48       * used to load this class itself, is used, based on the value of the
    49       * <code>useContextClassLoader</code> variable.
    50       */
    51      private ClassLoader classLoader;
    52
    53      /***
    54       * Do we want to use the Context ClassLoader when loading classes
    55       * for instantiating new objects?  Default is <code>false</code>.
    56       */
    57      private boolean useContextClassLoader = false;
    58
    59
    60      public DefaultTagLibraryResolver() {
    61      }
    62
    63
    64      // TagLibraryResolver interface
    65      //-------------------------------------------------------------------------
    66
    67      /***
    68       * Attempts to resolve the given URI to be associated with a TagLibrary
    69       * otherwise null is returned to indicate no tag library could be found
    70       * so that the namespace URI should be treated as just vanilla XML.
    71       */
    72      public TagLibrary resolveTagLibrary(String uri) {
    73          DiscoverClasses discovery = getDiscoverClasses();
    74          String name = uri;
    75          if ( uri.startsWith( "jelly:" ) ) {
    76              name = "jelly." + uri.substring(6);
    77          }
    78
    79          log.info( "Looking up service name: " + name );
    80
    81  /*
    82          ClassLoaders loaders = ClassLoaders.getAppLoaders(TagLibrary.class, getClass(), false);
    83
    84          DiscoverClass discover = new DiscoverClass(loaders);
    85          Class implClass = discover.find(TestInterface2.class);
    86
    87
    88
    89          TagLibrary answer = null;
    90          try {
    91              answer = (TagLibrary) DiscoverSingleton.find(TagLibrary.class, name);
    92          }
    93          catch (Exception e) {
    94              log.error( "Could not load service: " + name );
    95          }
    96          return answer;
    97  */
    98          ResourceClassIterator iter = discovery.findResourceClasses(name);
    99          while (iter.hasNext()) {
    100             ResourceClass resource = iter.nextResourceClass();
    101             try {
    102                 Class typeClass = resource.loadClass();
    103                 if ( typeClass != null ) {
    104                     return newInstance(uri, typeClass);
    105                 }
    106             }
    107             catch (Exception e) {
    108                 log.error( "Could not load service: " + resource );
    109             }
    110         }
    111         log.info( "Could not find any services for name: " + name );
    112         return null;
    113     }
    114
    115     // Properties
    116     //-------------------------------------------------------------------------
    117
    118     /***
    119      * Return the class loader to be used for instantiating application objects
    120      * when required.  This is determined based upon the following rules:
    121      * <ul>
    122      * <li>The class loader set by <code>setClassLoader()</code>, if any</li>
    123      * <li>The thread context class loader, if it exists and the
    124      *     <code>useContextClassLoader</code> property is set to true</li>
    125      * <li>The class loader used to load the XMLParser class itself.
    126      * </ul>
    127      */
    128     public ClassLoader getClassLoader() {
    129         return ClassLoaderUtils.getClassLoader(classLoader, useContextClassLoader, getClass());
    130     }
    131
    132     /***
    133      * Set the class loader to be used for instantiating application objects
    134      * when required.
    135      *
    136      * @param classLoader The new class loader to use, or <code>null</code>
    137      *  to revert to the standard rules
    138      */
    139     public void setClassLoader(ClassLoader classLoader) {
    140         this.classLoader = classLoader;
    141     }
    142
    143     /***
    144      * Return the boolean as to whether the context classloader should be used.
    145      */
    146     public boolean getUseContextClassLoader() {
    147         return useContextClassLoader;
    148     }
    149
    150     /***
    151      * Determine whether to use the Context ClassLoader (the one found by
    152      * calling <code>Thread.currentThread().getContextClassLoader()</code>)
    153      * to resolve/load classes.  If not
    154      * using Context ClassLoader, then the class-loading defaults to
    155      * using the calling-class' ClassLoader.
    156      *
    157      * @param boolean determines whether to use JellyContext ClassLoader.
    158      */
    159     public void setUseContextClassLoader(boolean use) {
    160         useContextClassLoader = use;
    161     }
    162
    163     /***
    164      * @return the DiscoverClasses instance to use to locate services.
    165      *  This object is lazily created if it has not been configured.
    166      */
    167     public DiscoverClasses getDiscoverClasses() {
    168         if ( discovery == null ) {
    169             ClassLoaders loaders = ClassLoaders.getAppLoaders(TagLibrary.class, getClass(), false);
    170             discovery = new DiscoverClasses(loaders);
    171         }
    172         return discovery;
    173     }
    174
    175     /***
    176      * Sets the fully configured DiscoverClasses instance to be used to
    177      * lookup services
    178      */
    179     public void setDiscoverClasses(DiscoverClasses discovery) {
    180         this.discovery = discovery;
    181     }
    182
    183     // Implementation methods
    184     //-------------------------------------------------------------------------
    185
    186     /***
    187      * Instantiates the given class name. Otherwise an exception is logged
    188      * and null is returned
    189      */
    190     protected TagLibrary loadClass(String uri, String className) {
    191         try {
    192             Class theClass = getClassLoader().loadClass(className);
    193             if ( theClass != null ) {
    194                 return newInstance(uri, theClass);
    195             }
    196         }
    197         catch (ClassNotFoundException e) {
    198             log.error("Could not find the class: " + className + " when trying to resolve URI: " + uri, e);
    199         }
    200         return null;
    201     }
    202
    203
    204     /***
    205      * Creates a new instance of the given TagLibrary class or
    206      * return null if it could not be instantiated.
    207      */
    208     protected TagLibrary newInstance(String uri, Class theClass) {
    209         try {
    210             Object object = theClass.newInstance();
    211             if (object instanceof TagLibrary) {
    212                 return (TagLibrary) object;
    213             }
    214             else {
    215                 log.error(
    216                     "The tag library object mapped to: "
    217                         + uri
    218                         + " is not a TagLibrary. Object = "
    219                         + object);
    220             }
    221         }
    222         catch (Exception e) {
    223             log.error(
    224                 "Could not instantiate instance of class: " + theClass.getName() + ". Reason: " + e,
    225                 e);
    226         }
    227         return null;
    228     }
    229
    230 }