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.