1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
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
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
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 }