You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by js...@apache.org on 2002/05/15 18:21:07 UTC

cvs commit: jakarta-commons-sandbox/jelly/src/java/org/apache/commons/jelly/parser XMLParser.java

jstrachan    02/05/15 09:21:06

  Modified:    jelly/src/java/org/apache/commons/jelly JellyContext.java
               jelly/src/java/org/apache/commons/jelly/parser
                        XMLParser.java
  Log:
  Tidied up the code a bit more, removing some old logging messages.
  
  Also made loading of tag libraries lazy so that the standard library does not force jar dependencies until tags get used. e.g. javax.sql.* is only needed if you use the new SQL tags.
  
  Revision  Changes    Path
  1.3       +1 -1      jakarta-commons-sandbox/jelly/src/java/org/apache/commons/jelly/JellyContext.java
  
  Index: JellyContext.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons-sandbox/jelly/src/java/org/apache/commons/jelly/JellyContext.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- JellyContext.java	15 May 2002 07:47:50 -0000	1.2
  +++ JellyContext.java	15 May 2002 16:21:06 -0000	1.3
  @@ -1 +1 @@
  -/*
 * $Header: /home/cvs/jakarta-commons-sandbox/jelly/src/java/org/apache/commons/jelly/JellyContext.java,v 1.10 2002/04/26 12:20:12 jstrachan Exp $
 * $Revision: 1.10 $
 * $Date: 2002/04/26 12:20:12 $
 *
 * ====================================================================
 *
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999-2002 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution, if
 *    any, must include the following acknowlegement:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowlegement may appear in the software itself,
 *    if and wherever such third-party acknowlegements normally appear.
 *
 * 4. The names "The Jakarta Project", "Commons", and "Apache Software
 *    Foundation" must not be used to endorse or promote products derived
 *    from this software without prior written permission. For written
 *    permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache"
 *    nor may "Apache" appear in their names without prior written
 *    permission of the Apache Group.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 * 
 * $Id: JellyContext.java,v 1.10 2002/04/26 12:20:12 jstrachan Exp $
 */
package org.apache.commons.jelly;

import java.io.File;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;

import org.apache.commons.jelly.parser.XMLParser;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/** <p><code>JellyContext</code> represents the Jelly context.</p>
  *
  * @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
  * @version $Revision: 1.10 $
  */
public class JellyContext {

    /** The root URL context (where scripts are located from) */
    private URL rootContext;

    /** The current URL context (where relative scripts are located from) */
    private URL currentJellyContext;

    /** Tag libraries found so far */
    private Map taglibs = new Hashtable();

    /** synchronized access to the variables in scope */
    private Map variables = new Hashtable();

    /** The Log to which logging calls will be made. */
    private Log log = LogFactory.getLog(JellyContext.class);


    public JellyContext() {
        this.currentJellyContext = rootContext;
    }

    public JellyContext(URL rootContext) {
        this.rootContext = rootContext;
        this.currentJellyContext = rootContext;
    }

    public JellyContext(URL rootContext, URL currentJellyContext) {
        this.rootContext = rootContext;
        this.currentJellyContext = currentJellyContext;
    }

    public JellyContext(JellyContext parentJellyContext) {
        this.rootContext = parentJellyContext.rootContext;
        this.currentJellyContext = parentJellyContext.currentJellyContext;
        this.taglibs = parentJellyContext.taglibs;
        this.variables.put("parentScope", parentJellyContext.variables);
    }

    public JellyContext(JellyContext parentJellyContext, URL currentJellyContext) {
        this(parentJellyContext);
        this.currentJellyContext = currentJellyContext;
    }

    /** @return the value of the given variable name */
    public Object getVariable(String name) {
        return variables.get(name);
    }

    /** Sets the value of the given variable name */
    public void setVariable(String name, Object value) {
        if (value == null) {
            variables.remove(name);
        }
        else {
            variables.put(name, value);
        }
    }

    /** Removes the given variable */
    public void removeVariable(String name) {
        variables.remove(name);
    }

    /** 
     * @return an Iterator over the current variable names in this
     * context 
     */
    public Iterator getVariableNames() {
        return variables.keySet().iterator();
    }

    /**
     * @return the Map of variables in this scope
     */
    public Map getVariables() {
        return variables;
    }

    /**
     * Sets the Map of variables to use
     */

    public void setVariables(Map variables) {
        this.variables = variables;
    }

    /**
     * A factory method to create a new child context of the
     * current context.
     */
    public JellyContext newJellyContext(Map newVariables) {
        // XXXX: should allow this new context to
        // XXXX: inherit parent contexts? 
        // XXXX: Or at least publish the parent scope
        // XXXX: as a Map in this new variable scope?
        newVariables.put("parentScope", variables);
        JellyContext answer = createChildContext();
        answer.setVariables(newVariables);
        return answer;
    }

    /** Registers the given tag library against the given namespace URI.
     * This should be called before the parser is used.
     */
    public void registerTagLibrary(String namespaceURI, TagLibrary taglib) {
        if (log.isDebugEnabled()) {
            log.debug("Registering tag library to: " + namespaceURI + " taglib: " + taglib);
        }
        taglibs.put(namespaceURI, taglib);
    }

    /** Registers the given tag library class name against the given namespace URI.
     * The class will be loaded via the given ClassLoader
     * This should be called before the parser is used.
     */
    public void registerTagLibrary(
        String namespaceURI,
        String className,
        ClassLoader classLoader) {
        try {
            Class theClass = classLoader.loadClass(className);
            Object object = theClass.newInstance();
            if (object instanceof TagLibrary) {
                registerTagLibrary(namespaceURI, (TagLibrary) object);
            }
            else {
                log.error(
                    "The tag library object mapped to: "
                        + namespaceURI
                        + " is not a TagLibrary. Object = "
                        + object);
            }
        }
        catch (ClassNotFoundException e) {
            log.error("Could not find the class: " + className, e);
        }
        catch (Exception e) {
            log.error(
                "Could not instantiate instance of class: " + className + ". Reason: " + e,
                e);
        }
    }

    /** 
     * @return the TagLibrary for the given namespace URI or null if one could not be found
     */
    public TagLibrary getTagLibrary(String namespaceURI) {
        return (TagLibrary) taglibs.get(namespaceURI);
    }

    /** 
     * Attempts to parse the script from the given uri using the 
     * {#link getResource()} method then returns the compiled script.
     */
    public Script compileScript(String uri) throws Exception {
        XMLParser parser = new XMLParser();
        parser.setJellyContext(this);
        InputStream in = getResourceAsStream(uri);
        if (in == null) {
            throw new JellyException("Could not find Jelly script: " + uri);
        }
        Script script = parser.parse(in);
        return script.compile();
    }

    /** 
     * Attempts to parse the script from the given URL using the 
     * {#link getResource()} method then returns the compiled script.
     */
    public Script compileScript(URL url) throws Exception {
        XMLParser parser = new XMLParser();
        parser.setJellyContext(this);
        Script script = parser.parse(url.toString());
        return script.compile();
    }

    /** 
     * Attempts to parse the script from the given uri using the 
     * JellyContext.getResource() API then compiles it and runs it.
     */
    public void runScript(String uri, XMLOutput output) throws Exception {
        URL url = getResource(uri);
        if (url == null) {
            throw new JellyException("Could not find Jelly script: " + url);
        }
        Script script = compileScript(url);
        URL newJellyContextURL = getJellyContextURL(url);
        JellyContext newJellyContext = new JellyContext(this, newJellyContextURL);
        script.run(newJellyContext, output);
    }

    /**
     * Returns a URL for the given resource from the specified path.
     * If the uri starts with "/" then the path is taken as relative to 
     * the current context root. If the uri is a well formed URL then it
     * is used. Otherwise the uri is interpreted as relative to the current
     * context (the location of the current script).
     */
    public URL getResource(String uri) throws MalformedURLException {
        if (uri.startsWith("/")) {
            // append this uri to the context root
            return createRelativeURL(rootContext, uri.substring(1));
        }
        else {
            try {
                return new URL(uri);
            }
            catch (MalformedURLException e) {
                // lets try find a relative resource
                try {
                    return createRelativeURL(currentJellyContext, uri);
                }
                catch (MalformedURLException e2) {
                    throw e;
                }
            }
        }
    }

    /**
     * Attempts to open an InputStream to the given resource at the specified path.
     * If the uri starts with "/" then the path is taken as relative to 
     * the current context root. If the uri is a well formed URL then it
     * is used. Otherwise the uri is interpreted as relative to the current
     * context (the location of the current script).
     *
     * @return null if this resource could not be loaded, otherwise the resources 
     *  input stream is returned.
     */
    public InputStream getResourceAsStream(String uri) {
        try {
            URL url = getResource(uri);
            return url.openStream();
        }
        catch (Exception e) {
            if (log.isTraceEnabled()) {
                log.trace(
                    "Caught exception attempting to open: " + uri + ". Exception: " + e,
                    e);
            }
            return null;
        }
    }

    // Implementation methods
    //-------------------------------------------------------------------------                
    /**
     * @return a new relative URL from the given root and with the addition of the
     * extra relative URI
     *
     * @param rootURL is the root context from which the relative URI will be applied
     * @param relativeURI is the relative URI (without a leading "/")
     * @throws MalformedURLException if the URL is invalid.
     */
    protected URL createRelativeURL(URL rootURL, String relativeURI)
        throws MalformedURLException {
        String urlText = null;
        if (rootURL == null) {
            String userDir = System.getProperty("user.dir");
            urlText = "file://" + userDir + relativeURI;
        }
        else {
            urlText = rootURL.toString() + relativeURI;
        }
        log.info("Attempting to open url: " + urlText);
        return new URL(urlText);
    }

    /** 
     * Strips off the name of a script to create a new context URL
     */
    protected URL getJellyContextURL(URL url) throws MalformedURLException {
        String text = url.toString();
        int idx = text.lastIndexOf('/');
        text = text.substring(0, idx + 1);
        return new URL(text);
    }

    /**
     * Factory method to create a new child of this context
     */
    protected JellyContext createChildContext() {
        return new JellyContext(this);
    }
}
  \ No newline at end of file
  +/*
 * $Header: /home/cvs/jakarta-commons-sandbox/jelly/src/java/org/apache/commons/jelly/JellyContext.java,v 1.10 2002/04/26 12:20:12 jstrachan Exp $
 * $Revision: 1.10 $
 * $Date: 2002/04/26 12:20:12 $
 *
 * ====================================================================
 *
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999-2002 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution, if
 *    any, must include the following acknowlegement:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowlegement may appear in the software itself,
 *    if and wherever such third-party acknowlegements normally appear.
 *
 * 4. The names "The Jakarta Project", "Commons", and "Apache Software
 *    Foundation" must not be used to endorse or promote products derived
 *    from this software without prior written permission. For written
 *    permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache"
 *    nor may "Apache" appear in their names without prior written
 *    permission of the Apache Group.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 * 
 * $Id: JellyContext.java,v 1.10 2002/04/26 12:20:12 jstrachan Exp $
 */
package org.apache.commons.jelly;

import java.io.File;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;

import org.apache.commons.jelly.parser.XMLParser;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/** <p><code>JellyContext</code> represents the Jelly context.</p>
  *
  * @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
  * @version $Revision: 1.10 $
  */
public class JellyContext {

    /** The root URL context (where scripts are located from) */
    private URL rootContext;

    /** The current URL context (where relative scripts are located from) */
    private URL currentJellyContext;

    /** Tag libraries found so far */
    private Map taglibs = new Hashtable();

    /** synchronized access to the variables in scope */
    private Map variables = new Hashtable();

    /** The Log to which logging calls will be made. */
    private Log log = LogFactory.getLog(JellyContext.class);

    /**
     * The class loader to use for instantiating application objects.
     * If not specified, the context class loader, or the class loader
     * used to load XMLParser itself, is used, based on the value of the
     * <code>useContextClassLoader</code> variable.
     */
    protected ClassLoader classLoader;

    /**
     * Do we want to use the JellyContext ClassLoader when loading classes
     * for instantiating new objects?  Default is <code>false</code>.
     */
    protected boolean useContextClassLoader = false;


    public JellyContext() {
        this.currentJellyContext = rootContext;
    }

    public JellyContext(URL rootContext) {
        this.rootContext = rootContext;
        this.currentJellyContext = rootContext;
    }

    public JellyContext(URL rootContext, URL currentJellyContext) {
        this.rootContext = rootContext;
        this.currentJellyContext = currentJellyContext;
    }

    public JellyContext(JellyContext parentJellyContext) {
        this.rootContext = parentJellyContext.rootContext;
        this.currentJellyContext = parentJellyContext.currentJellyContext;
        this.taglibs = parentJellyContext.taglibs;
        this.variables.put("parentScope", parentJellyContext.variables);
    }

    public JellyContext(JellyContext parentJellyContext, URL currentJellyContext) {
        this(parentJellyContext);
        this.currentJellyContext = currentJellyContext;
    }

    /** @return the value of the given variable name */
    public Object getVariable(String name) {
        return variables.get(name);
    }

    /** Sets the value of the given variable name */
    public void setVariable(String name, Object value) {
        if (value == null) {
            variables.remove(name);
        }
        else {
            variables.put(name, value);
        }
    }

    /** Removes the given variable */
    public void removeVariable(String name) {
        variables.remove(name);
    }

    /** 
     * @return an Iterator over the current variable names in this
     * context 
     */
    public Iterator getVariableNames() {
        return variables.keySet().iterator();
    }

    /**
     * @return the Map of variables in this scope
     */
    public Map getVariables() {
        return variables;
    }

    /**
     * Sets the Map of variables to use
     */

    public void setVariables(Map variables) {
        this.variables = variables;
    }

    /**
     * A factory method to create a new child context of the
     * current context.
     */
    public JellyContext newJellyContext(Map newVariables) {
        // XXXX: should allow this new context to
        // XXXX: inherit parent contexts? 
        // XXXX: Or at least publish the parent scope
        // XXXX: as a Map in this new variable scope?
        newVariables.put("parentScope", variables);
        JellyContext answer = createChildContext();
        answer.setVariables(newVariables);
        return answer;
    }

    /** Registers the given tag library against the given namespace URI.
     * This should be called before the parser is used.
     */
    public void registerTagLibrary(String namespaceURI, TagLibrary taglib) {
        if (log.isDebugEnabled()) {
            log.debug("Registering tag library to: " + namespaceURI + " taglib: " + taglib);
        }
        taglibs.put(namespaceURI, taglib);
    }

    /** Registers the given tag library class name against the given namespace URI.
     * The class will be loaded via the given ClassLoader
     * This should be called before the parser is used.
     */
    public void registerTagLibrary(
        String namespaceURI,
        String className) {
            
        if (log.isDebugEnabled()) {
            log.debug("Registering tag library to: " + namespaceURI + " taglib: " + className);
        }
        taglibs.put(namespaceURI, className);
    }

    /** 
     * @return the TagLibrary for the given namespace URI or null if one could not be found
     */
    public TagLibrary getTagLibrary(String namespaceURI) {
        Object answer = taglibs.get(namespaceURI);
        if ( answer instanceof TagLibrary ) {
            return (TagLibrary) answer;
        }
        else if ( answer instanceof String ) {
            String className = (String) answer;
            Class theClass = null;
            try {
                theClass = getClassLoader().loadClass(className);
            }
            catch (ClassNotFoundException e) {
                log.error("Could not find the class: " + className, e);
            }
            if ( theClass != null ) {
                try {
                    Object object = theClass.newInstance();
                    if (object instanceof TagLibrary) {
                        taglibs.put(namespaceURI, object);
                        return (TagLibrary) object;
                    }                
                    else {
                        log.error(
                            "The tag library object mapped to: "
                                + namespaceURI
                                + " is not a TagLibrary. Object = "
                                + object);
                    }
                }
                catch (Exception e) {
                    log.error(
                        "Could not instantiate instance of class: " + className + ". Reason: " + e,
                        e);
                }
            }
        }
        return null;
    }

    /** 
     * Attempts to parse the script from the given uri using the 
     * {#link getResource()} method then returns the compiled script.
     */
    public Script compileScript(String uri) throws Exception {
        XMLParser parser = new XMLParser();
        parser.setJellyContext(this);
        InputStream in = getResourceAsStream(uri);
        if (in == null) {
            throw new JellyException("Could not find Jelly script: " + uri);
        }
        Script script = parser.parse(in);
        return script.compile();
    }

    /** 
     * Attempts to parse the script from the given URL using the 
     * {#link getResource()} method then returns the compiled script.
     */
    public Script compileScript(URL url) throws Exception {
        XMLParser parser = new XMLParser();
        parser.setJellyContext(this);
        Script script = parser.parse(url.toString());
        return script.compile();
    }

    /** 
     * Attempts to parse the script from the given uri using the 
     * JellyContext.getResource() API then compiles it and runs it.
     */
    public void runScript(String uri, XMLOutput output) throws Exception {
        URL url = getResource(uri);
        if (url == null) {
            throw new JellyException("Could not find Jelly script: " + url);
        }
        Script script = compileScript(url);
        URL newJellyContextURL = getJellyContextURL(url);
        JellyContext newJellyContext = new JellyContext(this, newJellyContextURL);
        script.run(newJellyContext, output);
    }

    /**
     * Returns a URL for the given resource from the specified path.
     * If the uri starts with "/" then the path is taken as relative to 
     * the current context root. If the uri is a well formed URL then it
     * is used. Otherwise the uri is interpreted as relative to the current
     * context (the location of the current script).
     */
    public URL getResource(String uri) throws MalformedURLException {
        if (uri.startsWith("/")) {
            // append this uri to the context root
            return createRelativeURL(rootContext, uri.substring(1));
        }
        else {
            try {
                return new URL(uri);
            }
            catch (MalformedURLException e) {
                // lets try find a relative resource
                try {
                    return createRelativeURL(currentJellyContext, uri);
                }
                catch (MalformedURLException e2) {
                    throw e;
                }
            }
        }
    }

    /**
     * Attempts to open an InputStream to the given resource at the specified path.
     * If the uri starts with "/" then the path is taken as relative to 
     * the current context root. If the uri is a well formed URL then it
     * is used. Otherwise the uri is interpreted as relative to the current
     * context (the location of the current script).
     *
     * @return null if this resource could not be loaded, otherwise the resources 
     *  input stream is returned.
     */
    public InputStream getResourceAsStream(String uri) {
        try {
            URL url = getResource(uri);
            return url.openStream();
        }
        catch (Exception e) {
            if (log.isTraceEnabled()) {
                log.trace(
                    "Caught exception attempting to open: " + uri + ". Exception: " + e,
                    e);
            }
            return null;
        }
    }


    // Properties
    //-------------------------------------------------------------------------                


    /**
     * Return the class loader to be used for instantiating application objects
     * when required.  This is determined based upon the following rules:
     * <ul>
     * <li>The class loader set by <code>setClassLoader()</code>, if any</li>
     * <li>The thread context class loader, if it exists and the
     *     <code>useContextClassLoader</code> property is set to true</li>
     * <li>The class loader used to load the XMLParser class itself.
     * </ul>
     */
    public ClassLoader getClassLoader() {
        if (this.classLoader != null) {
            return (this.classLoader);
        }
        if (this.useContextClassLoader) {
            ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
            if (classLoader != null) {
                return (classLoader);
            }
        }
        return (this.getClass().getClassLoader());
    }
    
    /**
     * Set the class loader to be used for instantiating application objects
     * when required.
     *
     * @param classLoader The new class loader to use, or <code>null</code>
     *  to revert to the standard rules
     */
    public void setClassLoader(ClassLoader classLoader) {
        this.classLoader = classLoader;
    }
    
    /**
     * Return the boolean as to whether the context classloader should be used.
     */
    public boolean getUseContextClassLoader() {
        return useContextClassLoader;
    }

    /**
     * Determine whether to use the JellyContext ClassLoader (the one found by
     * calling <code>Thread.currentThread().getContextClassLoader()</code>)
     * to resolve/load classes that are defined in various rules.  If not
     * using JellyContext ClassLoader, then the class-loading defaults to
     * using the calling-class' ClassLoader.
     *
     * @param boolean determines whether to use JellyContext ClassLoader.
     */
    public void setUseContextClassLoader(boolean use) {
        useContextClassLoader = use;
    }
    

    // Implementation methods
    //-------------------------------------------------------------------------                
    /**
     * @return a new relative URL from the given root and with the addition of the
     * extra relative URI
     *
     * @param rootURL is the root context from which the relative URI will be applied
     * @param relativeURI is the relative URI (without a leading "/")
     * @throws MalformedURLException if the URL is invalid.
     */
    protected URL createRelativeURL(URL rootURL, String relativeURI)
        throws MalformedURLException {
        String urlText = null;
        if (rootURL == null) {
            String userDir = System.getProperty("user.dir");
            urlText = "file://" + userDir + relativeURI;
        }
        else {
            urlText = rootURL.toString() + relativeURI;
        }
        log.info("Attempting to open url: " + urlText);
        return new URL(urlText);
    }

    /** 
     * Strips off the name of a script to create a new context URL
     */
    protected URL getJellyContextURL(URL url) throws MalformedURLException {
        String text = url.toString();
        int idx = text.lastIndexOf('/');
        text = text.substring(0, idx + 1);
        return new URL(text);
    }

    /**
     * Factory method to create a new child of this context
     */
    protected JellyContext createChildContext() {
        return new JellyContext(this);
    }
}
  \ No newline at end of file
  
  
  
  1.15      +1 -1081   jakarta-commons-sandbox/jelly/src/java/org/apache/commons/jelly/parser/XMLParser.java
  
  Index: XMLParser.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons-sandbox/jelly/src/java/org/apache/commons/jelly/parser/XMLParser.java,v
  retrieving revision 1.14
  retrieving revision 1.15
  diff -u -r1.14 -r1.15
  --- XMLParser.java	15 May 2002 06:25:49 -0000	1.14
  +++ XMLParser.java	15 May 2002 16:21:06 -0000	1.15
  @@ -1,1081 +1 @@
  -/*
  - * $Header: /home/cvs/jakarta-commons-sandbox/jelly/src/java/org/apache/commons/jelly/parser/XMLParser.java,v 1.14 2002/05/15 06:25:49 jstrachan Exp $
  - * $Revision: 1.14 $
  - * $Date: 2002/05/15 06:25:49 $
  - *
  - * ====================================================================
  - *
  - * The Apache Software License, Version 1.1
  - *
  - * Copyright (c) 1999-2002 The Apache Software Foundation.  All rights
  - * reserved.
  - *
  - * Redistribution and use in source and binary forms, with or without
  - * modification, are permitted provided that the following conditions
  - * are met:
  - *
  - * 1. Redistributions of source code must retain the above copyright
  - *    notice, this list of conditions and the following disclaimer.
  - *
  - * 2. Redistributions in binary form must reproduce the above copyright
  - *    notice, this list of conditions and the following disclaimer in
  - *    the documentation and/or other materials provided with the
  - *    distribution.
  - *
  - * 3. The end-user documentation included with the redistribution, if
  - *    any, must include the following acknowlegement:
  - *       "This product includes software developed by the
  - *        Apache Software Foundation (http://www.apache.org/)."
  - *    Alternately, this acknowlegement may appear in the software itself,
  - *    if and wherever such third-party acknowlegements normally appear.
  - *
  - * 4. The names "The Jakarta Project", "Commons", and "Apache Software
  - *    Foundation" must not be used to endorse or promote products derived
  - *    from this software without prior written permission. For written
  - *    permission, please contact apache@apache.org.
  - *
  - * 5. Products derived from this software may not be called "Apache"
  - *    nor may "Apache" appear in their names without prior written
  - *    permission of the Apache Group.
  - *
  - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  - * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  - * SUCH DAMAGE.
  - * ====================================================================
  - *
  - * This software consists of voluntary contributions made by many
  - * individuals on behalf of the Apache Software Foundation.  For more
  - * information on the Apache Software Foundation, please see
  - * <http://www.apache.org/>.
  - *
  - * $Id: XMLParser.java,v 1.14 2002/05/15 06:25:49 jstrachan Exp $
  - */
  -package org.apache.commons.jelly.parser;
  -
  -import java.io.File;
  -import java.io.FileReader;
  -import java.io.InputStream;
  -import java.io.IOException;
  -import java.io.PrintWriter;
  -import java.io.Reader;
  -import java.net.URL;
  -import java.net.URLConnection;
  -import java.util.ArrayList;
  -import java.util.EmptyStackException;
  -import java.util.HashMap;
  -import java.util.Iterator;
  -import java.util.List;
  -import java.util.Map;
  -import java.util.Properties;
  -
  -import javax.xml.parsers.SAXParser;
  -import javax.xml.parsers.SAXParserFactory;
  -
  -
  -import org.apache.commons.collections.ArrayStack;
  -
  -import org.apache.commons.jelly.JellyContext;
  -import org.apache.commons.jelly.Script;
  -import org.apache.commons.jelly.Tag;
  -import org.apache.commons.jelly.TagLibrary;
  -import org.apache.commons.jelly.impl.ScriptBlock;
  -import org.apache.commons.jelly.impl.StaticTag;
  -import org.apache.commons.jelly.impl.DynaTagScript;
  -import org.apache.commons.jelly.impl.TagScript;
  -import org.apache.commons.jelly.impl.TextScript;
  -import org.apache.commons.jelly.expression.ConstantExpression;
  -import org.apache.commons.jelly.expression.Expression;
  -import org.apache.commons.jelly.expression.ExpressionFactory;
  -import org.apache.commons.jelly.expression.jexl.JexlExpressionFactory;
  -import org.apache.commons.jelly.tags.core.CoreTagLibrary;
  -import org.apache.commons.jelly.tags.xml.XMLTagLibrary;
  -
  -import org.apache.commons.logging.Log;
  -import org.apache.commons.logging.LogFactory;
  -
  -import org.xml.sax.Attributes;
  -import org.xml.sax.ContentHandler;
  -import org.xml.sax.EntityResolver;
  -import org.xml.sax.ErrorHandler;
  -import org.xml.sax.helpers.DefaultHandler;
  -import org.xml.sax.InputSource;
  -import org.xml.sax.Locator;
  -import org.xml.sax.SAXException;
  -import org.xml.sax.SAXParseException;
  -import org.xml.sax.XMLReader;
  -
  -
  -/** <p><code>XMLParser</code> parses the XML Jelly format.
  - * The SAXParser and XMLReader portions of this code come from Digester.</p>
  - *
  - * @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
  - * @version $Revision: 1.14 $
  - */
  -public class XMLParser extends DefaultHandler {
  -
  -    /** JellyContext which is used to locate tag libraries*/
  -    private JellyContext context = new JellyContext();
  -    
  -    /** the expression factory used to evaluate tag attributes */
  -    private ExpressionFactory expressionFactory;
  -    
  -    /** The current script block */
  -    private ScriptBlock script;
  -    
  -    /** The current tagScript */
  -    private TagScript tagScript;
  -
  -    /** The current parent tag */
  -    private Tag parentTag;
  -    
  -    /** The stack of body scripts. */
  -    private ArrayStack scriptStack = new ArrayStack();
  -    
  -    /** The stack of tagScripts - use ArrayList as it allows null. */
  -    private ArrayList tagScriptStack = new ArrayList();
  -    
  -    /** The current text buffer where non-custom tags get written */
  -    private StringBuffer textBuffer;
  -    
  -    /**
  -     * The class loader to use for instantiating application objects.
  -     * If not specified, the context class loader, or the class loader
  -     * used to load XMLParser itself, is used, based on the value of the
  -     * <code>useContextClassLoader</code> variable.
  -     */
  -    protected ClassLoader classLoader = null;
  -    
  -    
  -    
  -    /**
  -     * The application-supplied error handler that is notified when parsing
  -     * warnings, errors, or fatal errors occur.
  -     */
  -    protected ErrorHandler errorHandler = null;
  -    
  -    
  -    /**
  -     * The SAXParserFactory that is created the first time we need it.
  -     */
  -    protected static SAXParserFactory factory = null;
  -    
  -    /**
  -     * The SAXParser we will use to parse the input stream.
  -     */
  -    protected SAXParser parser = null;
  -    
  -    /**
  -     * The XMLReader used to parse digester rules.
  -     */
  -    protected XMLReader reader = null;
  -    
  -    
  -    /**
  -     * The Locator associated with our parser.
  -     */
  -    protected Locator locator = null;
  -    
  -    
  -    /**
  -     * Registered namespaces we are currently processing.  The key is the
  -     * namespace prefix that was declared in the document.  The value is an
  -     * ArrayStack of the namespace URIs this prefix has been mapped to --
  -     * the top Stack element is the most current one.  (This architecture
  -     * is required because documents can declare nested uses of the same
  -     * prefix for different Namespace URIs).
  -     */
  -    protected HashMap namespaces = new HashMap();
  -    
  -    
  -    /**
  -     * Do we want to use the JellyContext ClassLoader when loading classes
  -     * for instantiating new objects?  Default is <code>false</code>.
  -     */
  -    protected boolean useContextClassLoader = false;
  -    
  -    
  -    /**
  -     * Do we want to use a validating parser?
  -     */
  -    protected boolean validating = false;
  -    
  -    
  -    /** Flag to indicate if this object has been configured */
  -    private boolean configured;
  -    
  -    /**
  -     * The Log to which logging calls will be made.
  -     */
  -    private Log log = LogFactory.getLog( XMLParser.class );
  -    
  -    
  -    /**
  -     * Construct a new XMLParser with default properties.
  -     */
  -    public XMLParser() {
  -    }
  -    
  -    /**
  -     * Construct a new XMLParser, allowing a SAXParser to be passed in.  This
  -     * allows XMLParser to be used in environments which are unfriendly to
  -     * JAXP1.1 (such as WebLogic 6.0).  Thanks for the request to change go to
  -     * James House (james@interobjective.com).  This may help in places where
  -     * you are able to load JAXP 1.1 classes yourself.
  -     */
  -    public XMLParser(SAXParser parser) {
  -        this.parser = parser;
  -    }
  -    
  -    /**
  -     * Construct a new XMLParser, allowing an XMLReader to be passed in.  This
  -     * allows XMLParser to be used in environments which are unfriendly to
  -     * JAXP1.1 (such as WebLogic 6.0).  Note that if you use this option you
  -     * have to configure namespace and validation support yourself, as these
  -     * properties only affect the SAXParser and emtpy constructor.
  -     */
  -    public XMLParser(XMLReader reader) {
  -        this.reader = reader;
  -    }
  -
  -
  -    /**
  -     * Parse the content of the specified file using this XMLParser.  Returns
  -     * the root element from the object stack (if any).
  -     *
  -     * @param file File containing the XML data to be parsed
  -     *
  -     * @exception IOException if an input/output error occurs
  -     * @exception SAXException if a parsing exception occurs
  -     */
  -    public Script parse(File file) throws IOException, SAXException {
  -        ensureConfigured();
  -        getXMLReader().parse(new InputSource(new FileReader(file)));
  -        return script;
  -    }
  -    
  -    
  -    /**
  -     * Parse the content of the specified input source using this XMLParser.
  -     * Returns the root element from the object stack (if any).
  -     *
  -     * @param input Input source containing the XML data to be parsed
  -     *
  -     * @exception IOException if an input/output error occurs
  -     * @exception SAXException if a parsing exception occurs
  -     */
  -    public Script parse(InputSource input) throws IOException, SAXException {
  -        ensureConfigured();
  -        getXMLReader().parse(input);
  -        return script;
  -        
  -    }
  -    
  -    
  -    /**
  -     * Parse the content of the specified input stream using this XMLParser.
  -     * Returns the root element from the object stack (if any).
  -     *
  -     * @param input Input stream containing the XML data to be parsed
  -     *
  -     * @exception IOException if an input/output error occurs
  -     * @exception SAXException if a parsing exception occurs
  -     */
  -    public Script parse(InputStream input) throws IOException, SAXException {
  -        ensureConfigured();
  -        getXMLReader().parse(new InputSource(input));
  -        return script;        
  -    }
  -    
  -    
  -    /**
  -     * Parse the content of the specified reader using this XMLParser.
  -     * Returns the root element from the object stack (if any).
  -     *
  -     * @param reader Reader containing the XML data to be parsed
  -     *
  -     * @exception IOException if an input/output error occurs
  -     * @exception SAXException if a parsing exception occurs
  -     */
  -    public Script parse(Reader reader) throws IOException, SAXException {
  -        ensureConfigured();
  -        getXMLReader().parse(new InputSource(reader));
  -        return script;
  -        
  -    }
  -    
  -    
  -    /**
  -     * Parse the content of the specified URI using this XMLParser.
  -     * Returns the root element from the object stack (if any).
  -     *
  -     * @param uri URI containing the XML data to be parsed
  -     *
  -     * @exception IOException if an input/output error occurs
  -     * @exception SAXException if a parsing exception occurs
  -     */
  -    public Script parse(String uri) throws IOException, SAXException {
  -        ensureConfigured();
  -        getXMLReader().parse(uri);
  -        return script;
  -        
  -    }
  -    
  -    
  -    
  -    /**
  -     * Return the currently mapped namespace URI for the specified prefix,
  -     * if any; otherwise return <code>null</code>.  These mappings come and
  -     * go dynamically as the document is parsed.
  -     *
  -     * @param prefix Prefix to look up
  -     */
  -    public String findNamespaceURI(String prefix) {
  -        ArrayStack stack = (ArrayStack) namespaces.get(prefix);
  -        if (stack == null) {
  -            return (null);
  -        }
  -        try {
  -            return ((String) stack.peek());
  -        }
  -        catch (EmptyStackException e) {
  -            return (null);
  -        }
  -    }
  -    
  -
  -    
  -    // Properties
  -    //-------------------------------------------------------------------------                    
  -    
  -    public JellyContext getJellyContext() {
  -        return context;
  -    }
  -    
  -    public void setJellyContext(JellyContext context) {
  -        this.context = context;
  -    }
  -        
  -    /**
  -     * Return the class loader to be used for instantiating application objects
  -     * when required.  This is determined based upon the following rules:
  -     * <ul>
  -     * <li>The class loader set by <code>setClassLoader()</code>, if any</li>
  -     * <li>The thread context class loader, if it exists and the
  -     *     <code>useContextClassLoader</code> property is set to true</li>
  -     * <li>The class loader used to load the XMLParser class itself.
  -     * </ul>
  -     */
  -    public ClassLoader getClassLoader() {
  -        if (this.classLoader != null) {
  -            return (this.classLoader);
  -        }
  -        if (this.useContextClassLoader) {
  -            ClassLoader classLoader =
  -            Thread.currentThread().getContextClassLoader();
  -            if (classLoader != null) {
  -                return (classLoader);
  -            }
  -        }
  -        return (this.getClass().getClassLoader());
  -    }
  -    
  -    
  -    /**
  -     * Set the class loader to be used for instantiating application objects
  -     * when required.
  -     *
  -     * @param classLoader The new class loader to use, or <code>null</code>
  -     *  to revert to the standard rules
  -     */
  -    public void setClassLoader(ClassLoader classLoader) {
  -        this.classLoader = classLoader;
  -    }
  -    
  -    
  -    
  -    /**
  -     * Return the error handler for this XMLParser.
  -     */
  -    public ErrorHandler getErrorHandler() {
  -        return (this.errorHandler);
  -    }
  -    
  -    
  -    /**
  -     * Set the error handler for this XMLParser.
  -     *
  -     * @param errorHandler The new error handler
  -     */
  -    public void setErrorHandler(ErrorHandler errorHandler) {
  -        this.errorHandler = errorHandler;
  -    }
  -    
  -    
  -    /**
  -     * Return the current Logger associated with this instance of the XMLParser
  -     */
  -    public Log getLogger() {
  -        return log;
  -    }
  -    
  -    
  -    /**
  -     * Set the current logger for this XMLParser.
  -     */
  -    public void setLogger(Log log) {
  -        this.log = log;
  -    }
  -
  -    /** @return the expression factory used to evaluate tag attributes */
  -    public ExpressionFactory getExpressionFactory() {
  -        if ( expressionFactory == null ) {
  -            expressionFactory = createExpressionFactory();
  -        }
  -        return expressionFactory;
  -    }
  -    
  -    /** Sets the expression factory used to evaluate tag attributes */
  -    public void setExpressionFactory(ExpressionFactory expressionFactory) {
  -        this.expressionFactory = expressionFactory;
  -    }
  -    
  -    /**
  -     * Return the SAXParser we will use to parse the input stream.  If there
  -     * is a problem creating the parser, return <code>null</code>.
  -     */
  -    public SAXParser getParser() {
  -        // Return the parser we already created (if any)
  -        if (parser != null) {
  -            return (parser);
  -        }
  -        
  -        // Create and return a new parser
  -        synchronized (this) {
  -            try {
  -                if (factory == null) {
  -                    factory = SAXParserFactory.newInstance();
  -                }
  -                factory.setNamespaceAware(true);
  -                factory.setValidating(validating);
  -                parser = factory.newSAXParser();
  -                return (parser);
  -            }
  -            catch (Exception e) {
  -                log.error("XMLParser.getParser: ", e);
  -                return (null);
  -            }
  -        }
  -    }
  -    
  -    
  -    /**
  -     * By setting the reader in the constructor, you can bypass JAXP and
  -     * be able to use digester in Weblogic 6.0.
  -     *
  -     * @deprecated Use getXMLReader() instead, which can throw a
  -     *  SAXException if the reader cannot be instantiated
  -     */
  -    public XMLReader getReader() {
  -        try {
  -            return (getXMLReader());
  -        }
  -        catch (SAXException e) {
  -            log.error("Cannot get XMLReader", e);
  -            return (null);
  -        }
  -    }
  -    
  -    
  -    /**
  -     * Return the XMLReader to be used for parsing the input document.
  -     *
  -     * @exception SAXException if no XMLReader can be instantiated
  -     */
  -    public synchronized XMLReader getXMLReader() throws SAXException {
  -        if (reader == null) {
  -            reader = getParser().getXMLReader();
  -        }
  -        
  -        //set up the parse
  -        reader.setContentHandler(this);
  -        reader.setDTDHandler(this);
  -        //reader.setEntityResolver(this);
  -        reader.setErrorHandler(this);
  -        return reader;
  -    }
  -    
  -    
  -    
  -    /**
  -     * Return the validating parser flag.
  -     */
  -    public boolean getValidating() {
  -        return (this.validating);
  -    }
  -    
  -    
  -    /**
  -     * Set the validating parser flag.  This must be called before
  -     * <code>parse()</code> is called the first time.
  -     *
  -     * @param validating The new validating parser flag.
  -     */
  -    public void setValidating(boolean validating) {
  -        this.validating = validating;
  -    }
  -    
  -    
  -    /**
  -     * Return the boolean as to whether the context classloader should be used.
  -     */
  -    public boolean getUseContextClassLoader() {
  -        return useContextClassLoader;
  -    }
  -    
  -    
  -    /**
  -     * Determine whether to use the JellyContext ClassLoader (the one found by
  -     * calling <code>Thread.currentThread().getContextClassLoader()</code>)
  -     * to resolve/load classes that are defined in various rules.  If not
  -     * using JellyContext ClassLoader, then the class-loading defaults to
  -     * using the calling-class' ClassLoader.
  -     *
  -     * @param boolean determines whether to use JellyContext ClassLoader.
  -     */
  -    public void setUseContextClassLoader(boolean use) {
  -        useContextClassLoader = use;
  -    }
  -    
  -    
  -    // ContentHandler interface
  -    //-------------------------------------------------------------------------
  -    
  -    /**
  -     * Process notification of the beginning of the document being reached.
  -     *
  -     * @exception SAXException if a parsing error is to be reported
  -     */
  -    public void startDocument() throws SAXException {
  -        script = new ScriptBlock();
  -        textBuffer = new StringBuffer();
  -        tagScript = null;
  -        parentTag = null;
  -        scriptStack.clear();
  -        tagScriptStack.clear();
  -    }
  -    
  -    
  -    /**
  -     * Process notification of the end of the document being reached.
  -     *
  -     * @exception SAXException if a parsing error is to be reported
  -     */
  -    public void endDocument() throws SAXException {
  -        textBuffer = null;
  -    }
  -    
  -    /**
  -     * Process notification of the start of an XML element being reached.
  -     *
  -     * @param uri The Namespace URI, or the empty string if the element
  -     *   has no Namespace URI or if Namespace processing is not being performed.
  -     * @param localName The local name (without prefix), or the empty
  -     *   string if Namespace processing is not being performed.
  -     * @param qName The qualified name (with prefix), or the empty
  -     *   string if qualified names are not available.\
  -     * @param list The attributes attached to the element. If there are
  -     *   no attributes, it shall be an empty Attributes object.
  -     * @exception SAXException if a parsing error is to be reported
  -     */
  -    public void startElement(
  -        String namespaceURI, String localName, String qName, Attributes list
  -    ) throws SAXException {
  -        
  -        // if this is a tag then create a script to run it
  -        // otherwise pass the text to the current body
  -        tagScript = createTag( namespaceURI, localName, list );
  -        if ( tagScript == null ) {
  -            tagScript = createStaticTag( namespaceURI, localName, qName, list );
  -        }
  -        tagScriptStack.add( tagScript );
  -
  -        if ( tagScript != null ) {            
  -            // set parent relationship...
  -            Tag tag = tagScript.getTag();
  -            tag.setParent( parentTag );
  -            parentTag = tag;
  -
  -            if ( textBuffer.length() > 0 ) {
  -                script.addScript( new TextScript( textBuffer.toString() ) );
  -                textBuffer.setLength(0);
  -            }
  -
  -            script.addScript( tagScript );
  -
  -            // start a new body
  -            scriptStack.push( script );
  -            script = new ScriptBlock();
  -            tag.setBody( script );            
  -        }
  -        else {
  -            // XXXX: might wanna handle empty elements later...
  -
  -            textBuffer.append( "<" );
  -            textBuffer.append( qName );
  -            int size = list.getLength();
  -            for ( int i = 0; i < size; i++ ) {
  -                textBuffer.append( " " );
  -                textBuffer.append( list.getQName(i) );
  -                textBuffer.append( "=" );
  -                textBuffer.append( "\"" );
  -                textBuffer.append( list.getValue(i) );
  -                textBuffer.append( "\"" );
  -            }
  -            textBuffer.append( ">" );
  -        }
  -    }
  -    
  -    /**
  -     * Process notification of character data received from the body of
  -     * an XML element.
  -     *
  -     * @param buffer The characters from the XML document
  -     * @param start Starting offset into the buffer
  -     * @param length Number of characters from the buffer
  -     *
  -     * @exception SAXException if a parsing error is to be reported
  -     */
  -    public void characters(char buffer[], int start, int length) throws SAXException {
  -        textBuffer.append(buffer, start, length);
  -    }
  -    
  -    
  -    
  -    /**
  -     * Process notification of the end of an XML element being reached.
  -     *
  -     * @param uri - The Namespace URI, or the empty string if the
  -     *   element has no Namespace URI or if Namespace processing is not
  -     *   being performed.
  -     * @param localName - The local name (without prefix), or the empty
  -     *   string if Namespace processing is not being performed.
  -     * @param qName - The qualified XML 1.0 name (with prefix), or the
  -     *   empty string if qualified names are not available.
  -     * @exception SAXException if a parsing error is to be reported
  -     */
  -    public void endElement(
  -        String namespaceURI, String localName, String qName
  -    ) throws SAXException {        
  -        
  -        tagScript = (TagScript) tagScriptStack.remove( tagScriptStack.size() - 1 );
  -        if ( tagScript != null ) {
  -            if ( textBuffer.length() > 0 ) {
  -                script.addScript( new TextScript( textBuffer.toString() ) );
  -                textBuffer.setLength(0);
  -            }
  -            script = (ScriptBlock) scriptStack.pop();
  -        }
  -        else {
  -            textBuffer.append( "</" );
  -            textBuffer.append( qName );
  -            textBuffer.append( ">" );
  -        }
  -    }
  -    
  -    
  -    /**
  -     * Process notification that a namespace prefix is going out of scope.
  -     *
  -     * @param prefix Prefix that is going out of scope
  -     *
  -     * @exception SAXException if a parsing error is to be reported
  -     */
  -    public void endPrefixMapping(String prefix) throws SAXException {
  -        
  -        // Deregister this prefix mapping
  -        ArrayStack stack = (ArrayStack) namespaces.get(prefix);
  -        if (stack == null) {
  -            return;
  -        }
  -        try {
  -            stack.pop();
  -            if (stack.empty()) {
  -                namespaces.remove(prefix);
  -            }
  -        }
  -        catch (EmptyStackException e) {
  -            throw createSAXException("endPrefixMapping popped too many times");
  -        }
  -        
  -    }
  -    
  -    
  -    /**
  -     * Process notification of ignorable whitespace received from the body of
  -     * an XML element.
  -     *
  -     * @param buffer The characters from the XML document
  -     * @param start Starting offset into the buffer
  -     * @param length Number of characters from the buffer
  -     *
  -     * @exception SAXException if a parsing error is to be reported
  -     */
  -    public void ignorableWhitespace(
  -        char buffer[], int start, int len
  -    ) throws SAXException {
  -        ;	// No processing required
  -        
  -    }
  -    
  -    
  -    /**
  -     * Process notification of a processing instruction that was encountered.
  -     *
  -     * @param target The processing instruction target
  -     * @param data The processing instruction data (if any)
  -     *
  -     * @exception SAXException if a parsing error is to be reported
  -     */
  -    public void processingInstruction(String target, String data)
  -    throws SAXException {
  -        ;	// No processing is required
  -    }
  -    
  -    
  -    /**
  -     * Set the document locator associated with our parser.
  -     *
  -     * @param locator The new locator
  -     */
  -    public void setDocumentLocator(Locator locator) {
  -        this.locator = locator;
  -    }
  -    
  -    
  -    /**
  -     * Process notification of a skipped entity.
  -     *
  -     * @param name Name of the skipped entity
  -     *
  -     * @exception SAXException if a parsing error is to be reported
  -     */
  -    public void skippedEntity(String name) throws SAXException {
  -        ; // No processing required
  -    }
  -    
  -    
  -    /**
  -     * Process notification that a namespace prefix is coming in to scope.
  -     *
  -     * @param prefix Prefix that is being declared
  -     * @param namespaceURI Corresponding namespace URI being mapped to
  -     *
  -     * @exception SAXException if a parsing error is to be reported
  -     */
  -    public void startPrefixMapping(String prefix, String namespaceURI)
  -    throws SAXException {
  -        
  -        // Register this prefix mapping
  -        ArrayStack stack = (ArrayStack) namespaces.get(prefix);
  -        if (stack == null) {
  -            stack = new ArrayStack();
  -            namespaces.put(prefix, stack);
  -        }
  -        stack.push(namespaceURI);
  -    }
  -    
  -    
  -    // DTDHandler interface
  -    //-------------------------------------------------------------------------
  -    
  -    
  -    /**
  -     * Receive notification of a notation declaration event.
  -     *
  -     * @param name The notation name
  -     * @param publicId The public identifier (if any)
  -     * @param systemId The system identifier (if any)
  -     */
  -    public void notationDecl(String name, String publicId, String systemId) {
  -    }
  -    
  -    
  -    /**
  -     * Receive notification of an unparsed entity declaration event.
  -     *
  -     * @param name The unparsed entity name
  -     * @param publicId The public identifier (if any)
  -     * @param systemId The system identifier (if any)
  -     * @param notation The name of the associated notation
  -     */
  -    public void unparsedEntityDecl(
  -        String name, String publicId, String systemId, String notation
  -    ) {
  -    }
  -    
  -    // ErrorHandler interface
  -    //-------------------------------------------------------------------------
  -    
  -    
  -    /**
  -     * Forward notification of a parsing error to the application supplied
  -     * error handler (if any).
  -     *
  -     * @param exception The error information
  -     *
  -     * @exception SAXException if a parsing exception occurs
  -     */
  -    public void error(SAXParseException exception) throws SAXException {
  -        
  -        log.error("Parse Error at line " + exception.getLineNumber() +
  -        " column " + exception.getColumnNumber() + ": " +
  -        exception.getMessage(), exception);
  -        if (errorHandler != null) {
  -            errorHandler.error(exception);
  -        }
  -        
  -    }
  -    
  -    
  -    /**
  -     * Forward notification of a fatal parsing error to the application
  -     * supplied error handler (if any).
  -     *
  -     * @param exception The fatal error information
  -     *
  -     * @exception SAXException if a parsing exception occurs
  -     */
  -    public void fatalError(SAXParseException exception) throws SAXException {
  -        
  -        log.error("Parse Fatal Error at line " + exception.getLineNumber() +
  -        " column " + exception.getColumnNumber() + ": " +
  -        exception.getMessage(), exception);
  -        if (errorHandler != null) {
  -            errorHandler.fatalError(exception);
  -        }
  -        
  -    }
  -    
  -    
  -    /**
  -     * Forward notification of a parse warning to the application supplied
  -     * error handler (if any).
  -     *
  -     * @param exception The warning information
  -     *
  -     * @exception SAXException if a parsing exception occurs
  -     */
  -    public void warning(SAXParseException exception) throws SAXException {
  -        
  -        log.error("Parse Warning at line " + exception.getLineNumber() +
  -        " column " + exception.getColumnNumber() + ": " +
  -        exception.getMessage(), exception);
  -        if (errorHandler != null) {
  -            errorHandler.warning(exception);
  -        }
  -        
  -    }
  -    
  -    
  -    
  -    
  -    
  -    
  -    
  -    // Implementation methods
  -    //-------------------------------------------------------------------------
  -
  -    /**
  -     * If this object has not been configured then register the default
  -     * namespaces
  -     */
  -    private void ensureConfigured() {
  -        if ( ! configured ) {
  -            configure();
  -            configured = true;
  -        }
  -    }
  -    
  -    /**
  -     * This method is called only once before parsing occurs
  -     * which allows tag libraries to be registered and so forth
  -     */
  -    protected void configure() {
  -        // load the properties file of libraries available
  -        InputStream in = null;
  -        URL url = getClassLoader().getResource( "org/apache/commons/jelly/jelly.properties" );
  -        if ( url != null ) {
  -            log.debug( "Loading Jelly default tag libraries from: " + url );
  -            
  -            Properties properties = new Properties();
  -            try {
  -                in = url.openStream();
  -                properties.load( in );
  -                for ( Iterator iter = properties.entrySet().iterator(); iter.hasNext(); ) {
  -                    Map.Entry entry = (Map.Entry) iter.next();
  -                    String uri = (String) entry.getKey();
  -                    String className = (String) entry.getValue();
  -                    context.registerTagLibrary( "jelly:" + uri, className, getClassLoader() );
  -                }
  -            }
  -            catch (IOException e) {
  -                log.error( "Could not load jelly properties from: " + url + ". Reason: " + e, e );
  -            }
  -            finally {
  -                try {
  -                    in.close();
  -                }
  -                catch (Exception e) {
  -                    // ignore
  -                }
  -            }
  -        }
  -    }
  -        
  -    
  -    /**
  -     * Factory method to create new Tag script for the given namespaceURI and name or
  -     * return null if this is not a custom Tag.
  -     */
  -    protected TagScript createTag( String namespaceURI, String localName, Attributes list ) throws SAXException {
  -        try {
  -            // use the URI to load a taglib
  -            TagLibrary taglib = context.getTagLibrary( namespaceURI );
  -            if ( taglib == null ) {
  -                if ( namespaceURI != null && namespaceURI.startsWith( "jelly:" ) ) {
  -                    String uri = namespaceURI.substring(6);
  -                    // try to find the class on the claspath
  -                    try {
  -                        Class taglibClass = getClassLoader().loadClass( uri );
  -                        taglib = (TagLibrary) taglibClass.newInstance();
  -                        
  -                        context.registerTagLibrary( namespaceURI, taglib );
  -                    }
  -                    catch (ClassNotFoundException e) {
  -                        log.warn( "Could not load class: " + uri + " so disabling the taglib" );
  -                    }
  -                }
  -            }
  -            if ( taglib != null ) {
  -                TagScript script = taglib.createTagScript( localName, list );
  -                
  -                // now iterate through through the expressions
  -                int size = list.getLength();
  -                for ( int i = 0; i < size; i++ ) {
  -                    String attributeName = list.getLocalName(i);
  -                    String attributeValue = list.getValue(i);
  -                    Expression expression = taglib.createExpression( getExpressionFactory(), localName, attributeName, attributeValue );
  -                    if ( expression == null ) {
  -                        expression = createConstantExpression( localName, attributeName, attributeValue );
  -                    }
  -                    script.addAttribute( attributeName, expression );
  -                }
  -                return script;
  -                
  -            }
  -            return null;
  -        }
  -        catch (Exception e) {
  -            log.warn( "Could not create taglib or URI: " + namespaceURI + " tag name: " + localName, e );
  -            throw createSAXException(e);
  -        }
  -        catch (Throwable e) {
  -            log.warn( "Could not create taglib or URI: " + namespaceURI + " tag name: " + localName, e );
  -            return null;
  -        }
  -    }
  -    
  -    /**
  -     * Factory method to create a static Tag that represents some static content.
  -     */
  -    protected TagScript createStaticTag( String namespaceURI, String localName, String qName, Attributes list ) throws SAXException {
  -        try {
  -            StaticTag tag = new StaticTag( namespaceURI, localName, qName );
  -            
  -            DynaTagScript script = new DynaTagScript( tag );
  -                
  -            // now iterate through through the expressions
  -            int size = list.getLength();
  -            for ( int i = 0; i < size; i++ ) {
  -                String attributeName = list.getLocalName(i);
  -                String attributeValue = list.getValue(i);
  -                Expression expression = getExpressionFactory().createExpression( attributeValue );
  -                if ( expression == null ) {
  -                    expression = createConstantExpression( localName, attributeName, attributeValue );
  -                }
  -                script.addAttribute( attributeName, expression );
  -            }
  -            return script;
  -        }
  -        catch (Exception e) {
  -            log.warn( "Could not create static tag for URI: " + namespaceURI + " tag name: " + localName, e );
  -            throw createSAXException(e);
  -        }
  -    }
  -    
  -    protected Expression createConstantExpression( String tagName, String attributeName, String attributeValue ) throws Exception {
  -        return new ConstantExpression( attributeValue );
  -    }
  -        
  -    protected ExpressionFactory createExpressionFactory() {
  -        return new JexlExpressionFactory();
  -    }
  -    
  -    
  -    /**
  -     * Create a SAX exception which also understands about the location in
  -     * the file where the exception occurs
  -     *
  -     * @return the new exception
  -     */
  -    protected SAXException createSAXException(String message, Exception e) {
  -        log.warn( "Underlying exception: " + e );
  -        e.printStackTrace();
  -        if (locator != null) {
  -            String error = "Error at (" + locator.getLineNumber() + ", "
  -            + locator.getColumnNumber() + ": " + message;
  -            if (e != null) {
  -                return new SAXParseException(error, locator, e);
  -            } 
  -            else {
  -                return new SAXParseException(error, locator);
  -            }
  -        }
  -        log.error("No Locator!");
  -        if (e != null) {
  -            return new SAXException(message, e);
  -        } 
  -        else {
  -            return new SAXException(message);
  -        }
  -    }
  -    
  -    /**
  -     * Create a SAX exception which also understands about the location in
  -     * the digester file where the exception occurs
  -     *
  -     * @return the new exception
  -     */
  -    protected SAXException createSAXException(Exception e) {
  -        return createSAXException(e.getMessage(), e);
  -    }
  -    
  -    /**
  -     * Create a SAX exception which also understands about the location in
  -     * the digester file where the exception occurs
  -     *
  -     * @return the new exception
  -     */
  -    protected SAXException createSAXException(String message) {
  -        return createSAXException(message, null);
  -    }
  -}
  +/*
 * $Header: /home/cvs/jakarta-commons-sandbox/jelly/src/java/org/apache/commons/jelly/parser/XMLParser.java,v 1.15 2002/05/15 16:21:06 jstrachan Exp $
 * $Revision: 1.15 $
 * $Date: 2002/05/15 16:21:06 $
 *
 * ====================================================================
 *
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999-2002 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution, if
 *    any, must include the following acknowlegement:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowlegement may appear in the software itself,
 *    if and wherever such third-party acknowlegements normally appear.
 *
 * 4. The names "The Jakarta Project", "Commons", and "Apache Software
 *    Foundation" must not be used to endorse or promote products derived
 *    from this software without prior written permission. For written
 *    permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache"
 *    nor may "Apache" appear in their names without prior written
 *    permission of the Apache Group.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 *
 * $Id: XMLParser.java,v 1.15 2002/05/15 16:21:06 jstrachan Exp $
 */

package org.apache.commons.jelly.parser;

import java.io.File;

import java.io.FileReader;

import java.io.InputStream;

import java.io.IOException;

import java.io.PrintWriter;

import java.io.Reader;

import java.net.URL;

import java.net.URLConnection;

import java.util.ArrayList;

import java.util.EmptyStackException;

import java.util.HashMap;

import java.util.Iterator;

import java.util.List;

import java.util.Map;

import java.util.Properties;

import javax.xml.parsers.SAXParser;

import javax.xml.parsers.SAXParserFactory;

import org.apache.commons.collections.ArrayStack;

import org.apache.commons.jelly.JellyContext;

import org.apache.commons.jelly.Script;

import org.apache.commons.jelly.Tag;

import org.apache.commons.jelly.TagLibrary;

import org.apache.commons.jelly.impl.ScriptBlock;

import org.apache.commons.jelly.impl.StaticTag;

import org.apache.commons.jelly.impl.DynaTagScript;

import org.apache.commons.jelly.impl.TagScript;

import org.apache.commons.jelly.impl.TextScript;

import org.apache.commons.jelly.expression.ConstantExpression;

import org.apache.commons.jelly.expression.Expression;

import org.apache.commons.jelly.expression.ExpressionFactory;

import org.apache.commons.jelly.expression.jexl.JexlExpressionFactory;

import org.apache.commons.jelly.tags.core.CoreTagLibrary;

import org.apache.commons.jelly.tags.xml.XMLTagLibrary;

import org.apache.commons.logging.Log;

import org.apache.commons.logging.LogFactory;

import org.xml.sax.Attributes;

import org.xml.sax.ContentHandler;

import org.xml.sax.EntityResolver;

import org.xml.sax.ErrorHandler;

import org.xml.sax.helpers.DefaultHandler;

import org.xml.sax.InputSource;

import org.xml.sax.Locator;

import org.xml.sax.SAXException;

import org.xml.sax.SAXParseException;

import org.xml.sax.XMLReader;

/** <p><code>XMLParser</code> parses the XML Jelly format.
 * The SAXParser and XMLReader portions of this code come from Digester.</p>
 *
 * @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
 * @version $Revision: 1.15 $
 */

public class XMLParser extends DefaultHandler {

    /** JellyContext which is used to locate tag libraries*/

    private JellyContext context = new JellyContext();

    /** the expression factory used to evaluate tag attributes */

    private ExpressionFactory expressionFactory;

    /** The current script block */

    private ScriptBlock script;

    /** The current tagScript */

    private TagScript tagScript;

    /** The current parent tag */

    private Tag parentTag;

    /** The stack of body scripts. */

    private ArrayStack scriptStack = new ArrayStack();

    /** The stack of tagScripts - use ArrayList as it allows null. */

    private ArrayList tagScriptStack = new ArrayList();

    /** The current text buffer where non-custom tags get written */

    private StringBuffer textBuffer;

    /**
     * The class loader to use for instantiating application objects.
     * If not specified, the context class loader, or the class loader
     * used to load XMLParser itself, is used, based on the value of the
     * <code>useContextClassLoader</code> variable.
     */

    protected ClassLoader classLoader = null;

    /**
     * The application-supplied error handler that is notified when parsing
     * warnings, errors, or fatal errors occur.
     */

    protected ErrorHandler errorHandler = null;

    /**
     * The SAXParserFactory that is created the first time we need it.
     */

    protected static SAXParserFactory factory = null;

    /**
     * The SAXParser we will use to parse the input stream.
     */

    protected SAXParser parser = null;

    /**
     * The XMLReader used to parse digester rules.
     */

    protected XMLReader reader = null;

    /**
     * The Locator associated with our parser.
     */

    protected Locator locator = null;

    /**
     * Registered namespaces we are currently processing.  The key is the
     * namespace prefix that was declared in the document.  The value is an
     * ArrayStack of the namespace URIs this prefix has been mapped to --
     * the top Stack element is the most current one.  (This architecture
     * is required because documents can declare nested uses of the same
     * prefix for different Namespace URIs).
     */

    protected HashMap namespaces = new HashMap();

    /**
     * Do we want to use the JellyContext ClassLoader when loading classes
     * for instantiating new objects?  Default is <code>false</code>.
     */

    protected boolean useContextClassLoader = false;

    /**
     * Do we want to use a validating parser?
     */

    protected boolean validating = false;

    /** Flag to indicate if this object has been configured */

    private boolean configured;

    /**
     * The Log to which logging calls will be made.
     */

    private Log log = LogFactory.getLog(XMLParser.class);

    /**
     * Construct a new XMLParser with default properties.
     */

    public XMLParser() {

    }

    /**
     * Construct a new XMLParser, allowing a SAXParser to be passed in.  This
     * allows XMLParser to be used in environments which are unfriendly to
     * JAXP1.1 (such as WebLogic 6.0).  Thanks for the request to change go to
     * James House (james@interobjective.com).  This may help in places where
     * you are able to load JAXP 1.1 classes yourself.
     */

    public XMLParser(SAXParser parser) {

        this.parser = parser;

    }

    /**
     * Construct a new XMLParser, allowing an XMLReader to be passed in.  This
     * allows XMLParser to be used in environments which are unfriendly to
     * JAXP1.1 (such as WebLogic 6.0).  Note that if you use this option you
     * have to configure namespace and validation support yourself, as these
     * properties only affect the SAXParser and emtpy constructor.
     */

    public XMLParser(XMLReader reader) {

        this.reader = reader;

    }

    /**
     * Parse the content of the specified file using this XMLParser.  Returns
     * the root element from the object stack (if any).
     *
     * @param file File containing the XML data to be parsed
     *
     * @exception IOException if an input/output error occurs
     * @exception SAXException if a parsing exception occurs
     */

    public Script parse(File file) throws IOException, SAXException {

        ensureConfigured();

        getXMLReader().parse(new InputSource(new FileReader(file)));

        return script;

    }

    /**
     * Parse the content of the specified input source using this XMLParser.
     * Returns the root element from the object stack (if any).
     *
     * @param input Input source containing the XML data to be parsed
     *
     * @exception IOException if an input/output error occurs
     * @exception SAXException if a parsing exception occurs
     */

    public Script parse(InputSource input) throws IOException, SAXException {

        ensureConfigured();

        getXMLReader().parse(input);

        return script;

    }

    /**
     * Parse the content of the specified input stream using this XMLParser.
     * Returns the root element from the object stack (if any).
     *
     * @param input Input stream containing the XML data to be parsed
     *
     * @exception IOException if an input/output error occurs
     * @exception SAXException if a parsing exception occurs
     */

    public Script parse(InputStream input) throws IOException, SAXException {

        ensureConfigured();

        getXMLReader().parse(new InputSource(input));

        return script;

    }

    /**
     * Parse the content of the specified reader using this XMLParser.
     * Returns the root element from the object stack (if any).
     *
     * @param reader Reader containing the XML data to be parsed
     *
     * @exception IOException if an input/output error occurs
     * @exception SAXException if a parsing exception occurs
     */

    public Script parse(Reader reader) throws IOException, SAXException {

        ensureConfigured();

        getXMLReader().parse(new InputSource(reader));

        return script;

    }

    /**
     * Parse the content of the specified URI using this XMLParser.
     * Returns the root element from the object stack (if any).
     *
     * @param uri URI containing the XML data to be parsed
     *
     * @exception IOException if an input/output error occurs
     * @exception SAXException if a parsing exception occurs
     */

    public Script parse(String uri) throws IOException, SAXException {

        ensureConfigured();

        getXMLReader().parse(uri);

        return script;

    }

    /**
     * Return the currently mapped namespace URI for the specified prefix,
     * if any; otherwise return <code>null</code>.  These mappings come and
     * go dynamically as the document is parsed.
     *
     * @param prefix Prefix to look up
     */

    public String findNamespaceURI(String prefix) {

        ArrayStack stack = (ArrayStack) namespaces.get(prefix);

        if (stack == null) {

            return (null);

        }

        try {

            return ((String) stack.peek());

        }

        catch (EmptyStackException e) {

            return (null);

        }

    }

    // Properties

    //-------------------------------------------------------------------------                    

    public JellyContext getJellyContext() {

        return context;

    }

    public void setJellyContext(JellyContext context) {

        this.context = context;

    }

    /**
     * Return the class loader to be used for instantiating application objects
     * when required.  This is determined based upon the following rules:
     * <ul>
     * <li>The class loader set by <code>setClassLoader()</code>, if any</li>
     * <li>The thread context class loader, if it exists and the
     *     <code>useContextClassLoader</code> property is set to true</li>
     * <li>The class loader used to load the XMLParser class itself.
     * </ul>
     */

    public ClassLoader getClassLoader() {

        if (this.classLoader != null) {

            return (this.classLoader);

        }

        if (this.useContextClassLoader) {

            ClassLoader classLoader = Thread.currentThread().getContextClassLoader();

            if (classLoader != null) {

                return (classLoader);

            }

        }

        return (this.getClass().getClassLoader());

    }

    /**
     * Set the class loader to be used for instantiating application objects
     * when required.
     *
     * @param classLoader The new class loader to use, or <code>null</code>
     *  to revert to the standard rules
     */

    public void setClassLoader(ClassLoader classLoader) {

        this.classLoader = classLoader;

    }

    /**
     * Return the error handler for this XMLParser.
     */

    public ErrorHandler getErrorHandler() {

        return (this.errorHandler);

    }

    /**
     * Set the error handler for this XMLParser.
     *
     * @param errorHandler The new error handler
     */

    public void setErrorHandler(ErrorHandler errorHandler) {

        this.errorHandler = errorHandler;

    }

    /**
     * Return the current Logger associated with this instance of the XMLParser
     */

    public Log getLogger() {

        return log;

    }

    /**
     * Set the current logger for this XMLParser.
     */

    public void setLogger(Log log) {

        this.log = log;

    }

    /** @return the expression factory used to evaluate tag attributes */

    public ExpressionFactory getExpressionFactory() {

        if (expressionFactory == null) {

            expressionFactory = createExpressionFactory();

        }

        return expressionFactory;

    }

    /** Sets the expression factory used to evaluate tag attributes */

    public void setExpressionFactory(ExpressionFactory expressionFactory) {

        this.expressionFactory = expressionFactory;

    }

    /**
     * Return the SAXParser we will use to parse the input stream.  If there
     * is a problem creating the parser, return <code>null</code>.
     */

    public SAXParser getParser() {

        // Return the parser we already created (if any)

        if (parser != null) {

            return (parser);

        }

        // Create and return a new parser

        synchronized (this) {

            try {

                if (factory == null) {

                    factory = SAXParserFactory.newInstance();

                }

                factory.setNamespaceAware(true);

                factory.setValidating(validating);

                parser = factory.newSAXParser();

                return (parser);

            }

            catch (Exception e) {

                log.error("XMLParser.getParser: ", e);

                return (null);

            }

        }

    }

    /**
     * By setting the reader in the constructor, you can bypass JAXP and
     * be able to use digester in Weblogic 6.0.
     *
     * @deprecated Use getXMLReader() instead, which can throw a
     *  SAXException if the reader cannot be instantiated
     */

    public XMLReader getReader() {

        try {

            return (getXMLReader());

        }

        catch (SAXException e) {

            log.error("Cannot get XMLReader", e);

            return (null);

        }

    }

    /**
     * Return the XMLReader to be used for parsing the input document.
     *
     * @exception SAXException if no XMLReader can be instantiated
     */

    public synchronized XMLReader getXMLReader() throws SAXException {

        if (reader == null) {

            reader = getParser().getXMLReader();

        }

        //set up the parse

        reader.setContentHandler(this);

        reader.setDTDHandler(this);

        //reader.setEntityResolver(this);

        reader.setErrorHandler(this);

        return reader;

    }

    /**
     * Return the validating parser flag.
     */

    public boolean getValidating() {

        return (this.validating);

    }

    /**
     * Set the validating parser flag.  This must be called before
     * <code>parse()</code> is called the first time.
     *
     * @param validating The new validating parser flag.
     */

    public void setValidating(boolean validating) {

        this.validating = validating;

    }

    /**
     * Return the boolean as to whether the context classloader should be used.
     */

    public boolean getUseContextClassLoader() {

        return useContextClassLoader;

    }

    /**
     * Determine whether to use the JellyContext ClassLoader (the one found by
     * calling <code>Thread.currentThread().getContextClassLoader()</code>)
     * to resolve/load classes that are defined in various rules.  If not
     * using JellyContext ClassLoader, then the class-loading defaults to
     * using the calling-class' ClassLoader.
     *
     * @param boolean determines whether to use JellyContext ClassLoader.
     */

    public void setUseContextClassLoader(boolean use) {

        useContextClassLoader = use;

    }

    // ContentHandler interface
    //-------------------------------------------------------------------------

    /**
     * Process notification of the beginning of the document being reached.
     *
     * @exception SAXException if a parsing error is to be reported
     */

    public void startDocument() throws SAXException {

        script = new ScriptBlock();

        textBuffer = new StringBuffer();

        tagScript = null;

        parentTag = null;

        scriptStack.clear();

        tagScriptStack.clear();

    }

    /**
     * Process notification of the end of the document being reached.
     *
     * @exception SAXException if a parsing error is to be reported
     */

    public void endDocument() throws SAXException {

        textBuffer = null;

    }

    /**
     * Process notification of the start of an XML element being reached.
     *
     * @param uri The Namespace URI, or the empty string if the element
     *   has no Namespace URI or if Namespace processing is not being performed.
     * @param localName The local name (without prefix), or the empty
     *   string if Namespace processing is not being performed.
     * @param qName The qualified name (with prefix), or the empty
     *   string if qualified names are not available.\
     * @param list The attributes attached to the element. If there are
     *   no attributes, it shall be an empty Attributes object.
     * @exception SAXException if a parsing error is to be reported
     */

    public void startElement(
        String namespaceURI,
        String localName,
        String qName,
        Attributes list)
        throws SAXException {

        // if this is a tag then create a script to run it

        // otherwise pass the text to the current body

        tagScript = createTag(namespaceURI, localName, list);

        if (tagScript == null) {

            tagScript = createStaticTag(namespaceURI, localName, qName, list);

        }

        tagScriptStack.add(tagScript);

        if (tagScript != null) {

            // set parent relationship...

            Tag tag = tagScript.getTag();

            tag.setParent(parentTag);

            parentTag = tag;

            if (textBuffer.length() > 0) {

                script.addScript(new TextScript(textBuffer.toString()));

                textBuffer.setLength(0);

            }

            script.addScript(tagScript);

            // start a new body

            scriptStack.push(script);

            script = new ScriptBlock();

            tag.setBody(script);

        }

        else {

            // XXXX: might wanna handle empty elements later...

            textBuffer.append("<");

            textBuffer.append(qName);

            int size = list.getLength();

            for (int i = 0; i < size; i++) {

                textBuffer.append(" ");

                textBuffer.append(list.getQName(i));

                textBuffer.append("=");

                textBuffer.append("\"");

                textBuffer.append(list.getValue(i));

                textBuffer.append("\"");

            }

            textBuffer.append(">");

        }

    }

    /**
     * Process notification of character data received from the body of
     * an XML element.
     *
     * @param buffer The characters from the XML document
     * @param start Starting offset into the buffer
     * @param length Number of characters from the buffer
     *
     * @exception SAXException if a parsing error is to be reported
     */

    public void characters(char buffer[], int start, int length)
        throws SAXException {

        textBuffer.append(buffer, start, length);

    }

    /**
     * Process notification of the end of an XML element being reached.
     *
     * @param uri - The Namespace URI, or the empty string if the
     *   element has no Namespace URI or if Namespace processing is not
     *   being performed.
     * @param localName - The local name (without prefix), or the empty
     *   string if Namespace processing is not being performed.
     * @param qName - The qualified XML 1.0 name (with prefix), or the
     *   empty string if qualified names are not available.
     * @exception SAXException if a parsing error is to be reported
     */

    public void endElement(String namespaceURI, String localName, String qName)
        throws SAXException {

        tagScript = (TagScript) tagScriptStack.remove(tagScriptStack.size() - 1);

        if (tagScript != null) {

            if (textBuffer.length() > 0) {

                script.addScript(new TextScript(textBuffer.toString()));

                textBuffer.setLength(0);

            }

            script = (ScriptBlock) scriptStack.pop();

        }

        else {

            textBuffer.append("</");

            textBuffer.append(qName);

            textBuffer.append(">");

        }

    }

    /**
     * Process notification that a namespace prefix is going out of scope.
     *
     * @param prefix Prefix that is going out of scope
     *
     * @exception SAXException if a parsing error is to be reported
     */

    public void endPrefixMapping(String prefix) throws SAXException {

        // Deregister this prefix mapping

        ArrayStack stack = (ArrayStack) namespaces.get(prefix);

        if (stack == null) {

            return;

        }

        try {

            stack.pop();

            if (stack.empty()) {

                namespaces.remove(prefix);

            }

        }

        catch (EmptyStackException e) {

            throw createSAXException("endPrefixMapping popped too many times");

        }

    }

    /**
     * Process notification of ignorable whitespace received from the body of
     * an XML element.
     *
     * @param buffer The characters from the XML document
     * @param start Starting offset into the buffer
     * @param length Number of characters from the buffer
     *
     * @exception SAXException if a parsing error is to be reported
     */

    public void ignorableWhitespace(char buffer[], int start, int len)
        throws SAXException {

        ; // No processing required

    }

    /**
     * Process notification of a processing instruction that was encountered.
     *
     * @param target The processing instruction target
     * @param data The processing instruction data (if any)
     *
     * @exception SAXException if a parsing error is to be reported
     */

    public void processingInstruction(String target, String data)
        throws SAXException {

        ; // No processing is required

    }

    /**
     * Set the document locator associated with our parser.
     *
     * @param locator The new locator
     */

    public void setDocumentLocator(Locator locator) {

        this.locator = locator;

    }

    /**
     * Process notification of a skipped entity.
     *
     * @param name Name of the skipped entity
     *
     * @exception SAXException if a parsing error is to be reported
     */

    public void skippedEntity(String name) throws SAXException {

        ; // No processing required

    }

    /**
     * Process notification that a namespace prefix is coming in to scope.
     *
     * @param prefix Prefix that is being declared
     * @param namespaceURI Corresponding namespace URI being mapped to
     *
     * @exception SAXException if a parsing error is to be reported
     */

    public void startPrefixMapping(String prefix, String namespaceURI)
        throws SAXException {

        // Register this prefix mapping

        ArrayStack stack = (ArrayStack) namespaces.get(prefix);

        if (stack == null) {

            stack = new ArrayStack();

            namespaces.put(prefix, stack);

        }

        stack.push(namespaceURI);

    }

    // DTDHandler interface

    //-------------------------------------------------------------------------

    /**
     * Receive notification of a notation declaration event.
     *
     * @param name The notation name
     * @param publicId The public identifier (if any)
     * @param systemId The system identifier (if any)
     */

    public void notationDecl(String name, String publicId, String systemId) {

    }

    /**
     * Receive notification of an unparsed entity declaration event.
     *
     * @param name The unparsed entity name
     * @param publicId The public identifier (if any)
     * @param systemId The system identifier (if any)
     * @param notation The name of the associated notation
     */

    public void unparsedEntityDecl(
        String name,
        String publicId,
        String systemId,
        String notation) {

    }

    // ErrorHandler interface

    //-------------------------------------------------------------------------

    /**
     * Forward notification of a parsing error to the application supplied
     * error handler (if any).
     *
     * @param exception The error information
     *
     * @exception SAXException if a parsing exception occurs
     */

    public void error(SAXParseException exception) throws SAXException {

        log.error(
            "Parse Error at line "
                + exception.getLineNumber()
                + " column "
                + exception.getColumnNumber()
                + ": "
                + exception.getMessage(),
            exception);

        if (errorHandler != null) {

            errorHandler.error(exception);

        }

    }

    /**
     * Forward notification of a fatal parsing error to the application
     * supplied error handler (if any).
     *
     * @param exception The fatal error information
     *
     * @exception SAXException if a parsing exception occurs
     */

    public void fatalError(SAXParseException exception) throws SAXException {

        log.error(
            "Parse Fatal Error at line "
                + exception.getLineNumber()
                + " column "
                + exception.getColumnNumber()
                + ": "
                + exception.getMessage(),
            exception);

        if (errorHandler != null) {

            errorHandler.fatalError(exception);

        }

    }

    /**
     * Forward notification of a parse warning to the application supplied
     * error handler (if any).
     *
     * @param exception The warning information
     *
     * @exception SAXException if a parsing exception occurs
     */

    public void warning(SAXParseException exception) throws SAXException {

        log.error(
            "Parse Warning at line "
                + exception.getLineNumber()
                + " column "
                + exception.getColumnNumber()
                + ": "
                + exception.getMessage(),
            exception);

        if (errorHandler != null) {

            errorHandler.warning(exception);

        }

    }

    // Implementation methods

    //-------------------------------------------------------------------------

    /**
     * If this object has not been configured then register the default
     * namespaces
     */

    private void ensureConfigured() {

        if (!configured) {

            configure();

            configured = true;

        }

    }

    /**
     * This method is called only once before parsing occurs
     * which allows tag libraries to be registered and so forth
     */

    protected void configure() {

        // load the properties file of libraries available

        InputStream in = null;

        URL url =
            getClassLoader().getResource("org/apache/commons/jelly/jelly.properties");

        if (url != null) {

            log.debug("Loading Jelly default tag libraries from: " + url);

            Properties properties = new Properties();

            try {

                in = url.openStream();

                properties.load(in);

                for (Iterator iter = properties.entrySet().iterator(); iter.hasNext();) {

                    Map.Entry entry = (Map.Entry) iter.next();

                    String uri = (String) entry.getKey();

                    String className = (String) entry.getValue();

                    context.registerTagLibrary("jelly:" + uri, className);

                }

            }

            catch (IOException e) {

                log.error("Could not load jelly properties from: " + url + ". Reason: " + e, e);

            }

            finally {

                try {

                    in.close();

                }

                catch (Exception e) {

                    // ignore

                }

            }

        }

    }

    /**
     * Factory method to create new Tag script for the given namespaceURI and name or
     * return null if this is not a custom Tag.
     */

    protected TagScript createTag(
        String namespaceURI,
        String localName,
        Attributes list)
        throws SAXException {

        try {

            // use the URI to load a taglib

            TagLibrary taglib = context.getTagLibrary(namespaceURI);

            if (taglib == null) {

                if (namespaceURI != null && namespaceURI.startsWith("jelly:")) {

                    String uri = namespaceURI.substring(6);

                    // try to find the class on the claspath

                    try {

                        Class taglibClass = getClassLoader().loadClass(uri);

                        taglib = (TagLibrary) taglibClass.newInstance();

                        context.registerTagLibrary(namespaceURI, taglib);

                    }

                    catch (ClassNotFoundException e) {

                        log.warn("Could not load class: " + uri + " so disabling the taglib");

                    }

                }

            }

            if (taglib != null) {

                TagScript script = taglib.createTagScript(localName, list);

                // now iterate through through the expressions

                int size = list.getLength();

                for (int i = 0; i < size; i++) {

                    String attributeName = list.getLocalName(i);

                    String attributeValue = list.getValue(i);

                    Expression expression =
                        taglib.createExpression(
                            getExpressionFactory(),
                            localName,
                            attributeName,
                            attributeValue);

                    if (expression == null) {

                        expression = createConstantExpression(localName, attributeName, attributeValue);

                    }

                    script.addAttribute(attributeName, expression);

                }

                return script;

            }

            return null;

        }

        catch (Exception e) {

            log.warn(
                "Could not create taglib or URI: " + namespaceURI + " tag name: " + localName,
                e);

            throw createSAXException(e);

        }

        catch (Throwable e) {

            log.warn(
                "Could not create taglib or URI: " + namespaceURI + " tag name: " + localName,
                e);

            return null;

        }

    }

    /**
     * Factory method to create a static Tag that represents some static content.
     */

    protected TagScript createStaticTag(
        String namespaceURI,
        String localName,
        String qName,
        Attributes list)
        throws SAXException {

        try {

            StaticTag tag = new StaticTag(namespaceURI, localName, qName);

            DynaTagScript script = new DynaTagScript(tag);

            // now iterate through through the expressions

            int size = list.getLength();

            for (int i = 0; i < size; i++) {

                String attributeName = list.getLocalName(i);

                String attributeValue = list.getValue(i);

                Expression expression = getExpressionFactory().createExpression(attributeValue);

                if (expression == null) {

                    expression = createConstantExpression(localName, attributeName, attributeValue);

                }

                script.addAttribute(attributeName, expression);

            }

            return script;

        }

        catch (Exception e) {

            log.warn(
                "Could not create static tag for URI: "
                    + namespaceURI
                    + " tag name: "
                    + localName,
                e);

            throw createSAXException(e);

        }

    }

    protected Expression createConstantExpression(
        String tagName,
        String attributeName,
        String attributeValue)
        throws Exception {

        return new ConstantExpression(attributeValue);

    }

    protected ExpressionFactory createExpressionFactory() {

        return new JexlExpressionFactory();

    }

    /**
     * Create a SAX exception which also understands about the location in
     * the file where the exception occurs
     *
     * @return the new exception
     */

    protected SAXException createSAXException(String message, Exception e) {

        log.warn("Underlying exception: " + e);

        e.printStackTrace();

        if (locator != null) {

            String error =
                "Error at ("
                    + locator.getLineNumber()
                    + ", "
                    + locator.getColumnNumber()
                    + ": "
                    + message;

            if (e != null) {

                return new SAXParseException(error, locator, e);

            }

            else {

                return new SAXParseException(error, locator);

            }

        }

        log.error("No Locator!");

        if (e != null) {

            return new SAXException(message, e);

        }

        else {

            return new SAXException(message);

        }

    }

    /**
     * Create a SAX exception which also understands about the location in
     * the digester file where the exception occurs
     *
     * @return the new exception
     */

    protected SAXException createSAXException(Exception e) {

        return createSAXException(e.getMessage(), e);

    }

    /**
     * Create a SAX exception which also understands about the location in
     * the digester file where the exception occurs
     *
     * @return the new exception
     */

    protected SAXException createSAXException(String message) {

        return createSAXException(message, null);

    }

}
  \ No newline at end of file
  
  
  

--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>