You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@struts.apache.org by mu...@apache.org on 2009/09/28 03:55:35 UTC

svn commit: r819444 [10/27] - in /struts/struts2/trunk/plugins/embeddedjsp: ./ src/main/java/org/apache/struts2/el/ src/main/java/org/apache/struts2/el/lang/ src/main/java/org/apache/struts2/el/parser/ src/main/java/org/apache/struts2/el/util/ src/main...

Added: struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/compiler/ImplicitTagLibraryInfo.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/compiler/ImplicitTagLibraryInfo.java?rev=819444&view=auto
==============================================================================
--- struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/compiler/ImplicitTagLibraryInfo.java (added)
+++ struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/compiler/ImplicitTagLibraryInfo.java Mon Sep 28 01:55:26 2009
@@ -0,0 +1,218 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.struts2.jasper.compiler;
+
+import java.io.InputStream;
+import java.util.Collection;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.Vector;
+
+import javax.servlet.jsp.tagext.FunctionInfo;
+import javax.servlet.jsp.tagext.TagFileInfo;
+import javax.servlet.jsp.tagext.TagInfo;
+import javax.servlet.jsp.tagext.TagLibraryInfo;
+
+import org.apache.struts2.jasper.JasperException;
+import org.apache.struts2.jasper.JspCompilationContext;
+import org.apache.struts2.jasper.xmlparser.ParserUtils;
+import org.apache.struts2.jasper.xmlparser.TreeNode;
+
+/**
+ * Class responsible for generating an implicit tag library containing tag
+ * handlers corresponding to the tag files in "/WEB-INF/tags/" or a 
+ * subdirectory of it.
+ *
+ * @author Jan Luehe
+ */
+class ImplicitTagLibraryInfo extends TagLibraryInfo {
+
+    private static final String WEB_INF_TAGS = "/WEB-INF/tags";
+    private static final String TAG_FILE_SUFFIX = ".tag";
+    private static final String TAGX_FILE_SUFFIX = ".tagx";
+    private static final String TAGS_SHORTNAME = "tags";
+    private static final String TLIB_VERSION = "1.0";
+    private static final String JSP_VERSION = "2.0";
+    private static final String IMPLICIT_TLD = "implicit.tld";
+
+    // Maps tag names to tag file paths
+    private Hashtable tagFileMap;
+
+    private ParserController pc;
+    private PageInfo pi;
+    private Vector vec;
+
+    /**
+     * Constructor.
+     */
+    public ImplicitTagLibraryInfo(JspCompilationContext ctxt,
+            ParserController pc,
+            PageInfo pi,
+            String prefix,
+            String tagdir,
+            ErrorDispatcher err) throws JasperException {
+        super(prefix, null);
+        this.pc = pc;
+        this.pi = pi;
+        this.tagFileMap = new Hashtable();
+        this.vec = new Vector();
+
+        // Implicit tag libraries have no functions:
+        this.functions = new FunctionInfo[0];
+
+        tlibversion = TLIB_VERSION;
+        jspversion = JSP_VERSION;
+
+        if (!tagdir.startsWith(WEB_INF_TAGS)) {
+            err.jspError("jsp.error.invalid.tagdir", tagdir);
+        }
+
+        // Determine the value of the <short-name> subelement of the
+        // "imaginary" <taglib> element
+        if (tagdir.equals(WEB_INF_TAGS)
+                || tagdir.equals( WEB_INF_TAGS + "/")) {
+            shortname = TAGS_SHORTNAME;
+        } else {
+            shortname = tagdir.substring(WEB_INF_TAGS.length());
+            shortname = shortname.replace('/', '-');
+        }
+
+        // Populate mapping of tag names to tag file paths
+        Set dirList = ctxt.getResourcePaths(tagdir);
+        if (dirList != null) {
+            Iterator it = dirList.iterator();
+            while (it.hasNext()) {
+                String path = (String) it.next();
+                if (path.endsWith(TAG_FILE_SUFFIX)
+                        || path.endsWith(TAGX_FILE_SUFFIX)) {
+                    /*
+                     * Use the filename of the tag file, without the .tag or
+                     * .tagx extension, respectively, as the <name> subelement
+                     * of the "imaginary" <tag-file> element
+                     */
+                    String suffix = path.endsWith(TAG_FILE_SUFFIX) ?
+                            TAG_FILE_SUFFIX : TAGX_FILE_SUFFIX; 
+                    String tagName = path.substring(path.lastIndexOf("/") + 1);
+                    tagName = tagName.substring(0,
+                            tagName.lastIndexOf(suffix));
+                    tagFileMap.put(tagName, path);
+                } else if (path.endsWith(IMPLICIT_TLD)) {
+                    InputStream in = null;
+                    try {
+                        in = ctxt.getResourceAsStream(path);
+                        if (in != null) {
+                            
+                            // Add implicit TLD to dependency list
+                            if (pi != null) {
+                                pi.addDependant(path);
+                            }
+                            
+                            ParserUtils pu = new ParserUtils();
+                            TreeNode tld = pu.parseXMLDocument(uri, in);
+
+                            if (tld.findAttribute("version") != null) {
+                                this.jspversion = tld.findAttribute("version");
+                            }
+
+                            // Process each child element of our <taglib> element
+                            Iterator list = tld.findChildren();
+
+                            while (list.hasNext()) {
+                                TreeNode element = (TreeNode) list.next();
+                                String tname = element.getName();
+
+                                if ("tlibversion".equals(tname) // JSP 1.1
+                                        || "tlib-version".equals(tname)) { // JSP 1.2
+                                    this.tlibversion = element.getBody();
+                                } else if ("jspversion".equals(tname)
+                                        || "jsp-version".equals(tname)) {
+                                    this.jspversion = element.getBody();
+                                } else if ("shortname".equals(tname) || "short-name".equals(tname)) {
+                                    // Ignore
+                                } else {
+                                    // All other elements are invalid
+                                    err.jspError("jsp.error.invalid.implicit", path);
+                                }
+                            }
+                            try {
+                                double version = Double.parseDouble(this.jspversion);
+                                if (version < 2.0) {
+                                    err.jspError("jsp.error.invalid.implicit.version", path);
+                                }
+                            } catch (NumberFormatException e) {
+                                err.jspError("jsp.error.invalid.implicit.version", path);
+                            }
+                        }
+                    } finally {
+                        if (in != null) {
+                            try {
+                                in.close();
+                            } catch (Throwable t) {
+                            }
+                        }
+                    }
+                }
+            }
+        }        
+        
+    }
+
+    /**
+     * Checks to see if the given tag name maps to a tag file path,
+     * and if so, parses the corresponding tag file.
+     *
+     * @return The TagFileInfo corresponding to the given tag name, or null if
+     * the given tag name is not implemented as a tag file
+     */
+    public TagFileInfo getTagFile(String shortName) {
+
+        TagFileInfo tagFile = super.getTagFile(shortName);
+        if (tagFile == null) {
+            String path = (String) tagFileMap.get(shortName);
+            if (path == null) {
+                return null;
+            }
+
+            TagInfo tagInfo = null;
+            try {
+                tagInfo = TagFileProcessor.parseTagFileDirectives(pc,
+                        shortName,
+                        path,
+                        pc.getJspCompilationContext().getTagFileJarUrl(path),
+                        this);
+            } catch (JasperException je) {
+                throw new RuntimeException(je.toString(), je);
+            }
+
+            tagFile = new TagFileInfo(shortName, path, tagInfo);
+            vec.addElement(tagFile);
+
+            this.tagFiles = new TagFileInfo[vec.size()];
+            vec.copyInto(this.tagFiles);
+        }
+
+        return tagFile;
+    }
+
+    public TagLibraryInfo[] getTagLibraryInfos() {
+        Collection coll = pi.getTaglibs();
+        return (TagLibraryInfo[]) coll.toArray(new TagLibraryInfo[0]);
+    }
+
+}

Added: struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/compiler/JasperTagInfo.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/compiler/JasperTagInfo.java?rev=819444&view=auto
==============================================================================
--- struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/compiler/JasperTagInfo.java (added)
+++ struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/compiler/JasperTagInfo.java Mon Sep 28 01:55:26 2009
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.struts2.jasper.compiler;
+
+import javax.servlet.jsp.tagext.*;
+
+/**
+ * TagInfo extension used by tag handlers that are implemented via tag files.
+ * This class provides access to the name of the Map used to store the
+ * dynamic attribute names and values passed to the custom action invocation.
+ * This information is used by the code generator.
+ */
+class JasperTagInfo extends TagInfo {
+
+    private String dynamicAttrsMapName;
+
+    public JasperTagInfo(String tagName,
+			 String tagClassName,
+			 String bodyContent,
+			 String infoString,
+			 TagLibraryInfo taglib,
+			 TagExtraInfo tagExtraInfo,
+			 TagAttributeInfo[] attributeInfo,
+			 String displayName,
+			 String smallIcon,
+			 String largeIcon,
+			 TagVariableInfo[] tvi,
+			 String mapName) {
+
+	super(tagName, tagClassName, bodyContent, infoString, taglib,
+	      tagExtraInfo, attributeInfo, displayName, smallIcon, largeIcon,
+	      tvi);
+	this.dynamicAttrsMapName = mapName;
+    }
+
+    public String getDynamicAttributesMapName() {
+	return dynamicAttrsMapName;
+    }
+
+    public boolean hasDynamicAttributes() {
+        return dynamicAttrsMapName != null;
+    }
+}

Added: struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/compiler/JavacErrorDetail.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/compiler/JavacErrorDetail.java?rev=819444&view=auto
==============================================================================
--- struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/compiler/JavacErrorDetail.java (added)
+++ struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/compiler/JavacErrorDetail.java Mon Sep 28 01:55:26 2009
@@ -0,0 +1,232 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.struts2.jasper.compiler;
+
+import java.io.BufferedReader;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.struts2.jasper.JspCompilationContext;
+
+/**
+ * Class providing details about a javac compilation error.
+ *
+ * @author Jan Luehe
+ * @author Kin-man Chung
+ */
+public class JavacErrorDetail {
+
+    private String javaFileName;
+    private int javaLineNum;
+    private String jspFileName;
+    private int jspBeginLineNum;
+    private StringBuffer errMsg;
+    private String jspExtract = null;
+
+    /**
+     * Constructor.
+     *
+     * @param javaFileName The name of the Java file in which the 
+     * compilation error occurred
+     * @param javaLineNum The compilation error line number
+     * @param errMsg The compilation error message
+     */
+    public JavacErrorDetail(String javaFileName,
+                            int javaLineNum,
+                            StringBuffer errMsg) {
+
+        this.javaFileName = javaFileName;
+        this.javaLineNum = javaLineNum;
+        this.errMsg = errMsg;
+        this.jspBeginLineNum = -1;
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param javaFileName The name of the Java file in which the 
+     * compilation error occurred
+     * @param javaLineNum The compilation error line number
+     * @param jspFileName The name of the JSP file from which the Java source
+     * file was generated
+     * @param jspBeginLineNum The start line number of the JSP element
+     * responsible for the compilation error
+     * @param errMsg The compilation error message
+     */
+    public JavacErrorDetail(String javaFileName,
+                            int javaLineNum,
+                            String jspFileName,
+                            int jspBeginLineNum,
+                            StringBuffer errMsg) {
+
+        this(javaFileName, javaLineNum, jspFileName, jspBeginLineNum, errMsg,
+                null);
+    }
+
+    public JavacErrorDetail(String javaFileName,
+            int javaLineNum,
+            String jspFileName,
+            int jspBeginLineNum,
+            StringBuffer errMsg,
+            JspCompilationContext ctxt) {
+        
+        this(javaFileName, javaLineNum, errMsg);
+        this.jspFileName = jspFileName;
+        this.jspBeginLineNum = jspBeginLineNum;
+        
+        if (jspBeginLineNum > 0 && ctxt != null) {
+            InputStream is = null;
+            FileInputStream  fis = null;
+            
+            try {
+                // Read both files in, so we can inspect them
+                is = ctxt.getResourceAsStream(jspFileName);
+                String[] jspLines = readFile(is);
+    
+                fis = new FileInputStream(ctxt.getServletJavaFileName());
+                String[] javaLines = readFile(fis);
+    
+                // If the line contains the opening of a multi-line scriptlet
+                // block, then the JSP line number we got back is probably
+                // faulty.  Scan forward to match the java line...
+                if (jspLines[jspBeginLineNum-1].lastIndexOf("<%") >
+                    jspLines[jspBeginLineNum-1].lastIndexOf("%>")) {
+                    String javaLine = javaLines[javaLineNum-1].trim();
+    
+                    for (int i=jspBeginLineNum-1; i<jspLines.length; i++) {
+                        if (jspLines[i].indexOf(javaLine) != -1) {
+                            // Update jsp line number
+                            this.jspBeginLineNum = i+1;
+                            break;
+                        }
+                    }
+                }
+    
+                // copy out a fragment of JSP to display to the user
+                StringBuffer fragment = new StringBuffer(1024);
+                int startIndex = Math.max(0, this.jspBeginLineNum-1-3);
+                int endIndex = Math.min(
+                        jspLines.length-1, this.jspBeginLineNum-1+3);
+    
+                for (int i=startIndex;i<=endIndex; ++i) {
+                    fragment.append(i+1);
+                    fragment.append(": ");
+                    fragment.append(jspLines[i]);
+                    fragment.append("\n");
+                }
+                jspExtract = fragment.toString();
+    
+            } catch (IOException ioe) {
+                // Can't read files - ignore
+            } finally {
+                if (is != null) {
+                    try {
+                        is.close();
+                    } catch (IOException ioe) {
+                        // Ignore
+                    }
+                }
+                if (fis != null) {
+                    try {
+                        fis.close();
+                    } catch (IOException ioe) {
+                        // Ignore
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Gets the name of the Java source file in which the compilation error
+     * occurred.
+     *
+     * @return Java source file name
+     */
+    public String getJavaFileName() {
+        return this.javaFileName;
+    }
+
+    /**
+     * Gets the compilation error line number.
+     * 
+     * @return Compilation error line number
+     */
+    public int getJavaLineNumber() {
+        return this.javaLineNum;
+    }
+
+    /**
+     * Gets the name of the JSP file from which the Java source file was
+     * generated.
+     *
+     * @return JSP file from which the Java source file was generated.
+     */
+    public String getJspFileName() {
+        return this.jspFileName;
+    }
+
+    /**
+     * Gets the start line number (in the JSP file) of the JSP element
+     * responsible for the compilation error.
+     *
+     * @return Start line number of the JSP element responsible for the
+     * compilation error
+     */
+    public int getJspBeginLineNumber() {
+        return this.jspBeginLineNum;
+    }
+
+    /**
+     * Gets the compilation error message.
+     *
+     * @return Compilation error message
+     */
+    public String getErrorMessage() {
+        return this.errMsg.toString();
+    }
+    
+    /**
+     * Gets the extract of the JSP that corresponds to this message.
+     *
+     * @return Extract of JSP where error occurred
+     */
+    public String getJspExtract() {
+        return this.jspExtract;
+    }
+    
+    /**
+     * Reads a text file from an input stream into a String[]. Used to read in
+     * the JSP and generated Java file when generating error messages.
+     */
+    private String[] readFile(InputStream s) throws IOException {
+        BufferedReader reader = new BufferedReader(new InputStreamReader(s));
+        List lines = new ArrayList();
+        String line;
+
+        while ( (line = reader.readLine()) != null ) {
+            lines.add(line);
+        }
+
+        return (String[]) lines.toArray( new String[lines.size()] );
+    }
+}

Added: struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/compiler/JspConfig.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/compiler/JspConfig.java?rev=819444&view=auto
==============================================================================
--- struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/compiler/JspConfig.java (added)
+++ struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/compiler/JspConfig.java Mon Sep 28 01:55:26 2009
@@ -0,0 +1,531 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.struts2.jasper.compiler;
+
+import java.io.InputStream;
+import java.util.Iterator;
+import java.util.Vector;
+import java.net.URL;
+
+import javax.servlet.ServletContext;
+
+import org.apache.struts2.jasper.JasperException;
+import org.apache.struts2.jasper.xmlparser.ParserUtils;
+import org.apache.struts2.jasper.xmlparser.TreeNode;
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+import org.xml.sax.InputSource;
+
+/**
+ * Handles the jsp-config element in WEB_INF/web.xml.  This is used
+ * for specifying the JSP configuration information on a JSP page
+ *
+ * @author Kin-man Chung
+ * @author Remy Maucherat
+ */
+
+public class JspConfig {
+
+    private static final String WEB_XML = "/WEB-INF/web.xml";
+
+    // Logger
+    private Log log = LogFactory.getLog(JspConfig.class);
+
+    private Vector jspProperties = null;
+    private ServletContext ctxt;
+    private boolean initialized = false;
+
+    private String defaultIsXml = null;		// unspecified
+    private String defaultIsELIgnored = null;	// unspecified
+    private String defaultIsScriptingInvalid = null;
+    private String defaultDeferedSyntaxAllowedAsLiteral = null;
+    private String defaultTrimDirectiveWhitespaces = null;
+    private JspProperty defaultJspProperty;
+
+    public JspConfig(ServletContext ctxt) {
+        this.ctxt = ctxt;
+    }
+
+    private double getVersion(TreeNode webApp) {
+        String v = webApp.findAttribute("version");
+        if (v != null) {
+            try {
+                return Double.parseDouble(v);
+            } catch (NumberFormatException e) {
+            }
+        }
+        return 2.3;
+    }
+
+    private void processWebDotXml(ServletContext ctxt) throws JasperException {
+
+        InputStream is = null;
+
+        try {
+            URL uri = ctxt.getResource(WEB_XML);
+            if (uri == null) {
+                // no web.xml
+                return;
+            }
+
+            is = uri.openStream();
+            InputSource ip = new InputSource(is);
+            ip.setSystemId(uri.toExternalForm()); 
+
+            ParserUtils pu = new ParserUtils();
+            TreeNode webApp = pu.parseXMLDocument(WEB_XML, ip);
+
+            if (webApp == null
+                    || getVersion(webApp) < 2.4) {
+                defaultIsELIgnored = "true";
+                return;
+            }
+            TreeNode jspConfig = webApp.findChild("jsp-config");
+            if (jspConfig == null) {
+                return;
+            }
+
+            jspProperties = new Vector();
+            Iterator jspPropertyList = jspConfig.findChildren("jsp-property-group");
+            while (jspPropertyList.hasNext()) {
+
+                TreeNode element = (TreeNode) jspPropertyList.next();
+                Iterator list = element.findChildren();
+
+                Vector urlPatterns = new Vector();
+                String pageEncoding = null;
+                String scriptingInvalid = null;
+                String elIgnored = null;
+                String isXml = null;
+                Vector includePrelude = new Vector();
+                Vector includeCoda = new Vector();
+                String deferredSyntaxAllowedAsLiteral = null;
+                String trimDirectiveWhitespaces = null;
+
+                while (list.hasNext()) {
+
+                    element = (TreeNode) list.next();
+                    String tname = element.getName();
+
+                    if ("url-pattern".equals(tname))
+                        urlPatterns.addElement( element.getBody() );
+                    else if ("page-encoding".equals(tname))
+                        pageEncoding = element.getBody();
+                    else if ("is-xml".equals(tname))
+                        isXml = element.getBody();
+                    else if ("el-ignored".equals(tname))
+                        elIgnored = element.getBody();
+                    else if ("scripting-invalid".equals(tname))
+                        scriptingInvalid = element.getBody();
+                    else if ("include-prelude".equals(tname))
+                        includePrelude.addElement(element.getBody());
+                    else if ("include-coda".equals(tname))
+                        includeCoda.addElement(element.getBody());
+                    else if ("deferred-syntax-allowed-as-literal".equals(tname))
+                        deferredSyntaxAllowedAsLiteral = element.getBody();
+                    else if ("trim-directive-whitespaces".equals(tname))
+                        trimDirectiveWhitespaces = element.getBody();
+                }
+
+                if (urlPatterns.size() == 0) {
+                    continue;
+                }
+
+                // Add one JspPropertyGroup for each URL Pattern.  This makes
+                // the matching logic easier.
+                for( int p = 0; p < urlPatterns.size(); p++ ) {
+                    String urlPattern = (String)urlPatterns.elementAt( p );
+                    String path = null;
+                    String extension = null;
+
+                    if (urlPattern.indexOf('*') < 0) {
+                        // Exact match
+                        path = urlPattern;
+                    } else {
+                        int i = urlPattern.lastIndexOf('/');
+                        String file;
+                        if (i >= 0) {
+                            path = urlPattern.substring(0,i+1);
+                            file = urlPattern.substring(i+1);
+                        } else {
+                            file = urlPattern;
+                        }
+
+                        // pattern must be "*", or of the form "*.jsp"
+                        if (file.equals("*")) {
+                            extension = "*";
+                        } else if (file.startsWith("*.")) {
+                            extension = file.substring(file.indexOf('.')+1);
+                        }
+
+                        // The url patterns are reconstructed as the follwoing:
+                        // path != null, extension == null:  / or /foo/bar.ext
+                        // path == null, extension != null:  *.ext
+                        // path != null, extension == "*":   /foo/*
+                        boolean isStar = "*".equals(extension);
+                        if ((path == null && (extension == null || isStar))
+                                || (path != null && !isStar)) {
+                            if (log.isWarnEnabled()) {
+                                log.warn(Localizer.getMessage(
+                                        "jsp.warning.bad.urlpattern.propertygroup",
+                                        urlPattern));
+                            }
+                            continue;
+                        }
+                    }
+
+                    JspProperty property = new JspProperty(isXml,
+                            elIgnored,
+                            scriptingInvalid,
+                            pageEncoding,
+                            includePrelude,
+                            includeCoda,
+                            deferredSyntaxAllowedAsLiteral,
+                            trimDirectiveWhitespaces);
+                    JspPropertyGroup propertyGroup =
+                        new JspPropertyGroup(path, extension, property);
+
+                    jspProperties.addElement(propertyGroup);
+                }
+            }
+        } catch (Exception ex) {
+            throw new JasperException(ex);
+        } finally {
+            if (is != null) {
+                try {
+                    is.close();
+                } catch (Throwable t) {}
+            }
+        }
+    }
+
+    private void init() throws JasperException {
+
+        if (!initialized) {
+            processWebDotXml(ctxt);
+            defaultJspProperty = new JspProperty(defaultIsXml,
+                    defaultIsELIgnored,
+                    defaultIsScriptingInvalid,
+                    null, null, null, defaultDeferedSyntaxAllowedAsLiteral, 
+                    defaultTrimDirectiveWhitespaces);
+            initialized = true;
+        }
+    }
+
+    /**
+     * Select the property group that has more restrictive url-pattern.
+     * In case of tie, select the first.
+     */
+    private JspPropertyGroup selectProperty(JspPropertyGroup prev,
+            JspPropertyGroup curr) {
+        if (prev == null) {
+            return curr;
+        }
+        if (prev.getExtension() == null) {
+            // exact match
+            return prev;
+        }
+        if (curr.getExtension() == null) {
+            // exact match
+            return curr;
+        }
+        String prevPath = prev.getPath();
+        String currPath = curr.getPath();
+        if (prevPath == null && currPath == null) {
+            // Both specifies a *.ext, keep the first one
+            return prev;
+        }
+        if (prevPath == null && currPath != null) {
+            return curr;
+        }
+        if (prevPath != null && currPath == null) {
+            return prev;
+        }
+        if (prevPath.length() >= currPath.length()) {
+            return prev;
+        }
+        return curr;
+    }
+
+
+    /**
+     * Find a property that best matches the supplied resource.
+     * @param uri the resource supplied.
+     * @return a JspProperty indicating the best match, or some default.
+     */
+    public JspProperty findJspProperty(String uri) throws JasperException {
+
+        init();
+
+        // JSP Configuration settings do not apply to tag files	    
+        if (jspProperties == null || uri.endsWith(".tag")
+                || uri.endsWith(".tagx")) {
+            return defaultJspProperty;
+        }
+
+        String uriPath = null;
+        int index = uri.lastIndexOf('/');
+        if (index >=0 ) {
+            uriPath = uri.substring(0, index+1);
+        }
+        String uriExtension = null;
+        index = uri.lastIndexOf('.');
+        if (index >=0) {
+            uriExtension = uri.substring(index+1);
+        }
+
+        Vector includePreludes = new Vector();
+        Vector includeCodas = new Vector();
+
+        JspPropertyGroup isXmlMatch = null;
+        JspPropertyGroup elIgnoredMatch = null;
+        JspPropertyGroup scriptingInvalidMatch = null;
+        JspPropertyGroup pageEncodingMatch = null;
+        JspPropertyGroup deferedSyntaxAllowedAsLiteralMatch = null;
+        JspPropertyGroup trimDirectiveWhitespacesMatch = null;
+
+        Iterator iter = jspProperties.iterator();
+        while (iter.hasNext()) {
+
+            JspPropertyGroup jpg = (JspPropertyGroup) iter.next();
+            JspProperty jp = jpg.getJspProperty();
+
+            // (arrays will be the same length)
+            String extension = jpg.getExtension();
+            String path = jpg.getPath();
+
+            if (extension == null) {
+                // exact match pattern: /a/foo.jsp
+                if (!uri.equals(path)) {
+                    // not matched;
+                    continue;
+                }
+            } else {
+                // Matching patterns *.ext or /p/*
+                if (path != null && uriPath != null &&
+                        ! uriPath.startsWith(path)) {
+                    // not matched
+                    continue;
+                }
+                if (!extension.equals("*") &&
+                        !extension.equals(uriExtension)) {
+                    // not matched
+                    continue;
+                }
+            }
+            // We have a match
+            // Add include-preludes and include-codas
+            if (jp.getIncludePrelude() != null) {
+                includePreludes.addAll(jp.getIncludePrelude());
+            }
+            if (jp.getIncludeCoda() != null) {
+                includeCodas.addAll(jp.getIncludeCoda());
+            }
+
+            // If there is a previous match for the same property, remember
+            // the one that is more restrictive.
+            if (jp.isXml() != null) {
+                isXmlMatch = selectProperty(isXmlMatch, jpg);
+            }
+            if (jp.isELIgnored() != null) {
+                elIgnoredMatch = selectProperty(elIgnoredMatch, jpg);
+            }
+            if (jp.isScriptingInvalid() != null) {
+                scriptingInvalidMatch =
+                    selectProperty(scriptingInvalidMatch, jpg);
+            }
+            if (jp.getPageEncoding() != null) {
+                pageEncodingMatch = selectProperty(pageEncodingMatch, jpg);
+            }
+            if (jp.isDeferedSyntaxAllowedAsLiteral() != null) {
+                deferedSyntaxAllowedAsLiteralMatch =
+                    selectProperty(deferedSyntaxAllowedAsLiteralMatch, jpg);
+            }
+            if (jp.isTrimDirectiveWhitespaces() != null) {
+                trimDirectiveWhitespacesMatch =
+                    selectProperty(trimDirectiveWhitespacesMatch, jpg);
+            }
+        }
+
+
+        String isXml = defaultIsXml;
+        String isELIgnored = defaultIsELIgnored;
+        String isScriptingInvalid = defaultIsScriptingInvalid;
+        String pageEncoding = null;
+        String isDeferedSyntaxAllowedAsLiteral = defaultDeferedSyntaxAllowedAsLiteral;
+        String isTrimDirectiveWhitespaces = defaultTrimDirectiveWhitespaces;
+
+        if (isXmlMatch != null) {
+            isXml = isXmlMatch.getJspProperty().isXml();
+        }
+        if (elIgnoredMatch != null) {
+            isELIgnored = elIgnoredMatch.getJspProperty().isELIgnored();
+        }
+        if (scriptingInvalidMatch != null) {
+            isScriptingInvalid =
+                scriptingInvalidMatch.getJspProperty().isScriptingInvalid();
+        }
+        if (pageEncodingMatch != null) {
+            pageEncoding = pageEncodingMatch.getJspProperty().getPageEncoding();
+        }
+        if (deferedSyntaxAllowedAsLiteralMatch != null) {
+            isDeferedSyntaxAllowedAsLiteral =
+                deferedSyntaxAllowedAsLiteralMatch.getJspProperty().isDeferedSyntaxAllowedAsLiteral();
+        }
+        if (trimDirectiveWhitespacesMatch != null) {
+            isTrimDirectiveWhitespaces =
+                trimDirectiveWhitespacesMatch.getJspProperty().isTrimDirectiveWhitespaces();
+        }
+
+        return new JspProperty(isXml, isELIgnored, isScriptingInvalid,
+                pageEncoding, includePreludes, includeCodas, 
+                isDeferedSyntaxAllowedAsLiteral, isTrimDirectiveWhitespaces);
+    }
+
+    /**
+     * To find out if an uri matches an url pattern in jsp config.  If so,
+     * then the uri is a JSP page.  This is used primarily for jspc.
+     */
+    public boolean isJspPage(String uri) throws JasperException {
+
+        init();
+        if (jspProperties == null) {
+            return false;
+        }
+
+        String uriPath = null;
+        int index = uri.lastIndexOf('/');
+        if (index >=0 ) {
+            uriPath = uri.substring(0, index+1);
+        }
+        String uriExtension = null;
+        index = uri.lastIndexOf('.');
+        if (index >=0) {
+            uriExtension = uri.substring(index+1);
+        }
+
+        Iterator iter = jspProperties.iterator();
+        while (iter.hasNext()) {
+
+            JspPropertyGroup jpg = (JspPropertyGroup) iter.next();
+            JspProperty jp = jpg.getJspProperty();
+
+            String extension = jpg.getExtension();
+            String path = jpg.getPath();
+
+            if (extension == null) {
+                if (uri.equals(path)) {
+                    // There is an exact match
+                    return true;
+                }
+            } else {
+                if ((path == null || path.equals(uriPath)) &&
+                        (extension.equals("*") || extension.equals(uriExtension))) {
+                    // Matches *, *.ext, /p/*, or /p/*.ext
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    static class JspPropertyGroup {
+        private String path;
+        private String extension;
+        private JspProperty jspProperty;
+
+        JspPropertyGroup(String path, String extension,
+                JspProperty jspProperty) {
+            this.path = path;
+            this.extension = extension;
+            this.jspProperty = jspProperty;
+        }
+
+        public String getPath() {
+            return path;
+        }
+
+        public String getExtension() {
+            return extension;
+        }
+
+        public JspProperty getJspProperty() {
+            return jspProperty;
+        }
+    }
+
+    static public class JspProperty {
+
+        private String isXml;
+        private String elIgnored;
+        private String scriptingInvalid;
+        private String pageEncoding;
+        private Vector includePrelude;
+        private Vector includeCoda;
+        private String deferedSyntaxAllowedAsLiteral;
+        private String trimDirectiveWhitespaces;
+
+        public JspProperty(String isXml, String elIgnored,
+                String scriptingInvalid, String pageEncoding,
+                Vector includePrelude, Vector includeCoda,
+                String deferedSyntaxAllowedAsLiteral, 
+                String trimDirectiveWhitespaces) {
+
+            this.isXml = isXml;
+            this.elIgnored = elIgnored;
+            this.scriptingInvalid = scriptingInvalid;
+            this.pageEncoding = pageEncoding;
+            this.includePrelude = includePrelude;
+            this.includeCoda = includeCoda;
+            this.deferedSyntaxAllowedAsLiteral = deferedSyntaxAllowedAsLiteral;
+            this.trimDirectiveWhitespaces = trimDirectiveWhitespaces;
+        }
+
+        public String isXml() {
+            return isXml;
+        }
+
+        public String isELIgnored() {
+            return elIgnored;
+        }
+
+        public String isScriptingInvalid() {
+            return scriptingInvalid;
+        }
+
+        public String getPageEncoding() {
+            return pageEncoding;
+        }
+
+        public Vector getIncludePrelude() {
+            return includePrelude;
+        }
+
+        public Vector getIncludeCoda() {
+            return includeCoda;
+        }
+        
+        public String isDeferedSyntaxAllowedAsLiteral() {
+            return deferedSyntaxAllowedAsLiteral;
+        }
+        
+        public String isTrimDirectiveWhitespaces() {
+            return trimDirectiveWhitespaces;
+        }
+    }
+}