You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by pi...@locus.apache.org on 2000/09/19 21:19:23 UTC

cvs commit: jakarta-tomcat-4.0/jasper/src/share/org/apache/jasper/compiler ParserController.java ParserXJspSax.java ParserXJspSaxHandler.java XmlOutputter.java PageInfoImpl.java

pierred     00/09/19 12:19:22

  Added:       jasper/src/share/org/apache/jasper/compiler
                        ParserController.java ParserXJspSax.java
                        ParserXJspSaxHandler.java XmlOutputter.java
                        PageInfoImpl.java
  Log:
  New classes for the support of XML syntax in jasper
  
  Revision  Changes    Path
  1.1                  jakarta-tomcat-4.0/jasper/src/share/org/apache/jasper/compiler/ParserController.java
  
  Index: ParserController.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999 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", "Tomcat", 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/>.
   *
   */
  package org.apache.jasper.compiler;
  
  import java.io.*;
  import java.util.*;
  
  import javax.servlet.jsp.tagext.*;
  
  import org.xml.sax.InputSource;
  
  import org.apache.jasper.*;
  
  import org.apache.jasper.logging.Logger;
  
  /**
   * Controller for the parsing of a JSP page.
   * <p>
   * A translation unit (JSP source file and any files included via the
   * include directive) may involve the processing of JSP pages
   * written with different syntaxes (currently the original JSP syntax,
   * as well as the XML syntax (as of JSP 1.2)). This class encapsulates 
   * the behavior related to the selection and invocation of 
   * the proper parser.
   *
   * Note: There's some 'commented out' code that would allow
   * the dynamic generation of a DTD so we could use a validating
   * parser. Should be working, but would like to investigate
   * XML schema before using validating parser.
   *
   * @author Pierre Delisle
   */
  public class ParserController {
      /*
       * The compilation context
       */
      private JspCompilationContext ctxt;
  
      /*
       * The filename and path of the file being currently parsed.
       * This is used to define the path to a file that may
       * be included by that 'parent' file.
       */
      private String currentFilePath = null;
      private String currentFileName = null;
  
      /*
       * The parse 'event handler', shared by both
       * types of parsers.
       */
      private ParseEventListener jspHandler = null;
  
      /*
       * Document information which tells us what
       * kind of document we are dealing with.
       */
      private boolean isXml;
      
      /*
       * Static information used in the process of figuring out
       * the kind of document we're dealing with.
       */
      private static final String XML_PROLOG_TAG = "<?xml";
      private static final String JSP_ROOT_TAG   = "<jsp:root";
  
      /*
       * Information to allow us to dynamically generate the
       * DTD to be used to validate the XML document.
       * @@@[This has been pulled out for the time being.
       * We only support non-validating SAX parser. Might want
       * to put it back eventually, or use XML Schema]
       */
      /* NOT COMPILED
      static final String JSP_TAGLIB_TAG = "jsp:directive.taglib";
      boolean hasTaglib;  // does xml document have tag lib(s)?
      InputSource dtdInputSource;
      static String jspDtd_part1 = null;
      static String jspDtd_part2 = null;
      */
  
      /*
       * Cached value of the class name of the SAX2 driver. 
       */
      String sax2DriverClassName;
  
      //*********************************************************************
      // Constructor
  
      public ParserController(JspCompilationContext ctxt) {
          this.ctxt = ctxt; // @@@ can we assert that ctxt is not null?
          jspHandler = new JspParseEventListener(ctxt, this);
  	sax2DriverClassName = ctxt.getOptions().getSax2DriverClassName();
  	
  	/* @@@ NOT COMPILED
  	// Cache the content of the jsp DTD
  	if (jspDtd_part1 == null) {
  	    jspDtd_part1 = getFileContent("/org/apache/jasper/resources/jsp12_part1.dtd");
  	    jspDtd_part2 = getFileContent("/org/apache/jasper/resources/jsp12_part2.dtd");
  	}
          */
      }
     
      //*********************************************************************
      // Accessors
  
      public ParseEventListener getParseEventListener() {
  	return jspHandler;
      }
  
      //*********************************************************************
      // Parse
  
      public void parse(String inFileName) throws JasperException {
          parse(inFileName, null);
      }
  
      /**
       * Parse the jsp page provided as an argument.
       * First invoked by the compiler, then invoked recursively by the
       * parser event handler for each 'include' directive.
       *
       * @param The name of the jsp file to be parsed.
       */
      public void parse(String inFileName, String encoding)
  	throws JasperException
      {
          //p("parse(" + inFileName + ", " + encoding + ")");
          resolveFileName(inFileName);
  
          if (encoding == null) {
              encoding = "8859_1"; // default per JSP spec
              // XXX - longer term, this should really be:
              //   System.getProperty("file.encoding", "8859_1");
              // but this doesn't work right now, so we stick with ASCII
          }
  
  	// @@@ need to do a pass at JSP doc to find encoding as specified
  	// @@@ in page directive (see JspParseEventListener)
  
          File file = new File(currentFileName);
  	currentFilePath = (ctxt == null) 
  	    ? file.getAbsolutePath()
  	    : ctxt.getRealPath(file.toString());
  	//p("currentFilePath: " + currentFilePath);
  
          InputStreamReader reader = null;
          try {
              // Figure out what type of JSP document we are dealing with
              reader = getReader(file, encoding);
              figureOutJspDocument(file, encoding, reader);
              //p("isXml = " + isXml + "   hasTaglib = " + hasTaglib);
  
              // dispatch to the proper parser
  	    try {
  		reader.close();
  	    } catch (IOException ex) {}
              reader = getReader(file, encoding);
              if (isXml) {
                  (new ParserXJspSax(currentFilePath, reader, jspHandler, sax2DriverClassName)).parse();
              } else {
                  (new Parser(ctxt, file, encoding, reader, jspHandler)).parse();
              }
          } catch (FileNotFoundException ex) {
              throw new JasperException(ex);
          } finally {
              if (reader != null) {
                  try {
                      reader.close();
  		} catch (Exception any) {}
  	    }
          }
      }
  
      //*********************************************************************
      // Figure out input Document
  
      private void figureOutJspDocument(File file, 
  				      String encoding,
  				      InputStreamReader reader)
  	 throws JasperException
      {
  	JspReader jspReader;
  	try {
  	    jspReader = new JspReader(ctxt, file, encoding, reader);
  	} catch (FileNotFoundException ex) {
  	    throw new JasperException(ex);
  	}
          jspReader.setSingleFile(true);
          Mark startMark = jspReader.mark();
  
          // check the prolog (ideally it's been included if it is an xml doc)
          Mark mark = jspReader.skipUntil(XML_PROLOG_TAG);
          if (mark != null) {
              isXml = true;
          } else {
              // must have the jsp:root tag
              jspReader.reset(startMark);
              mark = jspReader.skipUntil(JSP_ROOT_TAG);
              if (mark != null) {
                  isXml = true;
              } else {
                  isXml = false;
                  return;
              }
          }
  
  	/* NOT COMPILED
          // This is an XML document. Let's see if it uses tag libraries.
          jspReader.reset(startMark);
          Vector taglibMarks = new Vector();
          mark = jspReader.skipUntil(JSP_TAGLIB_TAG);
          while (mark != null) {
              taglibMarks.add(mark);
              mark = jspReader.skipUntil(JSP_TAGLIB_TAG);
          }
          hasTaglib = (taglibMarks.size() > 0);
          if (!hasTaglib) return;
  
          // The JSP document uses tag libraries. We parse the tag libraries and then
          // we will generate the JSP DTD on the fly to include the custom tags.
          // This way, we can use a validating xml parser.
  	dtdInputSource = buildDtd(jspReader, taglibMarks);
  	*/
      }
      
      /* NOT COMPILED 
      private InputSource buildDtd(JspReader jspReader, Vector taglibMarks) 
  	throws JasperException
      {
          TagLibraries libraries = new TagLibraries(null);
  
          Enumeration enum1 = taglibMarks.elements();
          while (enum1.hasMoreElements()) {
              Mark mark = (Mark)enum1.nextElement();
              jspReader.reset(mark);
              jspReader.advance(JSP_TAGLIB_TAG.length());
              Hashtable attrs = jspReader.parseTagAttributes();
              p("taglib attributes are: " + attrs);
  
              JspUtil.checkAttributes("Taglib directive", attrs,
              ParserJsp.Directive.tagDvalidAttrs, mark);
              String uri = (String) attrs.get("uri");
              String prefix = (String) attrs.get("prefix");
              p("uri = " + uri + "   prefix = " + prefix);
              try {
                  TagLibraryInfo tli = new TagLibraryInfoImpl(ctxt, prefix, uri);
                  libraries.addTagLibrary(prefix, tli);
              } catch (Exception ex) {
  	        // @@@
                  ex.printStackTrace();
                  Object[] args = new Object[] { uri, ex.getMessage() };
                  throw new CompileException(mark,
                  Constants.getString("jsp.error.badtaglib",
                  args));
              }
          }
          
          // Build a JSP DTD on the fly that will include the custom tag
          // ibraries.
          
          ByteArrayOutputStream baos = new ByteArrayOutputStream();        
  	StringBuffer part1Buf = new StringBuffer();
  	StringBuffer bufXmlns = new StringBuffer();
  	StringBuffer bufTags = new StringBuffer();
  
          part1Buf.append(jspDtd_part1);
  
          Enumeration enum2 = libraries.getTagLibInfos();
          while (enum2.hasMoreElements()) {
              TagLibraryInfo tli = (TagLibraryInfo)enum2.nextElement();
  	    bufXmlns.append("\nxmlns:").append(tli.getPrefixString()).append(" CDATA #FIXED \"");
              bufXmlns.append(tli.getURI()).append("\"");
              TagInfo[] tags = tli.getTags();
              for (int i=0; i<tags.length; i++) {
  		TagInfo tag = tags[i];
                  part1Buf.append("\n|").append(tli.getPrefixString()).append(":").append(tag.getTagName());
                  part1Buf.append("\n");
                  bufTags.append("\n<!ELEMENT ");
                  bufTags.append(tli.getPrefixString());
                  bufTags.append(":");
  		bufTags.append(tag.getTagName());
  		bufTags.append(' ');
  		if (TagInfo.BODY_CONTENT_EMPTY.equalsIgnoreCase(tag.getBodyContent())) {
  		    bufTags.append("EMPTY>");
  		} else {
  		    bufTags.append("#PCDATA>");
  		}
  		TagAttributeInfo[] tais = tag.getAttributes();
  		if (tais.length > 0) {
  		    bufTags.append("\n<!ATTLIST ");
  		    bufTags.append(tli.getPrefixString());
  		    bufTags.append(":");
  		    bufTags.append("tag.getTagName()");
  		    bufTags.append(' ');		    
  		    for (int j=0; j<tais.length; j++) {
  			TagAttributeInfo tai = tais[j];
  			bufTags.append('\n'); //@@@ newline
  			bufTags.append(tai.getName());
  			if (tai.canBeRequestTime()) {
  			    bufTags.append(" PCDATA ");
  			} else {
  			    bufTags.append(" CDATA ");
  			}
  			if (tai.isRequired()) {
  			    bufTags.append("#REQUIRED");
  			} else {
  			    bufTags.append("#IMPLIED");
  			}
  		    }
  		}
  	    }
  	}
  
          part1Buf.append(jspDtd_part2);
          part1Buf.append(bufXmlns).append(">\n");
          part1Buf.append(bufTags);
  
          p("---------ZE DTD:-----------");
          p(part1Buf.toString());
  	p("ZE DTD:----END-------");
          
          CharArrayReader car = new CharArrayReader(part1Buf.toString().toCharArray());
          return new InputSource(car);
      }
      */
  
      //*********************************************************************
      // Utility methods
  
      /*
       * Resolve the name of the file and update global
       * 'parentFileName' so we can properly include
       * other jsp pages that are relative to this one.
       */
      private void resolveFileName(String inFileName) {
          String baseDir = (currentFileName == null)
  	    ? null
  	    : currentFileName.substring(
          0, currentFileName.lastIndexOf("/") + 1);
          //@@@ if no '/', would fail???
          boolean isAbsolute = inFileName.startsWith("/");
  
          if (baseDir == null || isAbsolute) {
              currentFileName = inFileName;
          } else {
              currentFileName = baseDir + inFileName;
          }
  	//p("resolveFileName() currentFileName: " + currentFileName);
      }
  
      private InputStreamReader getReader(File file, String encoding)
  	throws JasperException
      {
          InputStream in;
          InputStreamReader reader;
  
  	try {
  	    if (ctxt == null) {
  		in = new FileInputStream(file);
  		reader = new InputStreamReader(in, encoding);
  	    } else {
  		String fileName = ctxt.getRealPath(file.toString());
  		in = ctxt.getResourceAsStream(file.toString());
  		if (in == null) {
  		    throw new FileNotFoundException(fileName);
  		}
  		reader = new InputStreamReader(in, encoding);
  	    }
  	    return reader;
  	} catch (FileNotFoundException ex) {
  	    throw new JasperException(ex);
  	} catch (UnsupportedEncodingException ex) {
  	    throw new JasperException(ex);
  	}
      }
  
      /* NOT COMPILED
      private String getFileContent(String fileName) {
          InputStream inStream;
          StringBuffer sb = new StringBuffer();
          inStream = getClass().getResourceAsStream(fileName);
          InputStreamReader in = new InputStreamReader(inStream);
          char[] buf = new char[1024];
          try {
              for (int i=0 ; (i=in.read(buf)) != -1 ;) {
                    sb.append(buf, 0 , i);
              }
              return sb.toString().trim();
          } catch (IOException ex) {
              p("IOException on jsp12.dtd");
              ex.printStackTrace();
              return null;
          }
      }
      */
  
      private void p(String s) {
          System.out.println("[ParserController] " + s);
      }
  
      private void p(String s, Throwable ex) {
          p(s);
          p(ex.getMessage());
          ex.printStackTrace();
      }
  }
  
  
  
  1.1                  jakarta-tomcat-4.0/jasper/src/share/org/apache/jasper/compiler/ParserXJspSax.java
  
  Index: ParserXJspSax.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999 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", "Tomcat", 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/>.
   *
   */
  
  package org.apache.jasper.compiler;
  
  import java.io.*;
  import java.lang.reflect.Method;
  import java.lang.reflect.InvocationTargetException;
  import java.net.MalformedURLException;
  import java.net.URL;
  import java.util.HashMap;
  import java.util.List;
  import java.util.LinkedList;
  import java.util.Stack;
  
  import org.xml.sax.Attributes;
  import org.xml.sax.DTDHandler;
  import org.xml.sax.EntityResolver;
  import org.xml.sax.ErrorHandler;
  import org.xml.sax.InputSource;
  import org.xml.sax.SAXException;
  import org.xml.sax.SAXNotRecognizedException;
  import org.xml.sax.SAXNotSupportedException;
  import org.xml.sax.SAXParseException;
  import org.xml.sax.XMLReader;
  import org.xml.sax.ext.LexicalHandler;
  import org.xml.sax.helpers.DefaultHandler;
  import org.xml.sax.helpers.XMLReaderFactory;
  
  import org.apache.jasper.JasperException;
  import org.apache.jasper.Constants;
  import org.apache.jasper.logging.Logger;
  
  /**
   * SAX Parser to handle XJsp syntax.
   * (JSP page as XML document).
   *
   * Any SAX2.0 parser should do.
   *
   * @author Pierre Delisle
   */
  public class ParserXJspSax {
  
      /*
       * The SAX 'driver' class to be used for parsing.
       */
      private String sax2DriverClassName;
  
      /* 
       * InputSource for XML document
       */
      private InputSource is;
  
      /*
       * File path that's used in parsing errors
       */
      private String filePath;
  
      /*
       * The 'parsing event handler' that does the real handling
       * of parse events (shared by both jsp and xjsp parsers)
       */
      private ParseEventListener jspHandler;
  
      /*
       * validation mode
       */
      static final private boolean validate = false;
  
      /*
       * Couple possible names for lexical reporting property name :-(
       */
      static final String[] lexicalHandlerPropNames = {
  	"http://xml.org/sax/handlers/LexicalHandler",
  	"http://xml.org/sax/properties/lexical-handler",
      };
  
      //*********************************************************************
      // Constructor
  
      public ParserXJspSax(String filePath,
  			 InputStreamReader reader, 
  			 ParseEventListener jspHandler,
  			 String sax2DriverClassName) 
      {
  	this.filePath = filePath;
  	this.is = new InputSource(reader);
  	this.jspHandler = jspHandler;
  	this.sax2DriverClassName = sax2DriverClassName;
      }
      
      //*********************************************************************
      // Parse
      
      public void parse() throws JasperException {
          try {
              XMLReader parser =
                  XMLReaderFactory.createXMLReader(sax2DriverClassName);
              ParserXJspSaxHandler handler =
                  new ParserXJspSaxHandler(filePath, jspHandler);
  	    
              parser.setContentHandler(handler);
  	    parser.setEntityResolver(handler);
  	    parser.setDTDHandler(handler);
  	    parser.setErrorHandler(handler);
  
  	    // set properties: lexical handler
  	    for (int i=0; i<lexicalHandlerPropNames.length; i++) {
  		if (setSaxProperty(parser, handler, 
  				   lexicalHandlerPropNames[i])) break;
  	    }
  	    
              // Set features: validation and namespaces
              try {
                  parser.setFeature(
                      "http://xml.org/sax/features/validation", validate);
                  parser.setFeature(
                      "http://xml.org/sax/features/namespaces", false);
                  parser.setFeature(
                      "http://xml.org/sax/features/namespace-prefixes", true);
              } catch (SAXNotSupportedException ex) {
  		throw new JasperException(
  		    Constants.getString("jsp.parser.sax.featurenotsupported",
  					new Object[] {ex.getMessage()}));
              } catch (SAXNotRecognizedException ex) {
  		throw new JasperException(
  		    Constants.getString("jsp.parser.sax.featurenotrecognized",
  					new Object[] {ex.getMessage()}));
  	    }
  
              parser.parse(is);
  
          } catch (IOException ex) {
  	    throw new JasperException(ex);
          } catch (SAXParseException ex) {
  	    Mark mark = 
  		new Mark(filePath, ex.getLineNumber(), ex.getColumnNumber());
  	    String reason;
  	    if (ex.getException() != null) {
  		reason = ex.getException().getMessage();
  	    } else {
  		reason = ex.getMessage();
  	    }
  	    throw new ParseException(mark, reason);
          } catch (SAXException ex) {
  	    Exception ex2 = ex;
  	    if (ex.getException() != null) ex2 = ex.getException();
  	    System.out.println("**** ICI ***");
  	    System.out.println(ex2.getMessage());
  	    System.out.println(ex2.getClass().getName());
  	    throw new JasperException(ex2);
          }
      }
  
      //*********************************************************************
      // Utility methods
  
      private boolean setSaxProperty(XMLReader parser, 
  				   DefaultHandler handler,
  				   String propName) 
      {
  	try {
  	    parser.setProperty(propName, handler);
  	    return true;
  	} catch (SAXNotSupportedException ex) {
  	    Constants.message("jsp.parser.sax.propertynotsupported",
  			      new Object[] {ex.getMessage()},
  			      Logger.WARNING);
  	    return false;
  	} catch (SAXNotRecognizedException ex) {
  	    Constants.message("jsp.parser.sax.propertynotrecognized",
  			      new Object[] {ex.getMessage()},
  			      Logger.WARNING);
  	    return false;
  	}
      }
  
      /* NOT COMPILED
      private void printException(SAXParseException ex) {
  	System.out.println("SAXParseException");
  	System.out.println("Public ID: " + ex.getPublicId());
  	System.out.println("System ID: " + ex.getSystemId());
  	System.out.println("line " + ex.getLineNumber() + 
  			   ", col " + ex.getColumnNumber());
  	ex.printStackTrace(System.out);
      }
  
      void p(String s) {
  	System.out.println("[ParserXJspSax] " + s);
      }
      */
  }
  
  
  
  
  1.1                  jakarta-tomcat-4.0/jasper/src/share/org/apache/jasper/compiler/ParserXJspSaxHandler.java
  
  Index: ParserXJspSaxHandler.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999 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", "Tomcat", 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/>.
   *
   */ 
  
  package org.apache.jasper.compiler;
  
  //@@@ have specific imports
  import java.io.*;
  import java.net.*;
  import java.util.*;
  
  import javax.servlet.jsp.tagext.TagLibraryInfo;
  import javax.servlet.jsp.tagext.TagInfo;
  
  import org.xml.sax.*;
  import org.xml.sax.ext.*;
  import org.xml.sax.helpers.*;
  
  import org.apache.jasper.*;
  
  /**
   * The SAX (2.0) parser event handler.
   *
   * @author Pierre Delisle
   *
   * @@@ TODO
   * - make sure validation is in sync with Parser (jsp syntax)
   * - fix the node.validate()
   */
  class ParserXJspSaxHandler 
      extends DefaultHandler implements LexicalHandler 
  {
      /*
       * JSP handler on which we piggyback to generate parse data
       */
      private ParseEventListener jspHandler;
  
      /*
       * Tells whether we are in a DTD
       */
      private boolean inDtd;
  
      /*
       * Tells whether we are in CDATA
       */
      private boolean inCdata;
  
      /*
       * Tells whether we are in Entity
       */
      private boolean inEntity;
  
      /*
       * parsing stack
       */
      private Stack stack;
  
      /*
       * Locator for sax parse events
       */
      private Locator locator;
  
      /*
       * File path that's used in parsing errors
       */
      private String filePath;
  
      //*********************************************************************
      // Constructor
  
      public ParserXJspSaxHandler(String filePath, 
  				ParseEventListener jspHandler) 
  	throws JasperException 
      {
  	this.filePath = filePath;
          this.jspHandler = jspHandler;
  
          stack = new Stack();
          inEntity = false;
          inDtd = false;
          inCdata = false;
      }
  
      //*********************************************************************
      // Interface ContentHandler methods
  
      public void setDocumentLocator(Locator locator) {
  	//p("\n*** setDocumentLocator");
  	this.locator = locator;
      }
  
      public void startDocument() throws SAXException {
  	//p("\n*** startDocument");
      }
  
      public void endDocument() throws SAXException {
  	//p("\n*** endDocument");
      }
  
      public void startPrefixMapping(String prefix, String uri) 
  	throws SAXException 
      {
  	//p("\n*** startPrefixMapping");
  	//p("prefix = " + prefix);
  	//p("uri = " + uri);
  	//p("BEWARE: Nothing done for this content.");
      }
  
      public void endPrefixMapping(String prefix)
  	throws SAXException 
      {
  	//p("\n*** endPrefixMapping");
  	//p("prefix = " + prefix);
  	//p("BEWARE: Nothing done for this content.");
      }
  
      public void characters(char[] ch, int start, int length)
          throws SAXException
      {
  	// @@@ have startMark computed from stopMark
  	Mark stopMark = new Mark(filePath, locator.getLineNumber(),
  				 locator.getColumnNumber());
  
  	//p("\n*** characters");
  	//printLocation();
  	//p("|" + String.valueOf(ch, start, length) + "|");
  
  	Node node = (Node)stack.peek();
  	if (node.isRoot()) {
  	    // template data in <jsp:root>.
  	    //p("these chars are added directly in jsp:root");
  	    try {
  		jspHandler.handleCharData(stopMark, stopMark,
  					  makeCharArray(ch, start, length)); 
  	    } catch (Exception ex) {
  		throw new SAXException(ex);
  	    }
  	} else {
  	    // characters added to the body content of the element
  	    // at the top of the stack
  	    //p("these chars are added to node " + node.rawName + " in stack");
  	    node.addText(ch, start, length);
  	}
      }
  
      public void ignorableWhitespace(char[] ch,
  				    int start,
  				    int length)
  	throws SAXException
      {
  	//p("\n*** ignorableWhitespace");
  	//printLocation();
  	//p("|" + String.valueOf(ch, start, length) + "|");
  	//p("BEWARE: Nothing done for this content.");
      }
  
      public void skippedEntity(String name)
  	throws SAXException
      {
  	//p("\n*** skippedEntity");
  	//p("name = " + name);
  	//p("BEWARE: Nothing done for this content.");
      }
  
  
      public void processingInstruction(String target, String data)
          throws SAXException 
      {
  	//p("\n*** processingInstruction");
  	//p("target = " + target);
  	//p("data = " + data);
  	//p("BEWARE: Nothing done for this content.");
      }
      
      public void startElement(String namespaceURI, String localName,
                               String rawName, Attributes attrs) 
  	throws SAXException 
      {
  	//p("\n*** startElement: " + rawName);
  	//printLocation();
  	//p("namespaceURI: " + namespaceURI);
  	//p("localName: " + localName);
  	//p("rawName: " + rawName);
  	//p("attrs: " + attrs.toString());
  
  	String name = rawName;
  	Mark start = new Mark(filePath, locator.getLineNumber(),
  			      locator.getColumnNumber());
  	Node node = new Node(rawName, new AttributesImpl(attrs), start);
  
  	if (name.equals("jsp:params")) {
  	    // don't have it pushed on the stack...
  	    // this is a noop...
  	    return;
  	}
  
          // Simply push the new 'node' on the stack, and it will be
  	// processed on the 'endElement' event.
  	stack.push(node);
  
  	// Those elements allow more 'parsed elements' in them.
  	// They are therefore handled both at the start and at the
  	// end.
  	try {
  	    if (name.equals("jsp:root")) {
  		jspHandler.handleRootBegin(attrsToHashtable(node.attrs));
  	    } else if (name.equals("jsp:useBean")) {
  		jspHandler.handleBean(
  				      node.start, node.start, attrsToHashtable(node.attrs));
  	    } else if (name.length()<4 || !name.substring(0,4).equals("jsp:")) {
  		// custom tag
  		processCustomTagBegin();
  	    }
  	} catch (Exception ex) {
  	    throw new SAXException(ex);
  	}
      }
  
      public void endElement(String namespaceURI, String localName,
                             String rawName) 
  	throws SAXException
      {
  	//p("\n*** endElement: " + rawName);
  	//printLocation();
  	//p("namespaceURI: " + namespaceURI);
  	//p("localName: " + localName);
  	//p("rawName: " + rawName);
  	//p("attrs: " + attrs.toString());
  
  	Mark stop = new Mark(filePath, locator.getLineNumber(),
  			     locator.getColumnNumber());
  
  	String name = rawName;
  	Node node = (Node)stack.pop();
  	//p(node);
  
  	try {
  	    if (name.equals("jsp:root")) {
  		jspHandler.handleRootEnd();
  	    } else if (name.equals("jsp:directive.include")) {
  		node.validate(true, false);
  		jspHandler.handleDirective(
  					   "include", node.start, stop, 
  					   attrsToHashtable(node.attrs));
  	    } else if (name.equals("jsp:directive.page")) {
  		node.validate(true, false);
  		jspHandler.handleDirective(
  					   "page", node.start, stop,
  					   attrsToHashtable(node.attrs));
  	    } else if (name.equals("jsp:directive.taglib")) {
  		node.validate(true, false);
  		jspHandler.handleDirective(
  					   "taglib", node.start, stop,
  					   attrsToHashtable(node.attrs));
  	    } else if (name.equals("jsp:declaration")) {
  		node.validate(false, true);
  		jspHandler.handleDeclaration(
  					     node.start, stop, null, node.getText());
  	    } else if (name.equals("jsp:expression")) {
  		node.validate(false, true);
  		jspHandler.handleExpression(
  					    node.start, stop, null, node.getText());
  	    } else if (name.equals("jsp:scriptlet")) {
  		node.validate(false, true);
  		jspHandler.handleScriptlet(
  					    node.start, stop, null, node.getText());
  	    } else if (name.equals("jsp:param")) {
  		node.validate(true, false);
  		// push the node back, it will be needed by the container node
  		stack.push(node);
  	    } else if (name.equals("jsp:fallback")) {
  		node.validate(false, true);
  		// push the node back, it will be needed by the container node
  		stack.push(node);
  	    } else if (name.equals("jsp:include")) {
  		Hashtable params = null;
  		if (!node.rawName.equals("jsp:include")) {
  		    // handle params
  		    stack.push(node);
  		    params = popParams();
  		    node = (Node)stack.pop();
  		}
  		node.validate(true, true); //@@@
  		jspHandler.handleInclude(
                      node.start, stop, attrsToHashtable(node.attrs), params);
  	    } else if (name.equals("jsp:forward")) {
  		Hashtable params = null;
  		if (!node.rawName.equals("jsp:forward")) {
  		    // handle params
  		    stack.push(node);
  		    params = popParams();
  		    node = (Node)stack.pop();
  		}
  		node.validate(true, true);
  		jspHandler.handleForward(
  					 node.start, stop, attrsToHashtable(node.attrs), params);
  	    } else if (name.equals("jsp:useBean")) {
  		node.validate(true, true); // @@@
  		jspHandler.handleBeanEnd(
  		    node.start, stop,  attrsToHashtable(node.attrs));
  	    } else if (name.equals("jsp:getProperty")) {
  		node.validate(true, true); // @@@
  		jspHandler.handleGetProperty(
  		    node.start, stop,  attrsToHashtable(node.attrs));
  	    } else if (name.equals("jsp:setProperty")) {
  		node.validate(true, true); // @@@
  		jspHandler.handleSetProperty(
  		    node.start, stop,  attrsToHashtable(node.attrs));
  	    } else if (name.equals("jsp:plugin")) {
  		//@@@ test jsp parser to see if fallback can come first?
  		Hashtable params = null;
  		String fallback = null;
  		if (node.rawName.equals("jsp:fallback")) {
  		    // handle fallback
  		    fallback = String.valueOf(node.getText());
  		    node = (Node)stack.pop();
  		}
  		if (!node.rawName.equals("jsp:plugin")) {
  		    // handle params
  		    stack.push(node);
  		    params = popParams();
  		    node = (Node)stack.pop();
  		}
  		node.validate(true, true);
  		//p(node);
  		jspHandler.handlePlugin(
  		    node.start, stop, attrsToHashtable(node.attrs), params, fallback);
  	    } else {
  		// Ought to be a custom tag
  		//p("should be nodetag");
  		//p(node);
  		//p("class is: " + node.getClass().getName());
  		processCustomTagEnd((NodeTag)node, stop);
  	    }
  	} catch (Exception ex) {
  	    ex.printStackTrace();
  	    throw new SAXException(ex);
  	}
      }
  
      private void processCustomTagBegin() 
  	throws ParseException, JasperException 
      {
  	Node node = (Node)stack.pop();
  	String tag = node.rawName;
  	int i = tag.indexOf(':');
  	if (i == -1) throw new ParseException("unknown tag: " + tag);
  	
  	String prefix = tag.substring(0, i);
  	String shortTagName = tag.substring(i+1);
  	
  	TagLibraries libraries = jspHandler.getTagLibraries();
  	
  	if (!libraries.isUserDefinedTag(prefix, shortTagName)) {
  	    throw new ParseException(node.start, "invalid tag: " + node.rawName);
  	}
  
  	if (shortTagName == null) {
  	    throw new ParseException(node.start, "Nothing after the :");
  	}
              
  	TagLibraryInfo tli = libraries.getTagLibInfo(prefix);
  	TagInfo ti = tli.getTag(shortTagName);
              
  	if (ti == null) {
  	    throw new ParseException(node.start, "Unable to locate TagInfo for "+tag);
  	}
  	node = new NodeTag(node, prefix, shortTagName, tli, ti);
  	stack.push(node);
  	jspHandler.handleTagBegin(node.start, node.start, 
  				  attrsToHashtable(node.attrs), 
  				  prefix, shortTagName, tli, ti);
      }
      
      private void processCustomTagEnd(NodeTag node, Mark stop) 
  	throws ParseException, JasperException {
  	String bc = node.ti.getBodyContent();
  	if (node.getText() != null && bc.equalsIgnoreCase(TagInfo.BODY_CONTENT_EMPTY)) {
  	    throw new ParseException(node.start, "Body is supposed to be empty for "
  				     + node.rawName);
  	}
  	jspHandler.handleTagEnd(node.start, stop, node.prefix, 
  				node.shortTagName, attrsToHashtable(node.attrs), 
  				node.tli, node.ti);
      }
  
      //*********************************************************************
      // Interface LexicalHandler methods
  
      public void startDTD(String name, String publicId, String systemId)
          throws SAXException 
      {
  	//p("\n*** startDTD");
  	//p("BEWARE: Nothing done for this content.");
      }
  
      public void endDTD() throws SAXException {
          inDtd = false;
  	//p("\n*** endDTD");
  	//p("BEWARE: Nothing done for this content.");
      }
  
      public void startEntity(String name)
          throws SAXException 
      {
  	//p("\n*** startEntity");
  	//p("name: " + name);
  	//p("BEWARE: Nothing done for this content.");
      }
  
      public void endEntity(String name)
          throws SAXException 
      {
  	//p("\n*** endEntity");
  	//p("name: " + name);
  	//p("BEWARE: Nothing done for this content.");
      }
  
      public void startCDATA() throws SAXException {
  	//p("\n*** startCDATA");
          inCdata = true;
      }
  
      public void endCDATA() throws SAXException {
  	//p("\n*** endCDATA");
          inCdata = false;
      }
  
      public void comment(char[] ch, int start, int length)
          throws SAXException 
      {
  	//p("\n*** comment");
  	//printLocation();
  	//p("|" + String.valueOf(ch, start, length) + "|");
  	//p("BEWARE: Nothing done for this content.");
  
  	/*
          String commentText = new String(ch, start, end);
          if ((!inDtd) && (!commentText.equals(""))) {
  	    if (stack.empty()) {
  		document.addComment(
  				    new Comment(commentText));
  	    } else {
  		((Element)stack.peek()).addChild(
  						 new Comment(commentText));
  	    }
          }
  	*/
      }
  
      //*********************************************************************
      // Interface ErrorHandler methods
  
      public void fatalError(SAXParseException ex)
          throws SAXException 
      {
  	printException("FATAL", ex);
          throw ex;
      }
  
      public void error(SAXParseException ex)
          throws SAXException 
      {
  	printException("ERROR", ex);
          throw ex;
      }
  
      public void warning(SAXParseException ex)
  	throws SAXException 
      {
  	printException("WARNING", ex);
      }
  
      //*********************************************************************
      // DTD Handler
  
      public void notationDecl(java.lang.String name,
  			     java.lang.String publicId,
  			     java.lang.String systemId)
  	throws SAXException
      {
  	//p("\n*** notationDecl");
  	//p("name = " + name);
  	//p("publicId = " + publicId);
  	//p("systemId = " + systemId);
  	//p("BEWARE: Nothing done for this content.");
      }
  
      public void unparsedEntityDecl(java.lang.String name,
  				   java.lang.String publicId,
  				   java.lang.String systemId,
  				   java.lang.String notationName)
  	throws SAXException
      {
  	//p("\n*** unparsedEntityDecl");
  	//p("name = " + name);
  	//p("publicId = " + publicId);
  	//p("systemId = " + systemId);
  	//p("notationName = " + notationName);
  	//p("BEWARE: Nothing done for this content.");
      }
  
      //*********************************************************************
      // EntityResolver
  
      static final String JSP_PUBLIC_ID1 = 
          "-//Sun Microsystems Inc.//DTD JavaServer Pages Version 1.1//EN";
      static final String JSP_PUBLIC_ID2 = 
          "-//Sun Microsystems Inc.//DTD JavaServer Pages Version 1.2//EN";
      static final String JSP_SYSTEM_ID = 
          "http://java.sun.com/products/jsp/dtd/jspcore_1_2.dtd";
      static final String JSP_SYSTEM_ID_INTERNAL = 
          "/org/apache/jasper/resources/jsp12.dtd";
      
      public InputSource resolveEntity(String publicId, String systemId)
  	throws SAXException 
      {
          //p("\n*** resolveEntity");
          //p("publicId: " + publicId);
          //p("systemId: " + systemId);
          
          if (publicId.equals(JSP_PUBLIC_ID1) ||
          publicId.equals(JSP_PUBLIC_ID2)) {
              InputStream is =
              this.getClass().getResourceAsStream(JSP_SYSTEM_ID_INTERNAL);
              //p("attempt to returning " + JSP_SYSTEM_ID_INTERNAL);
              InputSource isrc = new InputSource(is);
              //p("success on returning " + JSP_SYSTEM_ID_INTERNAL);
              return isrc;
          } else {
              System.out.println("ERROR: publicID does not match: " + publicId);
              return null;
          }
      }
  
      //*********************************************************************
      // class Node
  
      private class Node {
  	String rawName;
  	Attributes attrs;
  	Mark start;
  
  	boolean isRoot;
  	StringBuffer text = null;
  
  	Node(Node node) {
  	    this(node.rawName, node.attrs, node.start);
  	}
  
  	Node(String rawName, Attributes attrs, Mark start) {
  	    this.rawName = rawName;
  	    this.attrs = attrs;
  	    this.start = start;
  	    isRoot = rawName.equals("jsp:root");
  	}
  
  	void addText(char[] chars, int start, int length) {
  	    if (text == null) text = new StringBuffer();
  	    text.append(chars, start, length);
  	}
  
          char[] getText() {
              return text == null 
  	    ? null
  	    : text.toString().toCharArray();
          }
  
  	boolean isRoot() {
  	    return isRoot;
  	}
  
  	void validate(boolean canHaveAttributes,
  		      boolean canHaveText) 
  	    throws SAXException 
  	{
  	    if (!canHaveAttributes && attrs.getLength()!=0) {
  		throw new SAXException("VALIDATE ERROR: " +
  				       rawName + " cannot have attributes.");
  	    }
  	    if (!canHaveText && text != null) {
  		throw new SAXException("VALIDATE ERROR: " +
  				       rawName + " cannot have text.");
  	    }
  	}
  	public void display() {
  	    p("NODE: " + rawName);
  	    for (int i=0; i<attrs.getLength(); i++) {
  		p("attrs[" + i + "] " + attrs.getQName(i) + " = " +
  		  attrs.getValue(i));
  	    }
  	}
      }
  	
  
      //*********************************************************************
      // class NodeTag
  
      private class NodeTag extends Node {
  	String prefix;
  	String shortTagName;
  	TagLibraryInfo tli;
  	TagInfo ti;
  
  	NodeTag(Node node, String prefix, String shortTagName, 
  		TagLibraryInfo tli, TagInfo ti)
  	{
  	    super(node);
  	    this.prefix = prefix;
  	    this.shortTagName = shortTagName;
  	    this.tli = tli;
  	    this.ti = ti;
  	}
      }
  	
      //*********************************************************************
      // Utility methods
  
      /**
       * <p>
       *  Trim the right spacing off of a <code>String</code>.
       * </p>
       *
       * @param orig <code>String</code> to rtrim.
       * @return <code>String</code> - orig with no right spaces
       */
      private String rtrim(String orig) {
          int len = orig.length();
          int st = 0;
          int off = 0;
          char[] val = orig.toCharArray();
  
          while ((st < len) && (val[off + len - 1] <= ' ')) {
              len--;
          }
          return ((st > 0) || (len < orig.length())) 
  	    ? orig.substring(st, len) : orig;
      }
  
      /**
       * <p>
       *  Trim the left spacing off of a <code>String</code>.
       * </p>
       *
       * @param orig <code>String</code> to rtrim.
       * @return <code>String</code> - orig with no left spaces
       */
      private String ltrim(String orig) {
          int len = orig.length();
          int st = 0;
          int off = 0;
          char[] val = orig.toCharArray();
  
          while ((st < len) && (val[off + st] <= ' ')) {
              st++;
          }
          return ((st > 0) || (len < orig.length())) 
  	    ? orig.substring(st, len) : orig;
      }
  
      private void printException(String level, SAXParseException ex) {
  	p("\n*** SAXParseException: " + level);
  	p("Public ID: " + ex.getPublicId());
  	p("System ID: " + ex.getSystemId());
  	p("line " + ex.getLineNumber() + 
  	  ", col " + ex.getColumnNumber());
  	ex.printStackTrace(System.out);
      }
  
      private Hashtable attrsToHashtable(Attributes attrs) {
          int len = attrs.getLength();
          Hashtable table = new Hashtable(len);
          for (int i=0; i<len; i++) {
              table.put(attrs.getQName(i), attrs.getValue(i));
          }
          return table;
      }
      
      private char[] makeCharArray(char[] buf, int offset, int len) {
          char[] ret = new char[len];
          for (int i=0,j=offset; i<len; i++,j++) {
              ret[i] = buf[j];
          }
          return ret;
      }
  
      private Hashtable popParams() throws ParseException {
  	// @@@ code duplicated with JspParseEventListener
          Hashtable params = new Hashtable();
  	Node node;
  	while ((node = (Node)stack.peek()).rawName.equals("jsp:param")) {
  	    node = (Node)stack.pop();
  	    //p("popped this param node");
  	    //p(node);
              String name = node.attrs.getValue("name");
              String value = node.attrs.getValue("value");
              if (name == null) {
                  throw new ParseException(node.start, Constants.getString("jsp.error.param.noname"));
              }
              if (value == null) {
                  throw new ParseException(node.start, Constants.getString("jsp.error.param.novalue"));
              }
              // Put that new binding into the params hashtable:
              String oldval[] = (String[])params.get(name);
              if (oldval == null) {
                  String newval[] = new String[1];
                  newval[0] = value;
                  params.put(name, newval);
              } else {
                  String newval[] = new String[oldval.length+1];
                  System.arraycopy(oldval, 0, newval, 0, oldval.length);
                  newval[oldval.length] = value;
                  params.put(name, newval);
              }
          }
  	return params;
      }
  
      private void printLocation() {
  	p("--- (" + locator.getSystemId() + ", " +
  	  locator.getPublicId() + ") (" +
  	  locator.getLineNumber() + ", " +
  	  locator.getColumnNumber() + ")");
      }
  
      void p(String s) {
  	//System.out.println("[ParserXJspSaxHandler] " + s);
  	System.out.println(s);
      }
  
      void p(Node node) {
  	node.display();
      }
  }
  
  
  
  
  
  
  1.1                  jakarta-tomcat-4.0/jasper/src/share/org/apache/jasper/compiler/XmlOutputter.java
  
  Index: XmlOutputter.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-tomcat-4.0/jasper/src/share/org/apache/jasper/compiler/XmlOutputter.java,v 1.1 2000/09/19 19:19:21 pierred Exp $
   * $Revision: 1.1 $
   * $Date: 2000/09/19 19:19:21 $
   *
   * ====================================================================
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999 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", "Tomcat", 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/>.
   *
   */
  
  package org.apache.jasper.compiler;
  
  import java.util.Hashtable;
  import java.util.Enumeration;
  import java.io.InputStream;
  import java.io.ByteArrayInputStream;
  
  import javax.servlet.jsp.tagext.PageInfo;
  
  /**
   * Class responsible for generating the XML stream representing
   * the JSP translation unit being compiled.
   *
   * @author Pierre Delisle
   */
  public class XmlOutputter {
  
      /* 
       * XML data is appended to the stream as we parse and process
       * the JSP translation unit
       */
      private StringBuffer sb;
  
      /* 
       * The root attributes of all the <jsp:root> tags encountered
       * in the translation unit 
       */
      private Hashtable rootAttrs;
      
      //*********************************************************************
      // Constructor
  
      XmlOutputter() {
  	sb = new StringBuffer();
  	rootAttrs = new Hashtable();
      }
  
      //*********************************************************************
      // update methods to the XML stream
  
      /**
       * A translation unit (JSP source file and any files included via 
       * the include directive) may encounter multiple <jsp:root>
       * tags. This method cumulates all attributes for the
       * <jsp:root> tag.
       */
      void addRootAttrs(Hashtable attrs) {
          Enumeration enum = attrs.keys();
          while (enum.hasMoreElements()) {
              Object name = enum.nextElement();
              Object value = attrs.get(name);
              rootAttrs.put(name, value);
          }
      }
      
      /**
       * Append the cdata to the XML stream.
       */
      void append(char[] text) {
          sb.append("<![CDATA[\n");
          sb.append(text);
          sb.append("]]>\n");
      }
      
      /**
       * Append the start tag along with its attributes to the
       * XML stream.
       */
      void append(String tag, Hashtable attrs) {
          append(tag, attrs, sb);
      }
      
      /**
       * Append the start tag along with its attributes to the
       * specific XML stream. 
       * [StringBuffer is an argument so we can reuse the method
       * to generate the "header" in a different stream. The header
       * can only be generated once we've processed all parts
       * of the translation unit]
       */
      void append(String tag, Hashtable attrs, StringBuffer buff) {
          buff.append("<").append(tag);
          if (attrs == null) {
              buff.append(">");
          } else {
              buff.append("\n");
              Enumeration enum = attrs.keys();
              while (enum.hasMoreElements()) {
                  String name = (String)enum.nextElement();
                  String value = (String)attrs.get(name);
                  buff.append("  ").append(name).append("=\"");
  		buff.append(value).append("\"\n");
              }
              buff.append(">\n");
          }
      }
  
      /**
       * Append the start tag along with its attributes and body
       * to the XML stream.
       */
      void append(String tag, Hashtable attrs, char[] text) {
          append(tag, attrs);
          append(text);
          sb.append("</").append(tag).append(">\n");
      }
      
      /**
       * Append the end tag to the xml stream.
       */
      void append(String tag) {
          sb.append("</").append(tag).append(">");
      }
  
      //*********************************************************************
      // Outputting the XML stream
  
      private static final String PROLOG =
  	"<!DOCTYPE jsp:root\n  PUBLIC \"-//Sun Microsystems Inc.//DTD JavaServer Pages Version 1.1//EN\"\n  \"http://java.sun.com/products/jsp/dtd/jspcore_1_2.dtd\">\n";
  
      PageInfo getPageInfo() {
  	StringBuffer buff = new StringBuffer();
  
          buff.append(PROLOG);
          append("jsp:root", rootAttrs, buff);
  	buff.append(sb.toString());
  	InputStream is = 
  	    new ByteArrayInputStream(buff.toString().getBytes());
  	PageInfo pageInfo = new PageInfoImpl(is);
          return pageInfo;
      }
  }    
  
  
  
  1.1                  jakarta-tomcat-4.0/jasper/src/share/org/apache/jasper/compiler/PageInfoImpl.java
  
  Index: PageInfoImpl.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-tomcat-4.0/jasper/src/share/org/apache/jasper/compiler/PageInfoImpl.java,v 1.1 2000/09/19 19:19:21 pierred Exp $
   * $Revision: 1.1 $
   * $Date: 2000/09/19 19:19:21 $
   *
   * ====================================================================
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999 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", "Tomcat", 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/>.
   *
   */
  
  package org.apache.jasper.compiler;
  
  import java.io.InputStream;
  
  import javax.servlet.jsp.tagext.PageInfo;
  
  /**
   * Implementation of abstract class javax.servlet.jsp.tagext.PageInfo.
   *
   * @author Pierre Delisle
   */
  public class PageInfoImpl extends PageInfo {
      /**
       * The XML input stream representing the JSP translation unit.
       */
      private InputStream is;
  
      //*********************************************************************
      // Constructor
  
      public PageInfoImpl(InputStream is) {
  	this.is = is;
      }
  
      //*********************************************************************
      // PageInfo methods
  
      public InputStream getInputStream() {
  	return is;
      }
  }