1
2
3
4
5
6
7
8
9
10
11
12
13
14
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 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 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 private Map taglibs = new Hashtable();
79
80 /*** synchronized access to the variables in scope */
81 private Map variables = new Hashtable();
82
83 /*** The parent context */
84 private JellyContext parent;
85
86 /*** Do we inherit variables from parent context? */
87 private boolean inherit = JellyContext.DEFAULT_INHERIT;
88
89 /*** Do we export our variables to parent context? */
90 private boolean export = JellyContext.DEFAULT_EXPORT;
91
92 /*** Should we export tag libraries to our parents context */
93 private boolean exportLibraries = true;
94
95 /***
96 * Create a new context with the currentURL set to the rootURL
97 */
98 public JellyContext() {
99 this.currentURL = rootURL;
100 init();
101 }
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 this( rootURL, rootURL );
109 }
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 public JellyContext(URL rootURL, URL currentURL) {
117 this.rootURL = rootURL;
118 this.currentURL = currentURL;
119 init();
120 }
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 public JellyContext(JellyContext parent) {
131 this.parent = parent;
132 this.rootURL = parent.rootURL;
133 this.currentURL = parent.currentURL;
134 this.variables.put("parentScope", parent.variables);
135 init();
136 }
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 this(parentJellyContext);
148 this.currentURL = currentURL;
149 }
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 this(parentJellyContext, currentURL);
161 this.rootURL = rootURL;
162 }
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 variables.put("context",this);
171 try {
172 variables.put("systemScope", System.getProperties() );
173 } catch (SecurityException e) {
174 log.debug("security exception accessing system properties", e);
175 }
176 }
177
178 /***
179 * @return the parent context for this context
180 */
181 public JellyContext getParent() {
182 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 if ( "parent".equals( name ) ) {
192 return getParent();
193 }
194 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 Object answer = variables.get(name);
207 boolean definedHere = answer != null || variables.containsKey(name);
208
209 if (definedHere) return answer;
210
211 if ( answer == null && parent != null ) {
212 answer = parent.findVariable(name);
213 }
214
215 if ( answer == null ) {
216 answer = getSystemProperty(name);
217 }
218
219 if (log.isDebugEnabled()) {
220 log.debug("findVariable: " + name + " value: " + answer );
221 }
222 return answer;
223 }
224
225
226 /*** @return the value of the given variable name */
227 public Object getVariable(String name) {
228 Object value = variables.get(name);
229 boolean definedHere = value != null || variables.containsKey(name);
230
231 if (definedHere) return value;
232
233 if ( value == null && isInherit() ) {
234 JellyContext parentContext = getParent();
235 if (parentContext != null) {
236 value = parentContext.getVariable( name );
237 }
238 }
239
240
241 if ( value == null ) {
242 value = getSystemProperty(name);
243 }
244
245 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 return System.getProperty(name);
256 }
257 catch (SecurityException e) {
258 log.debug("security exception accessing system properties", e);
259 }
260 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 JellyContext scope = getScope(scopeName);
271 if ( scope != null ) {
272 return scope.getVariable(name);
273 }
274 return null;
275 }
276
277
278
279 /*** Sets the value of the named variable */
280 public void setVariable(String name, Object value) {
281 if ( isExport() ) {
282 getParent().setVariable( name, value );
283 return;
284 }
285 if (value == null) {
286 variables.remove(name);
287 }
288 else {
289 variables.put(name, value);
290 }
291 }
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 JellyContext scope = getScope(scopeName);
302 if ( scope != null ) {
303 scope.setVariable(name, value);
304 }
305 }
306
307 /*** Removes the given variable */
308 public void removeVariable(String name) {
309 variables.remove(name);
310 }
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 JellyContext scope = getScope(scopeName);
321 if ( scope != null ) {
322 scope.removeVariable(name);
323 }
324 }
325
326 /***
327 * @return an Iterator over the current variable names in this
328 * context
329 */
330 public Iterator getVariableNames() {
331 return variables.keySet().iterator();
332 }
333
334 /***
335 * @return the Map of variables in this scope
336 */
337 public Map getVariables() {
338 return variables;
339 }
340
341 /***
342 * Sets the Map of variables to use
343 */
344 public void setVariables(Map variables) {
345
346
347 for (Iterator iter = variables.entrySet().iterator(); iter.hasNext();) {
348 Map.Entry element = (Map.Entry) iter.next();
349 if (element.getValue() != null) {
350 this.variables.put(element.getKey(), element.getValue());
351 }
352 }
353
354 }
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
362
363
364
365 newVariables.put("parentScope", variables);
366 JellyContext answer = createChildContext();
367 answer.setVariables(newVariables);
368 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 return createChildContext();
377 }
378
379 /*** Clears variables set by Tags.
380 * @see #clearVariables()
381 */
382 public void clear() {
383 clearVariables();
384 }
385
386 /*** Clears variables set by Tags (variables set while running a Jelly script)
387 * @see #clear()
388 */
389 protected void clearVariables() {
390 variables.clear();
391 }
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 if (log.isDebugEnabled()) {
398 log.debug("Registering tag library to: " + namespaceURI + " taglib: " + taglib);
399 }
400 taglibs.put(namespaceURI, taglib);
401
402 if (isExportLibraries() && parent != null) {
403 parent.registerTagLibrary( namespaceURI, taglib );
404 }
405 }
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 if (log.isDebugEnabled()) {
416 log.debug("Registering tag library to: " + namespaceURI + " taglib: " + className);
417 }
418 taglibs.put(namespaceURI, className);
419
420 if (isExportLibraries() && parent != null) {
421 parent.registerTagLibrary( namespaceURI, className );
422 }
423 }
424
425 public boolean isTagLibraryRegistered(String namespaceURI) {
426 boolean answer = taglibs.containsKey( namespaceURI );
427 if (answer) {
428 return true;
429 }
430 else if ( parent != null ) {
431 return parent.isTagLibraryRegistered(namespaceURI);
432 }
433 else {
434 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
444
445
446 Object answer = taglibs.get(namespaceURI);
447
448 if ( answer == null && parent != null ) {
449 answer = parent.getTagLibrary( namespaceURI );
450 }
451
452 if ( answer instanceof TagLibrary ) {
453 return (TagLibrary) answer;
454 }
455 else if ( answer instanceof String ) {
456 String className = (String) answer;
457 Class theClass = null;
458 try {
459 theClass = getClassLoader().loadClass(className);
460 }
461 catch (ClassNotFoundException e) {
462 log.error("Could not find the class: " + className, e);
463 }
464 if ( theClass != null ) {
465 try {
466 Object object = theClass.newInstance();
467 if (object instanceof TagLibrary) {
468 taglibs.put(namespaceURI, object);
469 return (TagLibrary) object;
470 }
471 else {
472 log.error(
473 "The tag library object mapped to: "
474 + namespaceURI
475 + " is not a TagLibrary. Object = "
476 + object);
477 }
478 }
479 catch (Exception e) {
480 log.error(
481 "Could not instantiate instance of class: " + className + ". Reason: " + e,
482 e);
483 }
484 }
485 }
486
487 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 XMLParser parser = getXMLParser();
496 parser.setContext(this);
497 InputStream in = getResourceAsStream(uri);
498 if (in == null) {
499 throw new JellyException("Could not find Jelly script: " + uri);
500 }
501 Script script = null;
502 try {
503 script = parser.parse(in);
504 } catch (IOException e) {
505 throw new JellyException(JellyContext.BAD_PARSE, e);
506 } catch (SAXException e) {
507 throw new JellyException(JellyContext.BAD_PARSE, e);
508 }
509
510 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 XMLParser parser = getXMLParser();
519 parser.setContext(this);
520
521 Script script = null;
522 try {
523 script = parser.parse(url.toString());
524 } catch (IOException e) {
525 throw new JellyException(JellyContext.BAD_PARSE, e);
526 } catch (SAXException e) {
527 throw new JellyException(JellyContext.BAD_PARSE, e);
528 }
529
530 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 XMLParser parser = getXMLParser();
539 parser.setContext(this);
540
541 Script script = null;
542 try {
543 script = parser.parse(source);
544 } catch (IOException e) {
545 throw new JellyException(JellyContext.BAD_PARSE, e);
546 } catch (SAXException e) {
547 throw new JellyException(JellyContext.BAD_PARSE, e);
548 }
549
550 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 XMLParser parser = createXMLParser();
559 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 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 return runScript(file.toURL(), output, JellyContext.DEFAULT_EXPORT,
578 JellyContext.DEFAULT_INHERIT);
579 } catch (MalformedURLException e) {
580 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 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 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 URL url = null;
612 try {
613 url = getResource(uri);
614 } catch (MalformedURLException e) {
615 throw new JellyException(e.toString());
616 }
617
618 if (url == null) {
619 throw new JellyException("Could not find Jelly script: " + url);
620 }
621 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, boolean inherit) throws JellyException {
633 URL url = null;
634 try {
635 url = getResource(uri);
636 } catch (MalformedURLException e) {
637 throw new JellyException(e.toString());
638 }
639
640 if (url == null) {
641 throw new JellyException("Could not find Jelly script: " + url);
642 }
643
644 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, boolean inherit) throws JellyException {
654 try {
655 return runScript(file.toURL(), output, export, inherit);
656 } catch (MalformedURLException e) {
657 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, boolean inherit) throws JellyException {
668 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, boolean inherit) throws JellyException {
678 Script script = compileScript(source);
679
680 URL newJellyContextURL = null;
681 try {
682 newJellyContextURL = getJellyContextURL(source);
683 } catch (MalformedURLException e) {
684 throw new JellyException(e.toString());
685 }
686
687 JellyContext newJellyContext = newJellyContext();
688 newJellyContext.setRootURL( newJellyContextURL );
689 newJellyContext.setCurrentURL( newJellyContextURL );
690 newJellyContext.setExport( export );
691 newJellyContext.setInherit( inherit );
692
693 if ( inherit ) {
694
695 newJellyContext.variables = this.variables;
696 }
697
698 if (log.isDebugEnabled() ) {
699 log.debug( "About to run script: " + source.getSystemId() );
700 log.debug( "root context URL: " + newJellyContext.rootURL );
701 log.debug( "current context URL: " + newJellyContext.currentURL );
702 }
703
704 script.run(newJellyContext, output);
705
706 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 if (uri.startsWith("/")) {
720
721 return createRelativeURL(rootURL, uri.substring(1));
722 }
723 else {
724 try {
725 return new URL(uri);
726 }
727 catch (MalformedURLException e) {
728
729 try {
730 return createRelativeURL(currentURL, uri);
731 } catch (MalformedURLException e2) {
732 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 URL url = getResource(uri);
751 return url.openStream();
752 }
753 catch (Exception e) {
754 if (log.isTraceEnabled()) {
755 log.trace(
756 "Caught exception attempting to open: " + uri + ". Exception: " + e,
757 e);
758 }
759 return null;
760 }
761 }
762
763
764
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 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 this.rootURL = rootURL;
783 }
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 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 this.currentURL = currentURL;
802 }
803
804 /***
805 * Returns whether we export tag libraries to our parents context
806 * @return boolean
807 */
808 public boolean isExportLibraries() {
809 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 this.exportLibraries = exportLibraries;
818 }
819
820
821 /***
822 * Sets whether we should export variable definitions to our parent context
823 */
824 public void setExport(boolean export) {
825 this.export = export;
826 }
827
828 /***
829 * @return whether we should export variable definitions to our parent context
830 */
831 public boolean isExport() {
832 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 this.inherit = inherit;
840 }
841
842 /***
843 * @return whether we should inherit variables from our parent context
844 */
845 public boolean isInherit() {
846 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 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 this.classLoader = classLoader;
873 }
874
875 /***
876 * Return the boolean as to whether the context classloader should be used.
877 */
878 public boolean getUseContextClassLoader() {
879 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 useContextClassLoader = use;
893 }
894
895
896
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 URL url = rootURL;
909 if (url == null) {
910 File file = new File(System.getProperty("user.dir"));
911 url = file.toURL();
912 }
913 String urlText = url.toString() + relativeURI;
914 if ( log.isDebugEnabled() ) {
915 log.debug("Attempting to open url: " + urlText);
916 }
917 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 String text = url.toString();
925 int idx = text.lastIndexOf('/');
926 text = text.substring(0, idx + 1);
927 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 String text = source.getSystemId();
935 if (text != null) {
936 int idx = text.lastIndexOf('/');
937 text = text.substring(0, idx + 1);
938 return new URL(text);
939 } else {
940 return null;
941 }
942
943 }
944
945 /***
946 * Factory method to create a new child of this context
947 */
948 protected JellyContext createChildContext() {
949 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 parent = context;
959 this.variables.put("parentScope", parent.variables);
960
961 if (isExportLibraries() && parent != null) {
962 for (Iterator keys = taglibs.keySet().iterator(); keys.hasNext();)
963 {
964 String namespaceURI = (String) keys.next();
965 Object tagLibOrClassName = taglibs.get(namespaceURI);
966 if (tagLibOrClassName instanceof TagLibrary)
967 {
968 parent.registerTagLibrary( namespaceURI, (TagLibrary) tagLibOrClassName );
969 }
970 else
971 {
972 parent.registerTagLibrary( namespaceURI, (String) tagLibOrClassName );
973 }
974 }
975 }
976
977 }
978
979 }