You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by Petr Jiricka <pe...@netbeans.com> on 2000/04/17 20:39:25 UTC

Proposal: APIs for parsing JSPs

Hello,

this is a proposal which separates the "core" of the JSP compiler - the
parser. This should make it possible to do the following:
- Create an arbitrary implementation of ParseEventListener and use it with
the parser for other uses than generating the servlet code
- Parse JSPs which are available as character streams (Readers) as well as
byte stream-based JSPs
- Plug in an arbitrary XML parser to parse web.xml and *.tld files, use
JAXP, or use a completely different implementation which uses the parser
indirectly, such as XML data binding (JSR 31) or IBM BeanMaker

The separation is reflected by a proposed package change for the parser
classes to org.apache.jasper.parser.

The only other classes from the Tomcat source base which the parser depends
on are:
org.apache.tomcat.logging.Logger
org.apache.jasper.Constants
org.apache.jasper.JasperException

The idea is that the JSP compiler will be divided into several parts:
1) The basic parsing interfaces. Attached. I am also including the diffs
against the original compiler classes.
2) The default implementation of the interfaces. This implementation will
use the Sun XML parser, or it might even be parser independent and use DOM
only. I haven't implemented this part yet.
3) The JSP compiler and the two basic context implementation - embedded and
command line. The compiler will be an extension of the parser.

The core interface of the parser is JspParsingContext. The context is meant
to be implemented by individual parsers. Some methods, in particular the
TagLibraryInfo construction method, will be quite difficult to implement, so
a default implementation will be have to be provided. JspCompilationContext
will extend the JspParsingContext interface, and will define the additional
methods not necessary for parsing. 
The roles of JspParsingContext are the following:
- provide a hook for custom implementations of information from web.xml and
*.tld
- provide InputStreams for resources in the context
- optionally provide readers for JSPs. This feature is similar for example
to a similar feature in org.xml.sax.InputSource. It allows for example to
parse JSPs which are available as Swing documents

Another set of changes affects JspReader: now it also handles resolving the
tag library URL from information supplied by JspParsingContext. A possible
issue is handling the relative URIs relatively to the current context, which
was previously handled by JspCompilationContext.resolveRelativeUri(). I
don't understand all the issues about this, see the comment next to
JspParsingContext.resolveRelativeUri() - this method is commented out. The
other big change in this class is acquiring the stream or reader for a file
from the parsing context. This is possibly also affected by the relative URI
issue. I would welcome if someone could tell me more about this. Another
problem was that apparently servletcontext.getResourceAsStream() does not
work correctly in some cases. Does anyone know which bug number this is ?
I also implemented the change from my previous e-mail, affecting JspReader
and Mark (bug 100). A side-effect of these changes is that the context used
in the reader may no longer be null, which should not be a big problem.

Another important change in the parser is that the parser does not require a
tag library to be supplied as an instance of TagLibraryInfoImpl, it can be
an arbitrary implementation TagLibraryInfo. This is reflected in that
caching (TagCache) has been moved from tagLibraryInfoImpl to TagLibraries.
The implementation of TagBeginGenerator and TagEndGenerator will have to be
updated accordingly.

The last big change is the implementation of some parser events directly by
the parser. I believe that in order to correctly parse the JSP file, taglib
and include directives must be handled correctly. So right now the parser
relies on the implementation of ParseEventListener and its handling of
taglib and include directives. So the correct implementation of this
handling has been moved to Parser. If this is seen problematic, we can think
about making this resolving optional in the parser. So the user of the
Parser would be able to set whether taglib and include directives should be
"always resolved" / "resolution attempted" / "resolution not attempted".

Finally, a new class ParseUtil contains some utility methods copied from
JspUtil.

The biggest part of the default implementation of JspParsingContext will be
reading the TagLibraryInfo from the XML file. Most of the code from
TagLibraryInfoImpl can be used for this. However, currently
TagLibraryInfoImpl depends on some specific pieces of the JSP classloading
mechanism. This dependency appears in the part which handler tag libraries
packaged in .jar files, which I believe is not mandated by the spec. The
comments in the code also suggest that this code should be removed in the
future. Can I ask what's the current thinking about this ?

Basically I think that the proposed implementation of the JSP parser could
be more useful and cleaner than the current implementation, and that the
existing compiler could be quite easily rewritten to use the new
implementation.

I will welcome any comments on this.

Thanks
Petr


W:\Development\src_jakarta\jakarta-tomcat\jakarta-tomcat\src\share\org\apach
e\jasper\compiler>cvs diff -u *.java
Index: CoreElement.java
===================================================================
RCS file:
/home/cvspublic/jakarta-tomcat/src/share/org/apache/jasper/compiler/CoreElem
ent.java,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 CoreElement.java
--- CoreElement.java    1999/10/09 00:20:35     1.1.1.1
+++ CoreElement.java    2000/04/17 17:24:27
@@ -58,7 +58,7 @@
  * <http://www.apache.org/>.
  *
  */
-package org.apache.jasper.compiler;
+package org.apache.jasper.parser;

 import org.apache.jasper.JasperException;

Index: DelegatingListener.java
===================================================================
RCS file:
/home/cvspublic/jakarta-tomcat/src/share/org/apache/jasper/compiler/Delegati
ngListener.java,v
retrieving revision 1.5
diff -u -r1.5 DelegatingListener.java
--- DelegatingListener.java     2000/02/25 19:45:38     1.5
+++ DelegatingListener.java     2000/04/17 17:24:27
@@ -59,7 +59,7 @@
  *
  */

-package org.apache.jasper.compiler;
+package org.apache.jasper.parser;

 import java.util.Hashtable;
 import java.util.Vector;
@@ -186,7 +186,7 @@
     }

     public void handleTagBegin(Mark start, Mark stop, Hashtable attrs,
String prefix,
-                              String shortTagName, TagLibraryInfoImpl tli,
+                              String shortTagName, TagLibraryInfo tli,
                               TagInfo ti)
        throws JasperException
     {
@@ -196,7 +196,7 @@

     public void handleTagEnd(Mark start, Mark stop, String prefix,
                             String shortTagName, Hashtable attrs,
-                             TagLibraryInfoImpl tli, TagInfo ti)
+                             TagLibraryInfo tli, TagInfo ti)
        throws JasperException
     {
         doAction(this.tmplStart, this.tmplStop);
cvs.real server: I know nothing about JspParsingContext.java
Index: JspReader.java
===================================================================
RCS file:
/home/cvspublic/jakarta-tomcat/src/share/org/apache/jasper/compiler/JspReade
r.java,v
retrieving revision 1.13
diff -u -r1.13 JspReader.java
--- JspReader.java      2000/03/28 04:29:48     1.13
+++ JspReader.java      2000/04/17 17:24:28
@@ -54,7 +54,7 @@
  */


-package org.apache.jasper.compiler;
+package org.apache.jasper.parser;

 import java.io.InputStreamReader;
 import java.io.FileInputStream;
@@ -63,13 +63,14 @@
 import java.io.CharArrayWriter;
 import java.io.IOException;
 import java.io.FileNotFoundException;
-import java.io.File;
 import java.util.Hashtable;
 import java.util.Vector;
 import java.util.Stack;

+import javax.servlet.jsp.tagext.TagLibraryInfo;
+
+import org.apache.jasper.JasperException;
 import org.apache.jasper.Constants;
-import org.apache.jasper.JspCompilationContext;

 /**
  * JspReader is an input buffer for the JSP parser. It should allow
@@ -88,12 +89,36 @@
     Vector sourceFiles = new Vector();
     int size = 0;

-    private JspCompilationContext context;
+    private JspParsingContext context;

     public String getFile(int fileid) {
        return (String) sourceFiles.elementAt(fileid);
     }

+    /** Creates an implementation of TagLibraryInfo, possibly with the help
of the web.xml file.
+    * @param prefix perfix of the library in this page
+    * @param uri URI of this library in this page
+    */
+    public TagLibraryInfo getTagLibrary(String prefix, String uri) throws
IOException, JasperException {
+        String location =
(String)context.getTagLibraryDDEntries().get(uri);
+        if (location == null) {
+            // not present in web.xml
+            location = resolveRelativeUri(uri);
+        }
+        else {
+            // If this is a relative path, then it has to be
+            // relative to where web.xml is.
+
+            // I'm taking the simple way out. Since web.xml
+            // has to be directly under WEB-INF, I'm making
+            // an absolute URI out of it by prepending WEB-INF
+
+            if (!location.startsWith("/"))
+                location = "/WEB-INF/" + location;
+        }
+        return context.createTagLibraryInfo(location);
+    }
+
     /**
      * Register a new source file.
      * This method is used to implement file inclusion. Each included file
@@ -101,13 +126,23 @@
      * @return The index of the now registered file.
      */
     protected int registerSourceFile(String file) {
-        if (sourceFiles.contains(file))
-            return -1;
        sourceFiles.addElement(file);
        this.size++;
        return sourceFiles.size()-1;
     }

+    private String resolveRelativeUri(String name) {
+        String parent = master == null ?
+            null : master.substring(0, master.lastIndexOf("/") + 1);
+        boolean isAbsolute = name.startsWith("/");
+
+        if (parent == null || isAbsolute)
+            return name;
+        else
+            return parent + name;
+
+    }
+
     /**
      * Push a new file onto the stack.
      * The name of the file is resolved to a fully qualified filename.
@@ -117,14 +152,7 @@
     public void pushFile(String name, String encoding)
        throws ParseException, FileNotFoundException
     {
-        String parent = master == null ?
-            null : master.substring(0, master.lastIndexOf("/") + 1);
-        boolean isAbsolute = name.startsWith("/");
-
-        if (parent == null || isAbsolute)
-            pushFile(new File(name), encoding);
-        else
-            pushFile(new File(parent + name), encoding);
+        pushResource(resolveRelativeUri(name), encoding);

         if (master == null)
             master = name;
@@ -132,10 +160,10 @@

     /**
      * Push a new file to be parsed onto the stack.
-     * @param inputFile The fully qualified path of the file.
+     * @param resource The fully qualified resource name.
      * @param encoding Optional encoding to read the file.
      */
-    private void pushFile(File file, String encoding)
+    private void pushResource(String resource, String encoding)
        throws ParseException, FileNotFoundException
     {
         // Default encoding if needed:
@@ -147,29 +175,21 @@
         }

        // Register the file, and read its content:
-       int fileid    = registerSourceFile(file.getAbsolutePath());
-        if (fileid == -1)
-            throw new
ParseException(Constants.getString("jsp.error.file.already.registered",
-                                                         new Object[] {
-                                                             file
-                                                         }));
-
+       int fileid    = registerSourceFile(resource);

-       InputStreamReader reader = null;
+       Reader reader = null;
        try {
-            if (context == null)
-                reader = new InputStreamReader(new FileInputStream(file),
-                                               encoding);
+            if (context.isReaderSupported(resource, encoding))
+                reader = context.getResourceAsReader(resource, encoding);
             else {
-               String fileName = context.getRealPath(file.toString());
-                InputStream in = new FileInputStream(fileName);
+                InputStream in = context.getResourceAsStream(resource);
                 if (in == null)
-                    throw new FileNotFoundException(fileName);
+                    throw new FileNotFoundException(resource);

                 try {
                     reader = new InputStreamReader(in, encoding);
                 } catch (Throwable ex) {
-                    throw new FileNotFoundException(fileName + ": "+
ex.getMessage());
+                    throw new FileNotFoundException(resource + ": "+
ex.getMessage());
                 }
             }

@@ -179,9 +199,13 @@
                caw.write(buf, 0, i);
            caw.close();
            if (current == null) {
-               current = new Mark( this, caw.toCharArray(), fileid,
file.getParent(), encoding );
+               current = new Mark( this, caw.toCharArray(), fileid,
encoding );
            } else {
-               current.pushStream( caw.toCharArray(), fileid,
file.getParent(), encoding );
+               if (!current.pushStream( caw.toCharArray(), fileid, encoding
))
+                    throw new
ParseException(Constants.getString("jsp.error.file.already.registered",
+                                                                 new
Object[] {
+
resource
+                                                                 }));
            }

         } catch (FileNotFoundException fnfe) {
@@ -192,7 +216,7 @@
            // Pop state being constructed:
            popFile();
            throw new
ParseException(Constants.getString("jsp.error.file.cannot.read",
-                                                       new Object[] { file
}));
+                                                       new Object[] {
resource }));
        } finally {
            if ( reader != null ) {
                try { reader.close(); } catch (Exception any) {}
@@ -212,14 +236,14 @@
        return current.popStream();
     }

-    protected JspReader(String file, JspCompilationContext ctx, String
encoding)
+    protected JspReader(String file, JspParsingContext ctx, String
encoding)
        throws ParseException, FileNotFoundException
     {
         this.context = ctx;
        pushFile(file, encoding);
     }

-    public static JspReader createJspReader(String file,
JspCompilationContext ctx, String encoding)
+    public static JspReader createJspReader(String file, JspParsingContext
ctx, String encoding)
        throws ParseException, FileNotFoundException
     {
        return new JspReader(file, ctx, encoding);
cvs.real server: I know nothing about Main.java
Index: Mark.java
===================================================================
RCS file:
/home/cvspublic/jakarta-tomcat/src/share/org/apache/jasper/compiler/Mark.jav
a,v
retrieving revision 1.2
diff -u -r1.2 Mark.java
--- Mark.java   1999/12/21 13:14:16     1.2
+++ Mark.java   2000/04/17 17:24:28
@@ -58,7 +58,7 @@
  * <http://www.apache.org/>.
  *
  */
-package org.apache.jasper.compiler;
+package org.apache.jasper.parser;

 import java.util.Stack;

@@ -70,7 +70,7 @@
 public final class Mark {
     int cursor, line, col;     // position within current stream
     int fileid;                        // fileid of current stream
-    String baseDir;            // directory of file for current stream
+    //String baseDir;          // directory of file for current stream
     char[] stream = null;      // current stream
     Stack includeStack = null; // stack of stream and stream state of
streams
                                //   that have included current stream
@@ -88,18 +88,18 @@
     class IncludeState {
        int cursor, line, col;
        int fileid;
-       String baseDir;
+       //String baseDir;
        String encoding;
        char[] stream = null;

        IncludeState(int inCursor, int inLine, int inCol, int inFileid,
-                    String inBaseDir, String inEncoding, char[] inStream)
+                    /*String inBaseDir, */String inEncoding, char[]
inStream)
        {
            cursor = inCursor;
            line = inLine;
            col = inCol;
            fileid = inFileid;
-           baseDir = inBaseDir;
+//         baseDir = inBaseDir;
            encoding = inEncoding;
            stream = inStream;
        }
@@ -114,14 +114,14 @@
     * @param inEncoding encoding of current file
     * @param inBaseDir base directory of requested jsp file
     */
-    Mark(JspReader reader, char[] inStream, int fileid, String inBaseDir,
+    Mark(JspReader reader, char[] inStream, int fileid, /*String inBaseDir,
*/
         String inEncoding)
     {
        this.reader = reader;
        this.stream = inStream;
        this.cursor = this.line = this.col = 0;
        this.fileid = fileid;
-       this.baseDir = inBaseDir;
+       //this.baseDir = inBaseDir;
        this.encoding = inEncoding;
        this.includeStack = new Stack();
     }
@@ -133,7 +133,7 @@
        this.cursor = other.cursor;
        this.line = other.line;
        this.col = other.col;
-       this.baseDir = other.baseDir;
+       //this.baseDir = other.baseDir;
        this.encoding = other.encoding;

        // clone includeStack without cloning contents
@@ -150,12 +150,19 @@
      * @param inBaseDir directory of file
         * @param inEncoding encoding of new file
      */
-    public void pushStream(char[] inStream, int inFileid, String inBaseDir,
+    public boolean pushStream(char[] inStream, int inFileid, /*String
inBaseDir, */
                           String inEncoding)
     {
+        // check that the file has not been registered yet
+        String newFile = reader.getFile(inFileid);
+        for (int i = 0; i < includeStack.size() - 1; i++) {
+          String file =
reader.getFile(((IncludeState)includeStack.elementAt(i)).fileid);
+          if (newFile.equals(file))
+            return false;
+        }

        // store current state in stack
-       includeStack.push(new IncludeState(cursor, line, col, fileid,
baseDir,
+       includeStack.push(new IncludeState(cursor, line, col, fileid,/*
baseDir, */
                                           encoding, stream) );

        // set new variables
@@ -163,9 +170,11 @@
        line = 0;
        col = 0;
        fileid = inFileid;
-       baseDir = inBaseDir;
+       //baseDir = inBaseDir;
        encoding = inEncoding;
        stream = inStream;
+
+       return true;
     }


@@ -184,7 +193,7 @@
        line = state.line;
        col = state.col;
        fileid = state.fileid;
-       baseDir = state.baseDir;
+       //baseDir = state.baseDir;
        stream = state.stream;
        return true;
     }
Index: ParseEventListener.java
===================================================================
RCS file:
/home/cvspublic/jakarta-tomcat/src/share/org/apache/jasper/compiler/ParseEve
ntListener.java,v
retrieving revision 1.5
diff -u -r1.5 ParseEventListener.java
--- ParseEventListener.java     2000/02/25 19:45:38     1.5
+++ ParseEventListener.java     2000/04/17 17:24:29
@@ -58,7 +58,7 @@
  * <http://www.apache.org/>.
  *
  */
-package org.apache.jasper.compiler;
+package org.apache.jasper.parser;

 import java.util.Hashtable;
 import java.util.Vector;
@@ -107,11 +107,11 @@
      * stop: can be null if the body contained JSP tags...
      */
     void handleTagBegin(Mark start, Mark stop, Hashtable attrs, String
prefix, String shortTagName,
-                       TagLibraryInfoImpl tli, TagInfo ti)
+                       TagLibraryInfo tli, TagInfo ti)
        throws JasperException;

     void handleTagEnd(Mark start, Mark stop, String prefix, String
shortTagName,
-                     Hashtable attrs, TagLibraryInfoImpl tli, TagInfo ti)
+                     Hashtable attrs, TagLibraryInfo tli, TagInfo ti)
        throws JasperException;

     void handleForward(Mark start, Mark stop, Hashtable attrs, Hashtable
param)
Index: ParseException.java
===================================================================
RCS file:
/home/cvspublic/jakarta-tomcat/src/share/org/apache/jasper/compiler/ParseExc
eption.java,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 ParseException.java
--- ParseException.java 1999/10/09 00:20:37     1.1.1.1
+++ ParseException.java 2000/04/17 17:24:29
@@ -58,7 +58,7 @@
  * <http://www.apache.org/>.
  *
  */
-package org.apache.jasper.compiler;
+package org.apache.jasper.parser;

 import org.apache.jasper.JasperException;

Index: Parser.java
===================================================================
RCS file:
/home/cvspublic/jakarta-tomcat/src/share/org/apache/jasper/compiler/Parser.j
ava,v
retrieving revision 1.19
diff -u -r1.19 Parser.java
--- Parser.java 2000/04/07 22:27:52     1.19
+++ Parser.java 2000/04/17 17:24:32
@@ -52,7 +52,7 @@
  * <http://www.apache.org/>.
  *
  */
-package org.apache.jasper.compiler;
+package org.apache.jasper.parser;

 import java.util.Vector;
 import java.util.Hashtable;
@@ -136,27 +136,27 @@
          "taglib"
        };

-       private static final JspUtil.ValidAttribute[] pageDvalidAttrs = {
-           new JspUtil.ValidAttribute ("language"),
-           new JspUtil.ValidAttribute ("extends"),
-           new JspUtil.ValidAttribute ("import"),
-           new JspUtil.ValidAttribute ("session"),
-           new JspUtil.ValidAttribute ("buffer"),
-           new JspUtil.ValidAttribute ("autoFlush"),
-           new JspUtil.ValidAttribute ("isThreadSafe"),
-           new JspUtil.ValidAttribute ("info"),
-           new JspUtil.ValidAttribute ("errorPage"),
-           new JspUtil.ValidAttribute ("isErrorPage"),
-           new JspUtil.ValidAttribute ("contentType")
+       private static final ParseUtil.ValidAttribute[] pageDvalidAttrs = {
+           new ParseUtil.ValidAttribute ("language"),
+           new ParseUtil.ValidAttribute ("extends"),
+           new ParseUtil.ValidAttribute ("import"),
+           new ParseUtil.ValidAttribute ("session"),
+           new ParseUtil.ValidAttribute ("buffer"),
+           new ParseUtil.ValidAttribute ("autoFlush"),
+           new ParseUtil.ValidAttribute ("isThreadSafe"),
+           new ParseUtil.ValidAttribute ("info"),
+           new ParseUtil.ValidAttribute ("errorPage"),
+           new ParseUtil.ValidAttribute ("isErrorPage"),
+           new ParseUtil.ValidAttribute ("contentType")
        };

-       private static final JspUtil.ValidAttribute[] includeDvalidAttrs = {
-           new JspUtil.ValidAttribute ("file", true)
+       private static final ParseUtil.ValidAttribute[] includeDvalidAttrs =
{
+           new ParseUtil.ValidAttribute ("file", true)
        };

-       private static final JspUtil.ValidAttribute[] tagDvalidAttrs = {
-           new JspUtil.ValidAttribute ("uri", true),
-           new JspUtil.ValidAttribute ("prefix", true)
+       private static final ParseUtil.ValidAttribute[] tagDvalidAttrs = {
+           new ParseUtil.ValidAttribute ("uri", true),
+           new ParseUtil.ValidAttribute ("prefix", true)
        };

        public boolean accept(ParseEventListener listener, JspReader reader,
@@ -191,13 +191,13 @@
            // Parse the attr-val pairs.
            Hashtable attrs = reader.parseTagAttributes();
            if (match.equals ("page"))
-               JspUtil.checkAttributes ("Page directive", attrs,
+               ParseUtil.checkAttributes ("Page directive", attrs,
                                         pageDvalidAttrs);
            else if (match.equals("include"))
-               JspUtil.checkAttributes ("Include directive", attrs,
+               ParseUtil.checkAttributes ("Include directive", attrs,
                                         includeDvalidAttrs);
            else if (match.equals("taglib"))
-               JspUtil.checkAttributes ("Taglib directive", attrs,
+               ParseUtil.checkAttributes ("Taglib directive", attrs,
                                         tagDvalidAttrs);

            // Match close.
@@ -211,11 +211,50 @@

            Mark stop = reader.mark();

+            if (match.equals("include"))
+                processIncludeDirective(reader, start, stop, attrs);
+            if (match.equals("taglib"))
+                processTaglibDirective(listener, reader, start, stop,
attrs);
            listener.setTemplateInfo(parser.tmplStart, parser.tmplStop);
            listener.handleDirective(match, start, stop, attrs);
            return true;
        }

+        private void processTaglibDirective(ParseEventListener listener,
JspReader reader,
+                                            Mark start, Mark stop,
+                                            Hashtable attrs) throws
JasperException {
+            String uri = (String) attrs.get("uri");
+            String prefix = (String) attrs.get("prefix");
+            try {
+                TagLibraryInfo tl = reader.getTagLibrary(prefix, uri);
+                listener.getTagLibraries().addTagLibrary(prefix, tl);
+            } catch (JasperException ex) {
+                throw ex;
+            } catch (Exception ex) {
+                ex.printStackTrace();
+                Object[] args = new Object[] { uri, ex.getMessage() };
+                throw new
JasperException(Constants.getString("jsp.error.badtaglib",
+                                                              args));
+            }
+        }
+
+        private void processIncludeDirective(JspReader reader,
+                                            Mark start, Mark stop,
+                                            Hashtable attrs) throws
JasperException {
+           String file = (String) attrs.get("file");
+           String encoding = (String) attrs.get("encoding");
+
+           if (file == null)
+               throw new
JasperException(Constants.getString("jsp.error.include.missing.file"));
+
+            // jsp.error.include.bad.file needs taking care of here??
+            try {
+                reader.pushFile(file, encoding);
+            } catch (java.io.FileNotFoundException fnfe) {
+                throw new
JasperException(Constants.getString("jsp.error.include.bad.file"));
+            }
+       }
+
     }

     static {
@@ -233,9 +272,9 @@
        private static final String OPEN_INDIVIDUAL_PARAM = "<jsp:param";
        private static final String CLOSE_INDIVIDUAL_PARAM = "/>";

-       private static final JspUtil.ValidAttribute[] validAttributes = {
-            new JspUtil.ValidAttribute("page", true),
-            new JspUtil.ValidAttribute("flush")
+       private static final ParseUtil.ValidAttribute[] validAttributes = {
+            new ParseUtil.ValidAttribute("page", true),
+            new ParseUtil.ValidAttribute("flush")
        };

        public boolean accept(ParseEventListener listener, JspReader reader,
@@ -247,7 +286,7 @@
                Mark start = reader.mark();
                reader.advance(OPEN_INCLUDE.length());
                Hashtable attrs = reader.parseTagAttributes();
-               JspUtil.checkAttributes ("Include", attrs, validAttributes);
+               ParseUtil.checkAttributes ("Include", attrs,
validAttributes);
                reader.skipSpaces();

                if (!reader.matches(CLOSE_INCLUDE_NO_BODY)) {
@@ -318,8 +357,8 @@
        private static final String OPEN_INDIVIDUAL_PARAM = "<jsp:param";
        private static final String CLOSE_INDIVIDUAL_PARAM = "/>";

-       private static final JspUtil.ValidAttribute[] validAttributes = {
-          new JspUtil.ValidAttribute("page", true)
+       private static final ParseUtil.ValidAttribute[] validAttributes = {
+          new ParseUtil.ValidAttribute("page", true)
        };
        public boolean accept(ParseEventListener listener, JspReader reader,
                                Parser parser)
@@ -330,7 +369,7 @@
                reader.advance(OPEN_FORWARD.length());
                Hashtable attrs = reader.parseTagAttributes();
                Hashtable param = new Hashtable();
-               JspUtil.checkAttributes ("Forward", attrs, validAttributes);
+               ParseUtil.checkAttributes ("Forward", attrs,
validAttributes);
                reader.skipSpaces();
                if (!reader.matches(CLOSE_FORWARD_NO_BODY)) {
                    if (!reader.matches(CLOSE_FORWARD_BODY))
@@ -433,7 +472,7 @@
        private static final String OPEN_DECL  = "<%!";
        private static final String CLOSE_DECL = "%>";

-        private static final JspUtil.ValidAttribute[] validAttributes = {
+        private static final ParseUtil.ValidAttribute[] validAttributes = {
         };

        public boolean accept(ParseEventListener listener, JspReader reader,
Parser parser)
@@ -460,7 +499,7 @@
                reader.advance(end_open.length());
                reader.skipSpaces();

-               JspUtil.checkAttributes("Declaration", attrs,
validAttributes);
+               ParseUtil.checkAttributes("Declaration", attrs,
validAttributes);
             }

            Mark start = reader.mark();
@@ -486,7 +525,7 @@
        private static final String OPEN_EXPR  = "<%=";
        private static final String CLOSE_EXPR = "%>";

-        private static final JspUtil.ValidAttribute[] validAttributes = {
+        private static final ParseUtil.ValidAttribute[] validAttributes = {
         };

        public boolean accept(ParseEventListener listener, JspReader reader,
Parser parser)
@@ -513,7 +552,7 @@
                reader.advance(end_open.length());
                reader.skipSpaces();

-                JspUtil.checkAttributes("Expression", attrs,
validAttributes);
+                ParseUtil.checkAttributes("Expression", attrs,
validAttributes);
             }

            Mark start = reader.mark();
@@ -538,7 +577,7 @@
        private static final String OPEN_SCRIPTLET  = "<%";
        private static final String CLOSE_SCRIPTLET = "%>";

-        private static final JspUtil.ValidAttribute[] validAttributes = {
+        private static final ParseUtil.ValidAttribute[] validAttributes = {
         };

        public boolean accept(ParseEventListener listener, JspReader reader,
Parser parser)
@@ -565,7 +604,7 @@
                reader.advance(end_open.length());
                reader.skipSpaces();

-                JspUtil.checkAttributes("Scriptlet", attrs,
validAttributes);
+                ParseUtil.checkAttributes("Scriptlet", attrs,
validAttributes);
             }

            Mark start = reader.mark();
@@ -594,12 +633,12 @@
        private static final String CLOSE_BEAN_2 = "</jsp:useBean>";
        private static final String CLOSE_BEAN_3 = ">";

-       private static final JspUtil.ValidAttribute[] validAttributes = {
-          new JspUtil.ValidAttribute("id"),
-          new JspUtil.ValidAttribute("scope"),
-          new JspUtil.ValidAttribute("class"),
-          new JspUtil.ValidAttribute("type"),
-          new JspUtil.ValidAttribute("beanName")
+       private static final ParseUtil.ValidAttribute[] validAttributes = {
+          new ParseUtil.ValidAttribute("id"),
+          new ParseUtil.ValidAttribute("scope"),
+          new ParseUtil.ValidAttribute("class"),
+          new ParseUtil.ValidAttribute("type"),
+          new ParseUtil.ValidAttribute("beanName")
        };

        public boolean accept(ParseEventListener listener, JspReader reader,
Parser parser)
@@ -609,7 +648,7 @@
                Mark start = reader.mark();
                reader.advance(OPEN_BEAN.length());
                Hashtable attrs = reader.parseTagAttributesBean();
-               JspUtil.checkAttributes ("useBean", attrs, validAttributes);
+               ParseUtil.checkAttributes ("useBean", attrs,
validAttributes);
                reader.skipSpaces();
                if (!reader.matches(CLOSE_BEAN)) {
                    if (!reader.matches(CLOSE_BEAN_3))
@@ -662,9 +701,9 @@
        private static final String OPEN_GETPROPERTY  = "<jsp:getProperty";
        private static final String CLOSE_GETPROPERTY = "/>";

-       private static final JspUtil.ValidAttribute[] validAttributes = {
-          new JspUtil.ValidAttribute("name", true),
-          new JspUtil.ValidAttribute("property", true)
+       private static final ParseUtil.ValidAttribute[] validAttributes = {
+          new ParseUtil.ValidAttribute("name", true),
+          new ParseUtil.ValidAttribute("property", true)
        };

        public boolean accept(ParseEventListener listener, JspReader reader,
Parser parser)
@@ -674,7 +713,7 @@
                Mark start = reader.mark();
                reader.advance(OPEN_GETPROPERTY.length());
                Hashtable attrs = reader.parseTagAttributes ();
-               JspUtil.checkAttributes ("getProperty", attrs,
validAttributes);
+               ParseUtil.checkAttributes ("getProperty", attrs,
validAttributes);
                reader.skipSpaces();
                if (!reader.matches(CLOSE_GETPROPERTY))
                    throw new ParseException(reader.mark(),
@@ -703,11 +742,11 @@
        private static final String OPEN_SETPROPERTY  = "<jsp:setProperty";
        private static final String CLOSE_SETPROPERTY = "/>";

-       private static final JspUtil.ValidAttribute[] validAttributes = {
-          new JspUtil.ValidAttribute("name", true),
-          new JspUtil.ValidAttribute("property", true),
-          new JspUtil.ValidAttribute("value"),
-          new JspUtil.ValidAttribute("param")
+       private static final ParseUtil.ValidAttribute[] validAttributes = {
+          new ParseUtil.ValidAttribute("name", true),
+          new ParseUtil.ValidAttribute("property", true),
+          new ParseUtil.ValidAttribute("value"),
+          new ParseUtil.ValidAttribute("param")
        };

        public boolean accept(ParseEventListener listener, JspReader reader,
Parser parser)
@@ -717,7 +756,7 @@
                Mark start = reader.mark();
                reader.advance(OPEN_SETPROPERTY.length());
                Hashtable attrs = reader.parseTagAttributes ();
-               JspUtil.checkAttributes ("setProperty", attrs,
validAttributes);
+               ParseUtil.checkAttributes ("setProperty", attrs,
validAttributes);
                reader.skipSpaces();
                if (!reader.matches(CLOSE_SETPROPERTY))
                    throw new ParseException(reader.mark(),
@@ -784,7 +823,7 @@
                 throw new ParseException(start, "Nothing after the :");


-            TagLibraryInfoImpl tli = libraries.getTagLibInfo(prefix);
+            TagLibraryInfo tli = libraries.getTagLibInfo(prefix);
             TagInfo ti = tli.getTag(shortTagName);

             if (ti == null)
@@ -869,20 +908,20 @@
        private static final String OPEN_FALLBACK = "<jsp:fallback>";
        private static final String CLOSE_FALLBACK = "</jsp:fallback>";

-       private static final JspUtil.ValidAttribute[] validAttributes = {
-          new JspUtil.ValidAttribute ("type",true),
-          new JspUtil.ValidAttribute("code", true),
-          new JspUtil.ValidAttribute("codebase"),
-          new JspUtil.ValidAttribute("align"),
-          new JspUtil.ValidAttribute("archive"),
-          new JspUtil.ValidAttribute("height"),
-          new JspUtil.ValidAttribute("hspace"),
-          new JspUtil.ValidAttribute("jreversion"),
-          new JspUtil.ValidAttribute("name"),
-          new JspUtil.ValidAttribute("vspace"),
-          new JspUtil.ValidAttribute("width"),
-          new JspUtil.ValidAttribute("nspluginurl"),
-          new JspUtil.ValidAttribute("iepluginurl")
+       private static final ParseUtil.ValidAttribute[] validAttributes = {
+          new ParseUtil.ValidAttribute ("type",true),
+          new ParseUtil.ValidAttribute("code", true),
+          new ParseUtil.ValidAttribute("codebase"),
+          new ParseUtil.ValidAttribute("align"),
+          new ParseUtil.ValidAttribute("archive"),
+          new ParseUtil.ValidAttribute("height"),
+          new ParseUtil.ValidAttribute("hspace"),
+          new ParseUtil.ValidAttribute("jreversion"),
+          new ParseUtil.ValidAttribute("name"),
+          new ParseUtil.ValidAttribute("vspace"),
+          new ParseUtil.ValidAttribute("width"),
+          new ParseUtil.ValidAttribute("nspluginurl"),
+          new ParseUtil.ValidAttribute("iepluginurl")
        };

        public boolean accept(ParseEventListener listener, JspReader reader,
@@ -904,7 +943,7 @@
                Hashtable param = null;
                String fallback = null;

-               JspUtil.checkAttributes ("plugin", attrs, validAttributes);
+               ParseUtil.checkAttributes ("plugin", attrs,
validAttributes);
                if (reader.matches (OPEN_PARAMS)) {
                    param = new Hashtable ();
                    boolean paramsClosed = false;
cvs.real server: I know nothing about ParseUtil.java
Index: TagCache.java
===================================================================
RCS file:
/home/cvspublic/jakarta-tomcat/src/share/org/apache/jasper/compiler/TagCache
.java,v
retrieving revision 1.1
diff -u -r1.1 TagCache.java
--- TagCache.java       1999/10/20 11:22:54     1.1
+++ TagCache.java       2000/04/17 17:24:35
@@ -58,7 +58,7 @@
  * <http://www.apache.org/>.
  *
  */
-package org.apache.jasper.compiler;
+package org.apache.jasper.parser;

 import java.util.Hashtable;

Index: TagLibraries.java
===================================================================
RCS file:
/home/cvspublic/jakarta-tomcat/src/share/org/apache/jasper/compiler/TagLibra
ries.java,v
retrieving revision 1.4
diff -u -r1.4 TagLibraries.java
--- TagLibraries.java   1999/11/08 03:14:31     1.4
+++ TagLibraries.java   2000/04/17 17:24:35
@@ -52,7 +52,7 @@
  * <http://www.apache.org/>.
  *
  */
-package org.apache.jasper.compiler;
+package org.apache.jasper.parser;

 import java.lang.reflect.Constructor;

@@ -72,14 +72,15 @@
  *
  * @author Anil K. Vijendran
  */
-public class TagLibraries {
+public final class TagLibraries {

-    TagLibraries(ClassLoader cl) {
+    public TagLibraries(ClassLoader cl) {
         this.tagLibInfos = new Hashtable();
+        this.tagCaches = new Hashtable();
         this.cl = cl;
     }

-    void addTagLibrary(String prefix, TagLibraryInfoImpl tli) {
+    void addTagLibrary(String prefix, TagLibraryInfo tli) {
         tagLibInfos.put(prefix, tli);
     }

@@ -99,10 +100,40 @@
                                                       ));
     }

-    public TagLibraryInfoImpl getTagLibInfo(String prefix) {
-        return (TagLibraryInfoImpl) tagLibInfos.get(prefix);
+    public TagLibraryInfo getTagLibInfo(String prefix) {
+        return (TagLibraryInfo) tagLibInfos.get(prefix);
     }

+    public TagCache getTagCache(String prefix, String shortTagName) {
+        return (TagCache) tagCaches.get(new TagID(prefix, shortTagName));
+    }
+
+    public void putTagCache(String prefix, String shortTagName, TagCache
tc) {
+        tagCaches.put(new TagID(prefix, shortTagName), tc);
+    }
+
     private Hashtable tagLibInfos;
+    private Hashtable tagCaches;
     private ClassLoader cl;
+
+    private static class TagID {
+
+        private String prefix;
+        private String shortTagName;
+
+        public TagID(String prefix, String shortTagName) {
+            this.prefix = prefix;
+            this.shortTagName = shortTagName;
+        }
+
+        public boolean equals(Object obj) {
+            return (prefix.equals(((TagID)obj).prefix)) &&
+                   (shortTagName.equals(((TagID)obj).shortTagName));
+        }
+
+        public int hashCode() {
+          return prefix.hashCode() + shortTagName.hashCode();
+        }
+
+    }
 }