Coverage report

| %line | %branch
--- | --- | ---
org.apache.commons.jelly.JellyContext |
51% |
83% |

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.