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