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 }