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; + } + } +}