%line | %branch | |||||||||
---|---|---|---|---|---|---|---|---|---|---|
org.apache.commons.jelly.JellyContext |
|
|
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; |
|
17 | ||
18 | import java.io.File; |
|
19 | import java.io.IOException; |
|
20 | import java.io.InputStream; |
|
21 | import java.net.MalformedURLException; |
|
22 | import java.net.URL; |
|
23 | import java.util.Collections; |
|
24 | import java.util.HashMap; |
|
25 | import java.util.Hashtable; |
|
26 | import java.util.Iterator; |
|
27 | import java.util.Map; |
|
28 | import java.util.WeakHashMap; |
|
29 | ||
30 | import org.apache.commons.jelly.parser.XMLParser; |
|
31 | import org.apache.commons.jelly.util.ClassLoaderUtils; |
|
32 | import org.apache.commons.logging.Log; |
|
33 | import org.apache.commons.logging.LogFactory; |
|
34 | import org.xml.sax.InputSource; |
|
35 | import org.xml.sax.SAXException; |
|
36 | ||
37 | /** |
|
38 | * <p><code>JellyContext</code> represents the Jelly context.</p> |
|
39 | * |
|
40 | * @author <a href="mailto:jstrachan@apache.org">James Strachan</a> |
|
41 | * @version $Revision: 165507 $ |
|
42 | */ |
|
43 | public class JellyContext { |
|
44 | ||
45 | /** The Log to which logging calls will be made. */ |
|
46 | 650 | private static final Log log = LogFactory.getLog(JellyContext.class); |
47 | ||
48 | /** Default for inheritance of variables **/ |
|
49 | private static final boolean DEFAULT_INHERIT = true; |
|
50 | ||
51 | /** Default for export of variables **/ |
|
52 | private static final boolean DEFAULT_EXPORT = false; |
|
53 | ||
54 | /** String used to denote a script can't be parsed */ |
|
55 | private static final String BAD_PARSE = "Could not parse Jelly script"; |
|
56 | ||
57 | /** |
|
58 | * The class loader to use for instantiating application objects. |
|
59 | * If not specified, the context class loader, or the class loader |
|
60 | * used to load this class itself, is used, based on the value of the |
|
61 | * <code>useContextClassLoader</code> variable. |
|
62 | */ |
|
63 | protected ClassLoader classLoader; |
|
64 | ||
65 | /** |
|
66 | * Do we want to use the Context ClassLoader when loading classes |
|
67 | * for instantiating new objects? Default is <code>false</code>. |
|
68 | */ |
|
69 | 3445 | protected boolean useContextClassLoader = false; |
70 | ||
71 | /** The root URL context (where scripts are located from) */ |
|
72 | private URL rootURL; |
|
73 | ||
74 | /** The current URL context (where relative scripts are located from) */ |
|
75 | private URL currentURL; |
|
76 | ||
77 | /** Tag libraries found so far */ |
|
78 | 3445 | private Map taglibs = new Hashtable(); |
79 | ||
80 | /** synchronized access to the variables in scope */ |
|
81 | 3445 | private Map variables = new Hashtable(); |
82 | ||
83 | /** The parent context */ |
|
84 | private JellyContext parent; |
|
85 | ||
86 | /** Do we inherit variables from parent context? */ |
|
87 | 3445 | private boolean inherit = JellyContext.DEFAULT_INHERIT; |
88 | ||
89 | /** Do we export our variables to parent context? */ |
|
90 | 3445 | private boolean export = JellyContext.DEFAULT_EXPORT; |
91 | ||
92 | /** Should we export tag libraries to our parents context */ |
|
93 | 3445 | private boolean exportLibraries = true; |
94 | ||
95 | /** |
|
96 | * Create a new context with the currentURL set to the rootURL |
|
97 | */ |
|
98 | 2210 | public JellyContext() { |
99 | 2210 | this.currentURL = rootURL; |
100 | 2210 | init(); |
101 | 2210 | } |
102 | ||
103 | /** |
|
104 | * Create a new context with the given rootURL |
|
105 | * @param rootURL the root URL used in resolving absolute resources i.e. those starting with '/' |
|
106 | */ |
|
107 | public JellyContext(URL rootURL) { |
|
108 | 13 | this( rootURL, rootURL ); |
109 | 13 | } |
110 | ||
111 | /** |
|
112 | * Create a new context with the given rootURL and currentURL |
|
113 | * @param rootURL the root URL used in resolving absolute resources i.e. those starting with '/' |
|
114 | * @param currentURL the root URL used in resolving relative resources |
|
115 | */ |
|
116 | 832 | public JellyContext(URL rootURL, URL currentURL) { |
117 | 832 | this.rootURL = rootURL; |
118 | 832 | this.currentURL = currentURL; |
119 | 832 | init(); |
120 | 832 | } |
121 | ||
122 | ||
123 | /** |
|
124 | * Create a new context with the given parent context. |
|
125 | * The parent's rootURL and currentURL are set on the child, and the parent's variables are |
|
126 | * available in the child context under the name <code>parentScope</code>. |
|
127 | * |
|
128 | * @param parent the parent context for the newly created context. |
|
129 | */ |
|
130 | 403 | public JellyContext(JellyContext parent) { |
131 | 403 | this.parent = parent; |
132 | 403 | this.rootURL = parent.rootURL; |
133 | 403 | this.currentURL = parent.currentURL; |
134 | 403 | this.variables.put("parentScope", parent.variables); |
135 | 403 | init(); |
136 | 403 | } |
137 | ||
138 | /** |
|
139 | * Create a new context with the given parent context. |
|
140 | * The parent's rootURL are set on the child, and the parent's variables are |
|
141 | * available in the child context under the name <code>parentScope</code>. |
|
142 | * |
|
143 | * @param parentJellyContext the parent context for the newly created context. |
|
144 | * @param currentURL the root URL used in resolving relative resources |
|
145 | */ |
|
146 | public JellyContext(JellyContext parentJellyContext, URL currentURL) { |
|
147 | 0 | this(parentJellyContext); |
148 | 0 | this.currentURL = currentURL; |
149 | 0 | } |
150 | ||
151 | /** |
|
152 | * Create a new context with the given parent context. |
|
153 | * The parent's variables are available in the child context under the name <code>parentScope</code>. |
|
154 | * |
|
155 | * @param parentJellyContext the parent context for the newly created context. |
|
156 | * @param rootURL the root URL used in resolving absolute resources i.e. those starting with '/' |
|
157 | * @param currentURL the root URL used in resolving relative resources |
|
158 | */ |
|
159 | public JellyContext(JellyContext parentJellyContext, URL rootURL, URL currentURL) { |
|
160 | 0 | this(parentJellyContext, currentURL); |
161 | 0 | this.rootURL = rootURL; |
162 | 0 | } |
163 | ||
164 | /** |
|
165 | * Initialize the context. |
|
166 | * This includes adding the context to itself under the name <code>context</code> and |
|
167 | * making the System Properties available as <code>systemScope</code> |
|
168 | */ |
|
169 | private void init() { |
|
170 | 3445 | variables.put("context",this); |
171 | try { |
|
172 | 3445 | variables.put("systemScope", System.getProperties() ); |
173 | 0 | } catch (SecurityException e) { |
174 | 0 | log.debug("security exception accessing system properties", e); |
175 | 3445 | } |
176 | 3445 | } |
177 | ||
178 | /** |
|
179 | * @return the parent context for this context |
|
180 | */ |
|
181 | public JellyContext getParent() { |
|
182 | 9100 | return parent; |
183 | } |
|
184 | ||
185 | /** |
|
186 | * @return the scope of the given name, such as the 'parent' scope. |
|
187 | * If Jelly is used in a Servlet situation then 'request', 'session' and 'application' are other names |
|
188 | * for scopes |
|
189 | */ |
|
190 | public JellyContext getScope(String name) { |
|
191 | 0 | if ( "parent".equals( name ) ) { |
192 | 0 | return getParent(); |
193 | } |
|
194 | 0 | return null; |
195 | } |
|
196 | ||
197 | /** |
|
198 | * Finds the variable value of the given name in this context or in any other parent context. |
|
199 | * If this context does not contain the variable, then its parent is used and then its parent |
|
200 | * and so forth until the context with no parent is found. |
|
201 | * |
|
202 | * @return the value of the variable in this or one of its descendant contexts or null |
|
203 | * if the variable could not be found. |
|
204 | */ |
|
205 | public Object findVariable(String name) { |
|
206 | 0 | Object answer = variables.get(name); |
207 | 0 | boolean definedHere = answer != null || variables.containsKey(name); |
208 | ||
209 | 0 | if (definedHere) return answer; |
210 | ||
211 | 0 | if ( answer == null && parent != class="keyword">null ) { |
212 | 0 | answer = parent.findVariable(name); |
213 | } |
|
214 | // ### this is a hack - remove this when we have support for pluggable Scopes |
|
215 | 0 | if ( answer == null ) { |
216 | 0 | answer = getSystemProperty(name); |
217 | } |
|
218 | ||
219 | 0 | if (log.isDebugEnabled()) { |
220 | 0 | log.debug("findVariable: " + name + " value: " + answer ); |
221 | } |
|
222 | 0 | return answer; |
223 | } |
|
224 | ||
225 | ||
226 | /** @return the value of the given variable name */ |
|
227 | public Object getVariable(String name) { |
|
228 | 17576 | Object value = variables.get(name); |
229 | 17576 | boolean definedHere = value != null || variables.containsKey(name); |
230 | ||
231 | 17576 | if (definedHere) return value; |
232 | ||
233 | 9113 | if ( value == null && isInherit() ) { |
234 | 9061 | JellyContext parentContext = getParent(); |
235 | 9061 | if (parentContext != null) { |
236 | 416 | value = parentContext.getVariable( name ); |
237 | } |
|
238 | } |
|
239 | ||
240 | // ### this is a hack - remove this when we have support for pluggable Scopes |
|
241 | 9113 | if ( value == null ) { |
242 | 9074 | value = getSystemProperty(name); |
243 | } |
|
244 | ||
245 | 9113 | return value; |
246 | } |
|
247 | ||
248 | /** |
|
249 | * Get a system property and handle security exceptions |
|
250 | * @param name the name of the property to retrieve |
|
251 | * @return the value of the property, or null if a SecurityException occurs |
|
252 | */ |
|
253 | private Object getSystemProperty(String name) { |
|
254 | try { |
|
255 | 9074 | return System.getProperty(name); |
256 | } |
|
257 | 0 | catch (SecurityException e) { |
258 | 0 | log.debug("security exception accessing system properties", e); |
259 | } |
|
260 | 0 | return null; |
261 | } |
|
262 | ||
263 | /** |
|
264 | * @return the value of the given variable name in the given variable scope |
|
265 | * @param name is the name of the variable |
|
266 | * @param scopeName is the optional scope name such as 'parent'. For servlet environments |
|
267 | * this could be 'application', 'session' or 'request'. |
|
268 | */ |
|
269 | public Object getVariable(String name, String scopeName) { |
|
270 | 0 | JellyContext scope = getScope(scopeName); |
271 | 0 | if ( scope != null ) { |
272 | 0 | return scope.getVariable(name); |
273 | } |
|
274 | 0 | return null; |
275 | } |
|
276 | ||
277 | ||
278 | ||
279 | /** Sets the value of the named variable */ |
|
280 | public void setVariable(String name, Object value) { |
|
281 | 6448 | if ( isExport() ) { |
282 | 39 | getParent().setVariable( name, value ); |
283 | 39 | return; |
284 | } |
|
285 | 6409 | if (value == null) { |
286 | 52 | variables.remove(name); |
287 | 52 | } |
288 | else { |
|
289 | 6357 | variables.put(name, value); |
290 | } |
|
291 | 6409 | } |
292 | ||
293 | /** |
|
294 | * Sets the value of the given variable name in the given variable scope |
|
295 | * @param name is the name of the variable |
|
296 | * @param scopeName is the optional scope name such as 'parent'. For servlet environments |
|
297 | * this could be 'application', 'session' or 'request'. |
|
298 | * @param value is the value of the attribute |
|
299 | */ |
|
300 | public void setVariable(String name, String scopeName, Object value) { |
|
301 | 0 | JellyContext scope = getScope(scopeName); |
302 | 0 | if ( scope != null ) { |
303 | 0 | scope.setVariable(name, value); |
304 | } |
|
305 | 0 | } |
306 | ||
307 | /** Removes the given variable */ |
|
308 | public void removeVariable(String name) { |
|
309 | 78 | variables.remove(name); |
310 | 78 | } |
311 | ||
312 | /** |
|
313 | * Removes the given variable in the specified scope. |
|
314 | * |
|
315 | * @param name is the name of the variable |
|
316 | * @param scopeName is the optional scope name such as 'parent'. For servlet environments |
|
317 | * this could be 'application', 'session' or 'request'. |
|
318 | */ |
|
319 | public void removeVariable(String name, String scopeName) { |
|
320 | 0 | JellyContext scope = getScope(scopeName); |
321 | 0 | if ( scope != null ) { |
322 | 0 | scope.removeVariable(name); |
323 | } |
|
324 | 0 | } |
325 | ||
326 | /** |
|
327 | * @return an Iterator over the current variable names in this |
|
328 | * context |
|
329 | */ |
|
330 | public Iterator getVariableNames() { |
|
331 | 0 | return variables.keySet().iterator(); |
332 | } |
|
333 | ||
334 | /** |
|
335 | * @return the Map of variables in this scope |
|
336 | */ |
|
337 | public Map getVariables() { |
|
338 | 0 | return variables; |
339 | } |
|
340 | ||
341 | /** |
|
342 | * Sets the Map of variables to use |
|
343 | */ |
|
344 | public void setVariables(Map variables) { |
|
345 | // I have seen this fail when the passed Map contains a key, value |
|
346 | // pair where the value is null |
|
347 | 13 | for (Iterator iter = variables.entrySet().iterator(); iter.hasNext();) { |
348 | 0 | Map.Entry element = (Map.Entry) iter.next(); |
349 | 0 | if (element.getValue() != null) { |
350 | 0 | this.variables.put(element.getKey(), element.getValue()); |
351 | } |
|
352 | 0 | } |
353 | //this.variables.putAll( variables ); |
|
354 | 13 | } |
355 | ||
356 | /** |
|
357 | * A factory method to create a new child context of the |
|
358 | * current context. |
|
359 | */ |
|
360 | public JellyContext newJellyContext(Map newVariables) { |
|
361 | // XXXX: should allow this new context to |
|
362 | // XXXX: inherit parent contexts? |
|
363 | // XXXX: Or at least publish the parent scope |
|
364 | // XXXX: as a Map in this new variable scope? |
|
365 | 0 | newVariables.put("parentScope", variables); |
366 | 0 | JellyContext answer = createChildContext(); |
367 | 0 | answer.setVariables(newVariables); |
368 | 0 | return answer; |
369 | } |
|
370 | ||
371 | /** |
|
372 | * A factory method to create a new child context of the |
|
373 | * current context. |
|
374 | */ |
|
375 | public JellyContext newJellyContext() { |
|
376 | 156 | return createChildContext(); |
377 | } |
|
378 | ||
379 | /** Clears variables set by Tags. |
|
380 | * @see #clearVariables() |
|
381 | */ |
|
382 | public void clear() { |
|
383 | 0 | clearVariables(); |
384 | 0 | } |
385 | ||
386 | /** Clears variables set by Tags (variables set while running a Jelly script) |
|
387 | * @see #clear() |
|
388 | */ |
|
389 | protected void clearVariables() { |
|
390 | 0 | variables.clear(); |
391 | 0 | } |
392 | ||
393 | /** Registers the given tag library against the given namespace URI. |
|
394 | * This should be called before the parser is used. |
|
395 | */ |
|
396 | public void registerTagLibrary(String namespaceURI, TagLibrary taglib) { |
|
397 | 52 | if (log.isDebugEnabled()) { |
398 | 0 | log.debug("Registering tag library to: " + namespaceURI + " taglib: " + taglib); |
399 | } |
|
400 | 52 | taglibs.put(namespaceURI, taglib); |
401 | ||
402 | 52 | if (isExportLibraries() && parent != null) { |
403 | 0 | parent.registerTagLibrary( namespaceURI, taglib ); |
404 | } |
|
405 | 52 | } |
406 | ||
407 | /** Registers the given tag library class name against the given namespace URI. |
|
408 | * The class will be loaded via the given ClassLoader |
|
409 | * This should be called before the parser is used. |
|
410 | */ |
|
411 | public void registerTagLibrary( |
|
412 | String namespaceURI, |
|
413 | String className) { |
|
414 | ||
415 | 35074 | if (log.isDebugEnabled()) { |
416 | 0 | log.debug("Registering tag library to: " + namespaceURI + " taglib: " + className); |
417 | } |
|
418 | 35074 | taglibs.put(namespaceURI, className); |
419 | ||
420 | 35074 | if (isExportLibraries() && parent != null) { |
421 | 0 | parent.registerTagLibrary( namespaceURI, className ); |
422 | } |
|
423 | 35074 | } |
424 | ||
425 | public boolean isTagLibraryRegistered(String namespaceURI) { |
|
426 | 42978 | boolean answer = taglibs.containsKey( namespaceURI ); |
427 | 42978 | if (answer) { |
428 | 3952 | return true; |
429 | } |
|
430 | 39026 | else if ( parent != null ) { |
431 | 3952 | return parent.isTagLibraryRegistered(namespaceURI); |
432 | } |
|
433 | else { |
|
434 | 35074 | return false; |
435 | } |
|
436 | } |
|
437 | ||
438 | /** |
|
439 | * @return the TagLibrary for the given namespace URI or null if one could not be found |
|
440 | */ |
|
441 | public TagLibrary getTagLibrary(String namespaceURI) { |
|
442 | ||
443 | // use my own mapping first, so that namespaceURIs can |
|
444 | // be redefined inside child contexts... |
|
445 | ||
446 | 20449 | Object answer = taglibs.get(namespaceURI); |
447 | ||
448 | 20449 | if ( answer == null && parent != class="keyword">null ) { |
449 | 312 | answer = parent.getTagLibrary( namespaceURI ); |
450 | } |
|
451 | ||
452 | 20449 | if ( answer instanceof TagLibrary ) { |
453 | 18941 | return (TagLibrary) answer; |
454 | } |
|
455 | 1508 | else if ( answer instanceof String ) { |
456 | 936 | String className = (String) answer; |
457 | 936 | Class theClass = null; |
458 | try { |
|
459 | 936 | theClass = getClassLoader().loadClass(className); |
460 | } |
|
461 | 0 | catch (ClassNotFoundException e) { |
462 | 0 | log.error("Could not find the class: " + className, e); |
463 | 936 | } |
464 | 936 | if ( theClass != null ) { |
465 | try { |
|
466 | 936 | Object object = theClass.newInstance(); |
467 | 936 | if (object instanceof TagLibrary) { |
468 | 936 | taglibs.put(namespaceURI, object); |
469 | 936 | return (TagLibrary) object; |
470 | } |
|
471 | else { |
|
472 | 0 | log.error( |
473 | "The tag library object mapped to: " |
|
474 | + namespaceURI |
|
475 | + " is not a TagLibrary. Object = " |
|
476 | + object); |
|
477 | } |
|
478 | } |
|
479 | 0 | catch (Exception e) { |
480 | 0 | log.error( |
481 | "Could not instantiate instance of class: " + className + ". Reason: " + e, |
|
482 | e); |
|
483 | 0 | } |
484 | } |
|
485 | } |
|
486 | ||
487 | 572 | return null; |
488 | } |
|
489 | ||
490 | /** |
|
491 | * Attempts to parse the script from the given uri using the |
|
492 | * {@link #getResource} method then returns the compiled script. |
|
493 | */ |
|
494 | public Script compileScript(String uri) throws JellyException { |
|
495 | 0 | XMLParser parser = getXMLParser(); |
496 | 0 | parser.setContext(this); |
497 | 0 | InputStream in = getResourceAsStream(uri); |
498 | 0 | if (in == null) { |
499 | 0 | throw new JellyException("Could not find Jelly script: " + uri); |
500 | } |
|
501 | 0 | Script script = null; |
502 | try { |
|
503 | 0 | script = parser.parse(in); |
504 | 0 | } catch (IOException e) { |
505 | 0 | throw new JellyException(JellyContext.BAD_PARSE, e); |
506 | 0 | } catch (SAXException e) { |
507 | 0 | throw new JellyException(JellyContext.BAD_PARSE, e); |
508 | 0 | } |
509 | ||
510 | 0 | return script.compile(); |
511 | } |
|
512 | ||
513 | /** |
|
514 | * Attempts to parse the script from the given URL using the |
|
515 | * {@link #getResource} method then returns the compiled script. |
|
516 | */ |
|
517 | public Script compileScript(URL url) throws JellyException { |
|
518 | 0 | XMLParser parser = getXMLParser(); |
519 | 0 | parser.setContext(this); |
520 | ||
521 | 0 | Script script = null; |
522 | try { |
|
523 | 0 | script = parser.parse(url.toString()); |
524 | 0 | } catch (IOException e) { |
525 | 0 | throw new JellyException(JellyContext.BAD_PARSE, e); |
526 | 0 | } catch (SAXException e) { |
527 | 0 | throw new JellyException(JellyContext.BAD_PARSE, e); |
528 | 0 | } |
529 | ||
530 | 0 | return script.compile(); |
531 | } |
|
532 | ||
533 | /** |
|
534 | * Attempts to parse the script from the given InputSource using the |
|
535 | * {@link #getResource} method then returns the compiled script. |
|
536 | */ |
|
537 | public Script compileScript(InputSource source) throws JellyException { |
|
538 | 130 | XMLParser parser = getXMLParser(); |
539 | 130 | parser.setContext(this); |
540 | ||
541 | 130 | Script script = null; |
542 | try { |
|
543 | 130 | script = parser.parse(source); |
544 | 0 | } catch (IOException e) { |
545 | 0 | throw new JellyException(JellyContext.BAD_PARSE, e); |
546 | 0 | } catch (SAXException e) { |
547 | 0 | throw new JellyException(JellyContext.BAD_PARSE, e); |
548 | 130 | } |
549 | ||
550 | 130 | return script.compile(); |
551 | } |
|
552 | ||
553 | /** |
|
554 | * @return a thread pooled XMLParser to avoid the startup overhead |
|
555 | * of the XMLParser |
|
556 | */ |
|
557 | protected XMLParser getXMLParser() { |
|
558 | 130 | XMLParser parser = createXMLParser(); |
559 | 130 | return parser; |
560 | } |
|
561 | ||
562 | /** |
|
563 | * Factory method to allow JellyContext implementations to overload how an XMLParser |
|
564 | * is created - such as to overload what the default ExpressionFactory should be. |
|
565 | */ |
|
566 | protected XMLParser createXMLParser() { |
|
567 | 130 | return new XMLParser(); |
568 | } |
|
569 | ||
570 | /** |
|
571 | * Parses the script from the given File then compiles it and runs it. |
|
572 | * |
|
573 | * @return the new child context that was used to run the script |
|
574 | */ |
|
575 | public JellyContext runScript(File file, XMLOutput output) throws JellyException { |
|
576 | try { |
|
577 | 0 | return runScript(file.toURL(), output, JellyContext.DEFAULT_EXPORT, |
578 | JellyContext.DEFAULT_INHERIT); |
|
579 | 0 | } catch (MalformedURLException e) { |
580 | 0 | throw new JellyException(e.toString()); |
581 | } |
|
582 | } |
|
583 | ||
584 | /** |
|
585 | * Parses the script from the given URL then compiles it and runs it. |
|
586 | * |
|
587 | * @return the new child context that was used to run the script |
|
588 | */ |
|
589 | public JellyContext runScript(URL url, XMLOutput output) throws JellyException { |
|
590 | 13 | return runScript(url, output, JellyContext.DEFAULT_EXPORT, |
591 | JellyContext.DEFAULT_INHERIT); |
|
592 | } |
|
593 | ||
594 | /** |
|
595 | * Parses the script from the given InputSource then compiles it and runs it. |
|
596 | * |
|
597 | * @return the new child context that was used to run the script |
|
598 | */ |
|
599 | public JellyContext runScript(InputSource source, XMLOutput output) throws JellyException { |
|
600 | 13 | return runScript(source, output, JellyContext.DEFAULT_EXPORT, |
601 | JellyContext.DEFAULT_INHERIT); |
|
602 | } |
|
603 | ||
604 | /** |
|
605 | * Parses the script from the given uri using the |
|
606 | * JellyContext.getResource() API then compiles it and runs it. |
|
607 | * |
|
608 | * @return the new child context that was used to run the script |
|
609 | */ |
|
610 | public JellyContext runScript(String uri, XMLOutput output) throws JellyException { |
|
611 | 0 | URL url = null; |
612 | try { |
|
613 | 0 | url = getResource(uri); |
614 | 0 | } catch (MalformedURLException e) { |
615 | 0 | throw new JellyException(e.toString()); |
616 | 0 | } |
617 | ||
618 | 0 | if (url == null) { |
619 | 0 | throw new JellyException("Could not find Jelly script: " + url); |
620 | } |
|
621 | 0 | return runScript(url, output, JellyContext.DEFAULT_EXPORT, |
622 | JellyContext.DEFAULT_INHERIT); |
|
623 | } |
|
624 | ||
625 | /** |
|
626 | * Parses the script from the given uri using the |
|
627 | * JellyContext.getResource() API then compiles it and runs it. |
|
628 | * |
|
629 | * @return the new child context that was used to run the script |
|
630 | */ |
|
631 | public JellyContext runScript(String uri, XMLOutput output, |
|
632 | boolean export, class="keyword">boolean inherit) throws JellyException { |
|
633 | 104 | URL url = null; |
634 | try { |
|
635 | 104 | url = getResource(uri); |
636 | 0 | } catch (MalformedURLException e) { |
637 | 0 | throw new JellyException(e.toString()); |
638 | 104 | } |
639 | ||
640 | 104 | if (url == null) { |
641 | 0 | throw new JellyException("Could not find Jelly script: " + url); |
642 | } |
|
643 | ||
644 | 104 | return runScript(url, output, export, inherit); |
645 | } |
|
646 | ||
647 | /** |
|
648 | * Parses the script from the given file then compiles it and runs it. |
|
649 | * |
|
650 | * @return the new child context that was used to run the script |
|
651 | */ |
|
652 | public JellyContext runScript(File file, XMLOutput output, |
|
653 | boolean export, class="keyword">boolean inherit) throws JellyException { |
|
654 | try { |
|
655 | 0 | return runScript(file.toURL(), output, export, inherit); |
656 | 0 | } catch (MalformedURLException e) { |
657 | 0 | throw new JellyException(e.toString()); |
658 | } |
|
659 | } |
|
660 | ||
661 | /** |
|
662 | * Parses the script from the given URL then compiles it and runs it. |
|
663 | * |
|
664 | * @return the new child context that was used to run the script |
|
665 | */ |
|
666 | public JellyContext runScript(URL url, XMLOutput output, |
|
667 | boolean export, class="keyword">boolean inherit) throws JellyException { |
|
668 | 117 | return runScript(new InputSource(url.toString()), output, export, inherit); |
669 | } |
|
670 | ||
671 | /** |
|
672 | * Parses the script from the given InputSource then compiles it and runs it. |
|
673 | * |
|
674 | * @return the new child context that was used to run the script |
|
675 | */ |
|
676 | public JellyContext runScript(InputSource source, XMLOutput output, |
|
677 | boolean export, class="keyword">boolean inherit) throws JellyException { |
|
678 | 130 | Script script = compileScript(source); |
679 | ||
680 | 130 | URL newJellyContextURL = null; |
681 | try { |
|
682 | 130 | newJellyContextURL = getJellyContextURL(source); |
683 | 0 | } catch (MalformedURLException e) { |
684 | 0 | throw new JellyException(e.toString()); |
685 | 130 | } |
686 | ||
687 | 130 | JellyContext newJellyContext = newJellyContext(); |
688 | 130 | newJellyContext.setRootURL( newJellyContextURL ); |
689 | 130 | newJellyContext.setCurrentURL( newJellyContextURL ); |
690 | 130 | newJellyContext.setExport( export ); |
691 | 130 | newJellyContext.setInherit( inherit ); |
692 | ||
693 | 130 | if ( inherit ) { |
694 | // use the same variable scopes |
|
695 | 104 | newJellyContext.variables = this.variables; |
696 | } |
|
697 | ||
698 | 130 | if (log.isDebugEnabled() ) { |
699 | 0 | log.debug( "About to run script: " + source.getSystemId() ); |
700 | 0 | log.debug( "root context URL: " + newJellyContext.rootURL ); |
701 | 0 | log.debug( "current context URL: " + newJellyContext.currentURL ); |
702 | } |
|
703 | ||
704 | 130 | script.run(newJellyContext, output); |
705 | ||
706 | 130 | return newJellyContext; |
707 | } |
|
708 | ||
709 | /** |
|
710 | * Returns a URL for the given resource from the specified path. |
|
711 | * If the uri starts with "/" then the path is taken as relative to |
|
712 | * the current context root. |
|
713 | * If the uri is a well formed URL then it is used. |
|
714 | * If the uri is a file that exists and can be read then it is used. |
|
715 | * Otherwise the uri is interpreted as relative to the current context (the |
|
716 | * location of the current script). |
|
717 | */ |
|
718 | public URL getResource(String uri) throws MalformedURLException { |
|
719 | 104 | if (uri.startsWith("/")) { |
720 | // append this uri to the context root |
|
721 | 0 | return createRelativeURL(rootURL, uri.substring(1)); |
722 | } |
|
723 | else { |
|
724 | try { |
|
725 | 104 | return new URL(uri); |
726 | } |
|
727 | 104 | catch (MalformedURLException e) { |
728 | // lets try find a relative resource |
|
729 | try { |
|
730 | 104 | return createRelativeURL(currentURL, uri); |
731 | 0 | } catch (MalformedURLException e2) { |
732 | 0 | throw e; |
733 | } |
|
734 | } |
|
735 | } |
|
736 | } |
|
737 | ||
738 | /** |
|
739 | * Attempts to open an InputStream to the given resource at the specified path. |
|
740 | * If the uri starts with "/" then the path is taken as relative to |
|
741 | * the current context root. If the uri is a well formed URL then it |
|
742 | * is used. Otherwise the uri is interpreted as relative to the current |
|
743 | * context (the location of the current script). |
|
744 | * |
|
745 | * @return null if this resource could not be loaded, otherwise the resources |
|
746 | * input stream is returned. |
|
747 | */ |
|
748 | public InputStream getResourceAsStream(String uri) { |
|
749 | try { |
|
750 | 0 | URL url = getResource(uri); |
751 | 0 | return url.openStream(); |
752 | } |
|
753 | 0 | catch (Exception e) { |
754 | 0 | if (log.isTraceEnabled()) { |
755 | 0 | log.trace( |
756 | "Caught exception attempting to open: " + uri + ". Exception: " + e, |
|
757 | e); |
|
758 | } |
|
759 | 0 | return null; |
760 | } |
|
761 | } |
|
762 | ||
763 | ||
764 | // Properties |
|
765 | //------------------------------------------------------------------------- |
|
766 | ||
767 | /** |
|
768 | * @return the current root context URL from which all absolute resource URIs |
|
769 | * will be relative to. For example in a web application the root URL will |
|
770 | * map to the web directory which contains the WEB-INF directory. |
|
771 | */ |
|
772 | public URL getRootURL() { |
|
773 | 25259 | return rootURL; |
774 | } |
|
775 | ||
776 | /** |
|
777 | * Sets the current root context URL from which all absolute resource URIs |
|
778 | * will be relative to. For example in a web application the root URL will |
|
779 | * map to the web directory which contains the WEB-INF directory. |
|
780 | */ |
|
781 | public void setRootURL(URL rootURL) { |
|
782 | 13299 | this.rootURL = rootURL; |
783 | 13299 | } |
784 | ||
785 | ||
786 | /** |
|
787 | * @return the current URL context of the current script that is executing. |
|
788 | * This URL context is used to deduce relative scripts when relative URIs are |
|
789 | * used in calls to {@link #getResource} to process relative scripts. |
|
790 | */ |
|
791 | public URL getCurrentURL() { |
|
792 | 25584 | return currentURL; |
793 | } |
|
794 | ||
795 | /** |
|
796 | * Sets the current URL context of the current script that is executing. |
|
797 | * This URL context is used to deduce relative scripts when relative URIs are |
|
798 | * used in calls to {@link #getResource} to process relative scripts. |
|
799 | */ |
|
800 | public void setCurrentURL(URL currentURL) { |
|
801 | 13299 | this.currentURL = currentURL; |
802 | 13299 | } |
803 | ||
804 | /** |
|
805 | * Returns whether we export tag libraries to our parents context |
|
806 | * @return boolean |
|
807 | */ |
|
808 | public boolean isExportLibraries() { |
|
809 | 35126 | return exportLibraries; |
810 | } |
|
811 | ||
812 | /** |
|
813 | * Sets whether we export tag libraries to our parents context |
|
814 | * @param exportLibraries The exportLibraries to set |
|
815 | */ |
|
816 | public void setExportLibraries(boolean exportLibraries) { |
|
817 | 247 | this.exportLibraries = exportLibraries; |
818 | 247 | } |
819 | ||
820 | ||
821 | /** |
|
822 | * Sets whether we should export variable definitions to our parent context |
|
823 | */ |
|
824 | public void setExport(boolean export) { |
|
825 | 377 | this.export = export; |
826 | 377 | } |
827 | ||
828 | /** |
|
829 | * @return whether we should export variable definitions to our parent context |
|
830 | */ |
|
831 | public boolean isExport() { |
|
832 | 6448 | return this.export; |
833 | } |
|
834 | ||
835 | /** |
|
836 | * Sets whether we should inherit variables from our parent context |
|
837 | */ |
|
838 | public void setInherit(boolean inherit) { |
|
839 | 130 | this.inherit = inherit; |
840 | 130 | } |
841 | ||
842 | /** |
|
843 | * @return whether we should inherit variables from our parent context |
|
844 | */ |
|
845 | public boolean isInherit() { |
|
846 | 9113 | return this.inherit; |
847 | } |
|
848 | ||
849 | ||
850 | /** |
|
851 | * Return the class loader to be used for instantiating application objects |
|
852 | * when required. This is determined based upon the following rules: |
|
853 | * <ul> |
|
854 | * <li>The class loader set by <code>setClassLoader()</code>, if any</li> |
|
855 | * <li>The thread context class loader, if it exists and the |
|
856 | * <code>useContextClassLoader</code> property is set to true</li> |
|
857 | * <li>The class loader used to load the XMLParser class itself. |
|
858 | * </ul> |
|
859 | */ |
|
860 | public ClassLoader getClassLoader() { |
|
861 | 936 | return ClassLoaderUtils.getClassLoader(classLoader, useContextClassLoader, getClass()); |
862 | } |
|
863 | ||
864 | /** |
|
865 | * Set the class loader to be used for instantiating application objects |
|
866 | * when required. |
|
867 | * |
|
868 | * @param classLoader The new class loader to use, or <code>null</code> |
|
869 | * to revert to the standard rules |
|
870 | */ |
|
871 | public void setClassLoader(ClassLoader classLoader) { |
|
872 | 0 | this.classLoader = classLoader; |
873 | 0 | } |
874 | ||
875 | /** |
|
876 | * Return the boolean as to whether the context classloader should be used. |
|
877 | */ |
|
878 | public boolean getUseContextClassLoader() { |
|
879 | 0 | return useContextClassLoader; |
880 | } |
|
881 | ||
882 | /** |
|
883 | * Determine whether to use the Context ClassLoader (the one found by |
|
884 | * calling <code>Thread.currentThread().getContextClassLoader()</code>) |
|
885 | * to resolve/load classes. If not |
|
886 | * using Context ClassLoader, then the class-loading defaults to |
|
887 | * using the calling-class' ClassLoader. |
|
888 | * |
|
889 | * @param use determines whether to use JellyContext ClassLoader. |
|
890 | */ |
|
891 | public void setUseContextClassLoader(boolean use) { |
|
892 | 0 | useContextClassLoader = use; |
893 | 0 | } |
894 | ||
895 | ||
896 | // Implementation methods |
|
897 | //------------------------------------------------------------------------- |
|
898 | /** |
|
899 | * @return a new relative URL from the given root and with the addition of the |
|
900 | * extra relative URI |
|
901 | * |
|
902 | * @param rootURL is the root context from which the relative URI will be applied |
|
903 | * @param relativeURI is the relative URI (without a leading "/") |
|
904 | * @throws MalformedURLException if the URL is invalid. |
|
905 | */ |
|
906 | protected URL createRelativeURL(URL rootURL, String relativeURI) |
|
907 | throws MalformedURLException { |
|
908 | 104 | URL url = rootURL; |
909 | 104 | if (url == null) { |
910 | 0 | File file = new File(System.getProperty("user.dir")); |
911 | 0 | url = file.toURL(); |
912 | } |
|
913 | 104 | String urlText = url.toString() + relativeURI; |
914 | 104 | if ( log.isDebugEnabled() ) { |
915 | 0 | log.debug("Attempting to open url: " + urlText); |
916 | } |
|
917 | 104 | return new URL(urlText); |
918 | } |
|
919 | ||
920 | /** |
|
921 | * Strips off the name of a script to create a new context URL |
|
922 | */ |
|
923 | protected URL getJellyContextURL(URL url) throws MalformedURLException { |
|
924 | 0 | String text = url.toString(); |
925 | 0 | int idx = text.lastIndexOf('/'); |
926 | 0 | text = text.substring(0, idx + 1); |
927 | 0 | return new URL(text); |
928 | } |
|
929 | ||
930 | /** |
|
931 | * Strips off the name of a script to create a new context URL |
|
932 | */ |
|
933 | protected URL getJellyContextURL(InputSource source) throws MalformedURLException { |
|
934 | 130 | String text = source.getSystemId(); |
935 | 130 | if (text != null) { |
936 | 117 | int idx = text.lastIndexOf('/'); |
937 | 117 | text = text.substring(0, idx + 1); |
938 | 117 | return new URL(text); |
939 | } else { |
|
940 | 13 | return null; |
941 | } |
|
942 | ||
943 | } |
|
944 | ||
945 | /** |
|
946 | * Factory method to create a new child of this context |
|
947 | */ |
|
948 | protected JellyContext createChildContext() { |
|
949 | 156 | return new JellyContext(this); |
950 | } |
|
951 | ||
952 | /** |
|
953 | * Change the parent context to the one provided |
|
954 | * @param context the new parent context |
|
955 | */ |
|
956 | protected void setParent(JellyContext context) |
|
957 | { |
|
958 | 0 | parent = context; |
959 | 0 | this.variables.put("parentScope", parent.variables); |
960 | // need to re-export tag libraries to the new parent |
|
961 | 0 | if (isExportLibraries() && parent != null) { |
962 | 0 | for (Iterator keys = taglibs.keySet().iterator(); keys.hasNext();) |
963 | { |
|
964 | 0 | String namespaceURI = (String) keys.next(); |
965 | 0 | Object tagLibOrClassName = taglibs.get(namespaceURI); |
966 | 0 | if (tagLibOrClassName instanceof TagLibrary) |
967 | { |
|
968 | 0 | parent.registerTagLibrary( namespaceURI, (TagLibrary) tagLibOrClassName ); |
969 | 0 | } |
970 | else |
|
971 | { |
|
972 | 0 | parent.registerTagLibrary( namespaceURI, (String) tagLibOrClassName ); |
973 | } |
|
974 | 0 | } |
975 | } |
|
976 | ||
977 | 0 | } |
978 | ||
979 | } |
This report is generated by jcoverage, Maven and Maven JCoverage Plugin. |