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 02:43:39 UTC

svn commit: r819435 [10/23] - in /struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper: ./ compiler/ compiler/tagplugin/ el/ runtime/ security/ servlet/ tagplugins/ tagplugins/jstl/ tagplugins/jstl/core/ util/ xmlparser/

Added: struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/compiler/PageDataImpl.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/compiler/PageDataImpl.java?rev=819435&view=auto
==============================================================================
--- struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/compiler/PageDataImpl.java (added)
+++ struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/compiler/PageDataImpl.java Mon Sep 28 00:43:34 2009
@@ -0,0 +1,711 @@
+/*
+ * 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.jasper.compiler;
+
+import java.io.InputStream;
+import java.io.ByteArrayInputStream;
+import java.io.CharArrayWriter;
+import java.io.UnsupportedEncodingException;
+import java.util.ListIterator;
+import javax.servlet.jsp.tagext.PageData;
+import org.xml.sax.Attributes;
+import org.xml.sax.helpers.AttributesImpl;
+import org.apache.jasper.JasperException;
+
+/**
+ * An implementation of <tt>javax.servlet.jsp.tagext.PageData</tt> which
+ * builds the XML view of a given page.
+ *
+ * The XML view is built in two passes:
+ *
+ * During the first pass, the FirstPassVisitor collects the attributes of the
+ * top-level jsp:root and those of the jsp:root elements of any included
+ * pages, and adds them to the jsp:root element of the XML view.
+ * In addition, any taglib directives are converted into xmlns: attributes and
+ * added to the jsp:root element of the XML view.
+ * This pass ignores any nodes other than JspRoot and TaglibDirective.
+ *
+ * During the second pass, the SecondPassVisitor produces the XML view, using
+ * the combined jsp:root attributes determined in the first pass and any
+ * remaining pages nodes (this pass ignores any JspRoot and TaglibDirective
+ * nodes).
+ *
+ * @author Jan Luehe
+ */
+class PageDataImpl extends PageData implements TagConstants {
+
+    private static final String JSP_VERSION = "2.0";
+    private static final String CDATA_START_SECTION = "<![CDATA[\n";
+    private static final String CDATA_END_SECTION = "]]>\n";
+
+    // string buffer used to build XML view
+    private StringBuffer buf;
+
+    /**
+     * Constructor.
+     *
+     * @param page the page nodes from which to generate the XML view
+     */
+    public PageDataImpl(Node.Nodes page, Compiler compiler)
+	        throws JasperException {
+
+	// First pass
+	FirstPassVisitor firstPass = new FirstPassVisitor(page.getRoot(),
+							  compiler.getPageInfo());
+	page.visit(firstPass);
+
+	// Second pass
+	buf = new StringBuffer();
+	SecondPassVisitor secondPass
+	    = new SecondPassVisitor(page.getRoot(), buf, compiler,
+				    firstPass.getJspIdPrefix());
+	page.visit(secondPass);
+    }
+
+    /**
+     * Returns the input stream of the XML view.
+     *
+     * @return the input stream of the XML view
+     */
+    public InputStream getInputStream() {
+	// Turn StringBuffer into InputStream
+        try {
+            return new ByteArrayInputStream(buf.toString().getBytes("UTF-8"));
+        } catch (UnsupportedEncodingException uee) {
+	    // should never happen
+            throw new RuntimeException(uee.toString());
+        }
+    }
+
+    /*
+     * First-pass Visitor for JspRoot nodes (representing jsp:root elements)
+     * and TablibDirective nodes, ignoring any other nodes.
+     *
+     * The purpose of this Visitor is to collect the attributes of the
+     * top-level jsp:root and those of the jsp:root elements of any included
+     * pages, and add them to the jsp:root element of the XML view.
+     * In addition, this Visitor converts any taglib directives into xmlns:
+     * attributes and adds them to the jsp:root element of the XML view.
+     */
+    static class FirstPassVisitor
+	        extends Node.Visitor implements TagConstants {
+
+	private Node.Root root;
+	private AttributesImpl rootAttrs;
+	private PageInfo pageInfo;
+
+	// Prefix for the 'id' attribute
+	private String jspIdPrefix;
+
+	/*
+	 * Constructor
+	 */
+	public FirstPassVisitor(Node.Root root, PageInfo pageInfo) {
+	    this.root = root;
+	    this.pageInfo = pageInfo;
+	    this.rootAttrs = new AttributesImpl();
+	    this.rootAttrs.addAttribute("", "", "version", "CDATA",
+					JSP_VERSION);
+	    this.jspIdPrefix = "jsp";
+	}
+
+	public void visit(Node.Root n) throws JasperException {
+	    visitBody(n);
+	    if (n == root) {
+		/*
+		 * Top-level page.
+		 *
+		 * Add
+		 *   xmlns:jsp="http://java.sun.com/JSP/Page"
+		 * attribute only if not already present.
+		 */
+		if (!JSP_URI.equals(rootAttrs.getValue("xmlns:jsp"))) {
+		    rootAttrs.addAttribute("", "", "xmlns:jsp", "CDATA",
+					   JSP_URI);
+		}
+
+		if (pageInfo.isJspPrefixHijacked()) {
+		    /*
+		     * 'jsp' prefix has been hijacked, that is, bound to a
+		     * namespace other than the JSP namespace. This means that
+		     * when adding an 'id' attribute to each element, we can't
+		     * use the 'jsp' prefix. Therefore, create a new prefix 
+		     * (one that is unique across the translation unit) for use
+		     * by the 'id' attribute, and bind it to the JSP namespace
+		     */
+		    jspIdPrefix += "jsp";
+		    while (pageInfo.containsPrefix(jspIdPrefix)) {
+			jspIdPrefix += "jsp";
+		    }
+		    rootAttrs.addAttribute("", "", "xmlns:" + jspIdPrefix,
+					   "CDATA", JSP_URI);
+		}
+
+		root.setAttributes(rootAttrs);
+	    }
+	}
+
+	public void visit(Node.JspRoot n) throws JasperException {
+	    addAttributes(n.getTaglibAttributes());
+            addAttributes(n.getNonTaglibXmlnsAttributes());
+	    addAttributes(n.getAttributes());
+
+	    visitBody(n);
+	}
+
+	/*
+	 * Converts taglib directive into "xmlns:..." attribute of jsp:root
+	 * element.
+	 */
+	public void visit(Node.TaglibDirective n) throws JasperException {
+	    Attributes attrs = n.getAttributes();
+	    if (attrs != null) {
+		String qName = "xmlns:" + attrs.getValue("prefix");
+		/*
+		 * According to javadocs of org.xml.sax.helpers.AttributesImpl,
+		 * the addAttribute method does not check to see if the
+		 * specified attribute is already contained in the list: This
+		 * is the application's responsibility!
+		 */
+		if (rootAttrs.getIndex(qName) == -1) {
+		    String location = attrs.getValue("uri");
+		    if (location != null) {
+                        if (location.startsWith("/")) {
+                            location = URN_JSPTLD + location;
+                        }
+			rootAttrs.addAttribute("", "", qName, "CDATA",
+					       location);
+		    } else {
+			location = attrs.getValue("tagdir");
+			rootAttrs.addAttribute("", "", qName, "CDATA",
+					       URN_JSPTAGDIR + location);
+		    }
+		}
+	    }
+	}
+
+	public String getJspIdPrefix() {
+	    return jspIdPrefix;
+	}
+
+	private void addAttributes(Attributes attrs) {
+	    if (attrs != null) {
+		int len = attrs.getLength();
+
+		for (int i=0; i<len; i++) {
+                    String qName = attrs.getQName(i);
+		    if ("version".equals(qName)) {
+			continue;
+		    }
+
+                    // Bugzilla 35252: http://issues.apache.org/bugzilla/show_bug.cgi?id=35252
+                    if(rootAttrs.getIndex(qName) == -1) {
+                        rootAttrs.addAttribute(attrs.getURI(i),
+                                               attrs.getLocalName(i),
+                                               qName,
+                                               attrs.getType(i),
+                                               attrs.getValue(i));
+                    }
+		}
+	    }
+	}
+    }
+
+
+    /*
+     * Second-pass Visitor responsible for producing XML view and assigning
+     * each element a unique jsp:id attribute.
+     */
+    static class SecondPassVisitor extends Node.Visitor
+        	implements TagConstants {
+
+	private Node.Root root;
+	private StringBuffer buf;
+	private Compiler compiler;
+	private String jspIdPrefix;
+	private boolean resetDefaultNS = false;
+
+	// Current value of jsp:id attribute
+	private int jspId;
+
+	/*
+	 * Constructor
+	 */
+	public SecondPassVisitor(Node.Root root, StringBuffer buf,
+				 Compiler compiler, String jspIdPrefix) {
+	    this.root = root;
+	    this.buf = buf;
+	    this.compiler = compiler;
+	    this.jspIdPrefix = jspIdPrefix;
+	}
+
+	/*
+	 * Visits root node.
+	 */
+	public void visit(Node.Root n) throws JasperException {
+	    if (n == this.root) {
+		// top-level page
+		appendXmlProlog();
+		appendTag(n);
+	    } else {
+		boolean resetDefaultNSSave = resetDefaultNS;
+		if (n.isXmlSyntax()) {
+		    resetDefaultNS = true;
+		}
+		visitBody(n);
+		resetDefaultNS = resetDefaultNSSave;
+	    }
+	}
+
+	/*
+	 * Visits jsp:root element of JSP page in XML syntax.
+	 *
+	 * Any nested jsp:root elements (from pages included via an
+	 * include directive) are ignored.
+	 */
+	public void visit(Node.JspRoot n) throws JasperException {
+	    visitBody(n);
+	}
+
+	public void visit(Node.PageDirective n) throws JasperException {
+	    appendPageDirective(n);
+	}
+
+	public void visit(Node.IncludeDirective n) throws JasperException {
+	    // expand in place
+	    visitBody(n);
+	}
+
+	public void visit(Node.Comment n) throws JasperException {
+	    // Comments are ignored in XML view
+	}
+
+	public void visit(Node.Declaration n) throws JasperException {
+	    appendTag(n);
+	}
+
+	public void visit(Node.Expression n) throws JasperException {
+	    appendTag(n);
+	}
+
+	public void visit(Node.Scriptlet n) throws JasperException {
+	    appendTag(n);
+	}
+
+	public void visit(Node.JspElement n) throws JasperException {
+	    appendTag(n);
+	}
+
+	public void visit(Node.ELExpression n) throws JasperException {
+	    if (!n.getRoot().isXmlSyntax()) {
+		buf.append("<").append(JSP_TEXT_ACTION);
+		buf.append(" ");
+	        buf.append(jspIdPrefix);
+		buf.append(":id=\"");
+		buf.append(jspId++).append("\">");
+	    }
+	    buf.append("${");
+            buf.append(JspUtil.escapeXml(n.getText()));
+	    buf.append("}");
+	    if (!n.getRoot().isXmlSyntax()) {
+		buf.append(JSP_TEXT_ACTION_END);
+	    }
+	    buf.append("\n");
+	}
+
+	public void visit(Node.IncludeAction n) throws JasperException {
+	    appendTag(n);
+	}
+    
+	public void visit(Node.ForwardAction n) throws JasperException {
+	    appendTag(n);
+	}
+
+	public void visit(Node.GetProperty n) throws JasperException {
+	    appendTag(n);
+	}
+
+	public void visit(Node.SetProperty n) throws JasperException {
+	    appendTag(n);
+	}
+
+	public void visit(Node.ParamAction n) throws JasperException {
+	    appendTag(n);
+	}
+
+	public void visit(Node.ParamsAction n) throws JasperException {
+	    appendTag(n);
+	}
+
+	public void visit(Node.FallBackAction n) throws JasperException {
+	    appendTag(n);
+	}
+
+	public void visit(Node.UseBean n) throws JasperException {
+	    appendTag(n);
+	}
+	
+	public void visit(Node.PlugIn n) throws JasperException {
+	    appendTag(n);
+	}
+
+        public void visit(Node.NamedAttribute n) throws JasperException {
+            appendTag(n);
+        }
+        
+        public void visit(Node.JspBody n) throws JasperException {
+            appendTag(n);
+        }
+
+	public void visit(Node.CustomTag n) throws JasperException {
+	    boolean resetDefaultNSSave = resetDefaultNS;
+	    appendTag(n, resetDefaultNS);
+	    resetDefaultNS = resetDefaultNSSave;
+	}
+
+	public void visit(Node.UninterpretedTag n) throws JasperException {
+	    boolean resetDefaultNSSave = resetDefaultNS;
+	    appendTag(n, resetDefaultNS);
+	    resetDefaultNS = resetDefaultNSSave;
+	}
+
+	public void visit(Node.JspText n) throws JasperException {
+	    appendTag(n);
+	}
+
+	public void visit(Node.DoBodyAction n) throws JasperException {
+	    appendTag(n);
+	}
+
+        public void visit(Node.InvokeAction n) throws JasperException {
+	    appendTag(n);
+	}
+
+	public void visit(Node.TagDirective n) throws JasperException {
+	    appendTagDirective(n);
+	}
+
+	public void visit(Node.AttributeDirective n) throws JasperException {
+	    appendTag(n);
+	}
+
+	public void visit(Node.VariableDirective n) throws JasperException {
+	    appendTag(n);
+	}
+        
+	public void visit(Node.TemplateText n) throws JasperException {
+	    /*
+	     * If the template text came from a JSP page written in JSP syntax,
+	     * create a jsp:text element for it (JSP 5.3.2).
+	     */
+	    appendText(n.getText(), !n.getRoot().isXmlSyntax());
+	}
+
+	/*
+	 * Appends the given tag, including its body, to the XML view.
+	 */
+	private void appendTag(Node n) throws JasperException {
+	    appendTag(n, false);
+	}
+
+	/*
+	 * Appends the given tag, including its body, to the XML view,
+	 * and optionally reset default namespace to "", if none specified.
+	 */
+	private void appendTag(Node n, boolean addDefaultNS)
+		throws JasperException {
+
+	    Node.Nodes body = n.getBody();
+	    String text = n.getText();
+
+	    buf.append("<").append(n.getQName());
+	    buf.append("\n");
+
+	    printAttributes(n, addDefaultNS);
+	    buf.append("  ").append(jspIdPrefix).append(":id").append("=\"");
+	    buf.append(jspId++).append("\"\n");
+
+	    if (ROOT_ACTION.equals(n.getLocalName()) || body != null
+		        || text != null) {
+		buf.append(">\n");
+		if (ROOT_ACTION.equals(n.getLocalName())) {
+		    if (compiler.getCompilationContext().isTagFile()) {
+			appendTagDirective();
+		    } else {
+			appendPageDirective();
+		    }
+		}
+		if (body != null) {
+		    body.visit(this);
+		} else {
+		    appendText(text, false);
+		}
+		buf.append("</" + n.getQName() + ">\n");
+	    } else {
+		buf.append("/>\n");
+	    }
+	}
+
+	/*
+	 * Appends the page directive with the given attributes to the XML
+	 * view.
+	 *
+	 * Since the import attribute of the page directive is the only page
+	 * attribute that is allowed to appear multiple times within the same
+	 * document, and since XML allows only single-value attributes,
+	 * the values of multiple import attributes must be combined into one,
+	 * separated by comma.
+	 *
+	 * If the given page directive contains just 'contentType' and/or
+	 * 'pageEncoding' attributes, we ignore it, as we've already appended
+	 * a page directive containing just these two attributes.
+	 */
+	private void appendPageDirective(Node.PageDirective n) {
+	    boolean append = false;
+	    Attributes attrs = n.getAttributes();
+	    int len = (attrs == null) ? 0 : attrs.getLength();
+	    for (int i=0; i<len; i++) {
+		String attrName = attrs.getQName(i);
+		if (!"pageEncoding".equals(attrName)
+		        && !"contentType".equals(attrName)) {
+		    append = true;
+		    break;
+		}
+	    }
+	    if (!append) {
+		return;
+	    }
+
+	    buf.append("<").append(n.getQName());
+	    buf.append("\n");
+
+	    // append jsp:id
+	    buf.append("  ").append(jspIdPrefix).append(":id").append("=\"");
+	    buf.append(jspId++).append("\"\n");
+
+	    // append remaining attributes
+	    for (int i=0; i<len; i++) {
+		String attrName = attrs.getQName(i);
+		if ("import".equals(attrName) || "contentType".equals(attrName)
+		        || "pageEncoding".equals(attrName)) {
+		    /*
+		     * Page directive's 'import' attribute is considered
+		     * further down, and its 'pageEncoding' and 'contentType'
+		     * attributes are ignored, since we've already appended
+		     * a new page directive containing just these two
+		     * attributes
+		     */
+		    continue;
+		}
+		String value = attrs.getValue(i);
+		buf.append("  ").append(attrName).append("=\"");
+		buf.append(JspUtil.getExprInXml(value)).append("\"\n");
+	    }
+	    if (n.getImports().size() > 0) {
+		// Concatenate names of imported classes/packages
+		boolean first = true;
+		ListIterator iter = n.getImports().listIterator();
+		while (iter.hasNext()) {
+		    if (first) {
+			first = false;
+			buf.append("  import=\"");
+		    } else {
+			buf.append(",");
+		    }
+		    buf.append(JspUtil.getExprInXml((String) iter.next()));
+		}
+		buf.append("\"\n");
+	    }
+	    buf.append("/>\n");
+	}
+
+	/*
+	 * Appends a page directive with 'pageEncoding' and 'contentType'
+	 * attributes.
+	 *
+	 * The value of the 'pageEncoding' attribute is hard-coded
+	 * to UTF-8, whereas the value of the 'contentType' attribute, which
+	 * is identical to what the container will pass to
+	 * ServletResponse.setContentType(), is derived from the pageInfo.
+	 */
+	private void appendPageDirective() {
+	    buf.append("<").append(JSP_PAGE_DIRECTIVE_ACTION);
+	    buf.append("\n");
+
+	    // append jsp:id
+	    buf.append("  ").append(jspIdPrefix).append(":id").append("=\"");
+	    buf.append(jspId++).append("\"\n");
+	    buf.append("  ").append("pageEncoding").append("=\"UTF-8\"\n");
+	    buf.append("  ").append("contentType").append("=\"");
+	    buf.append(compiler.getPageInfo().getContentType()).append("\"\n");
+	    buf.append("/>\n");	    
+	}
+
+	/*
+	 * Appends the tag directive with the given attributes to the XML
+	 * view.
+	 *
+	 * If the given tag directive contains just a 'pageEncoding'
+	 * attributes, we ignore it, as we've already appended
+	 * a tag directive containing just this attributes.
+	 */
+	private void appendTagDirective(Node.TagDirective n)
+	        throws JasperException {
+
+	    boolean append = false;
+	    Attributes attrs = n.getAttributes();
+	    int len = (attrs == null) ? 0 : attrs.getLength();
+	    for (int i=0; i<len; i++) {
+		String attrName = attrs.getQName(i);
+		if (!"pageEncoding".equals(attrName)) {
+		    append = true;
+		    break;
+		}
+	    }
+	    if (!append) {
+		return;
+	    }
+
+	    appendTag(n);
+	}
+
+	/*
+	 * Appends a tag directive containing a single 'pageEncoding'
+	 * attribute whose value is hard-coded to UTF-8.
+	 */
+	private void appendTagDirective() {
+	    buf.append("<").append(JSP_TAG_DIRECTIVE_ACTION);
+	    buf.append("\n");
+
+	    // append jsp:id
+	    buf.append("  ").append(jspIdPrefix).append(":id").append("=\"");
+	    buf.append(jspId++).append("\"\n");
+	    buf.append("  ").append("pageEncoding").append("=\"UTF-8\"\n");
+	    buf.append("/>\n");	    
+	}
+
+	private void appendText(String text, boolean createJspTextElement) {
+	    if (createJspTextElement) {
+		buf.append("<").append(JSP_TEXT_ACTION);
+		buf.append("\n");
+
+		// append jsp:id
+		buf.append("  ").append(jspIdPrefix).append(":id").append("=\"");
+		buf.append(jspId++).append("\"\n");
+		buf.append(">\n");
+
+		appendCDATA(text);
+		buf.append(JSP_TEXT_ACTION_END);
+		buf.append("\n");
+	    } else {
+		appendCDATA(text);
+	    }
+	}
+	
+	/*
+	 * Appends the given text as a CDATA section to the XML view, unless
+	 * the text has already been marked as CDATA.
+	 */
+	private void appendCDATA(String text) {
+	    buf.append(CDATA_START_SECTION);
+	    buf.append(escapeCDATA(text));
+	    buf.append(CDATA_END_SECTION);
+	}
+
+	/*
+	 * Escapes any occurrences of "]]>" (by replacing them with "]]&gt;")
+	 * within the given text, so it can be included in a CDATA section.
+	 */
+	private String escapeCDATA(String text) {
+            if( text==null ) return "";
+	    int len = text.length();
+	    CharArrayWriter result = new CharArrayWriter(len);
+	    for (int i=0; i<len; i++) {
+		if (((i+2) < len)
+		        && (text.charAt(i) == ']')
+		        && (text.charAt(i+1) == ']')
+		        && (text.charAt(i+2) == '>')) {
+		    // match found
+		    result.write(']');
+		    result.write(']');
+		    result.write('&');
+		    result.write('g');
+		    result.write('t');
+		    result.write(';');
+		    i += 2;
+		} else {
+		    result.write(text.charAt(i));
+		}
+	    }
+	    return result.toString();
+	}
+
+	/*
+	 * Appends the attributes of the given Node to the XML view.
+	 */
+	private void printAttributes(Node n, boolean addDefaultNS) {
+
+	    /*
+	     * Append "xmlns" attributes that represent tag libraries
+	     */
+	    Attributes attrs = n.getTaglibAttributes();
+	    int len = (attrs == null) ? 0 : attrs.getLength();
+	    for (int i=0; i<len; i++) {
+		String name = attrs.getQName(i);
+		String value = attrs.getValue(i);
+		buf.append("  ").append(name).append("=\"").append(value).append("\"\n");
+	    }
+
+	    /*
+	     * Append "xmlns" attributes that do not represent tag libraries
+	     */
+	    attrs = n.getNonTaglibXmlnsAttributes();
+	    len = (attrs == null) ? 0 : attrs.getLength();
+	    boolean defaultNSSeen = false;
+	    for (int i=0; i<len; i++) {
+		String name = attrs.getQName(i);
+		String value = attrs.getValue(i);
+		buf.append("  ").append(name).append("=\"").append(value).append("\"\n");
+		defaultNSSeen |= "xmlns".equals(name);
+	    }
+	    if (addDefaultNS && !defaultNSSeen) {
+		buf.append("  xmlns=\"\"\n");
+	    }
+	    resetDefaultNS = false;
+
+	    /*
+	     * Append all other attributes
+	     */
+	    attrs = n.getAttributes();
+	    len = (attrs == null) ? 0 : attrs.getLength();
+	    for (int i=0; i<len; i++) {
+		String name = attrs.getQName(i);
+		String value = attrs.getValue(i);
+		buf.append("  ").append(name).append("=\"");
+		buf.append(JspUtil.getExprInXml(value)).append("\"\n");
+	    }
+	}
+
+	/*
+	 * Appends XML prolog with encoding declaration.
+	 */
+	private void appendXmlProlog() {
+	    buf.append("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n");
+	}
+    }
+}
+

Added: struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/compiler/PageInfo.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/compiler/PageInfo.java?rev=819435&view=auto
==============================================================================
--- struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/compiler/PageInfo.java (added)
+++ struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/compiler/PageInfo.java Mon Sep 28 00:43:34 2009
@@ -0,0 +1,711 @@
+/*
+ * 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.jasper.compiler;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Vector;
+
+import org.apache.el.ExpressionFactoryImpl;
+import org.apache.jasper.Constants;
+import org.apache.jasper.JasperException;
+
+import javax.el.ExpressionFactory;
+import javax.servlet.jsp.tagext.TagLibraryInfo;
+
+/**
+ * A repository for various info about the translation unit under compilation.
+ *
+ * @author Kin-man Chung
+ */
+
+class PageInfo {
+
+    private Vector imports;
+    private Vector dependants;
+
+    private BeanRepository beanRepository;
+    private HashMap taglibsMap;
+    private HashMap jspPrefixMapper;
+    private HashMap xmlPrefixMapper;
+    private HashMap nonCustomTagPrefixMap;
+    private String jspFile;
+    private String defaultLanguage = "java";
+    private String language;
+    private String defaultExtends = Constants.JSP_SERVLET_BASE;
+    private String xtends;
+    private String contentType = null;
+    private String session;
+    private boolean isSession = true;
+    private String bufferValue;
+    private int buffer = 8*1024;    // XXX confirm
+    private String autoFlush;
+    private boolean isAutoFlush = true;
+    private String isThreadSafeValue;
+    private boolean isThreadSafe = true;
+    private String isErrorPageValue;
+    private boolean isErrorPage = false;
+    private String errorPage = null;
+    private String info;
+
+    private boolean scriptless = false;
+    private boolean scriptingInvalid = false;
+    
+    private String isELIgnoredValue;
+    private boolean isELIgnored = false;
+    
+    // JSP 2.1
+    private String deferredSyntaxAllowedAsLiteralValue;
+    private boolean deferredSyntaxAllowedAsLiteral = false;
+    private ExpressionFactory expressionFactory = new ExpressionFactoryImpl();
+    private String trimDirectiveWhitespacesValue;
+    private boolean trimDirectiveWhitespaces = false;
+    
+    private String omitXmlDecl = null;
+    private String doctypeName = null;
+    private String doctypePublic = null;
+    private String doctypeSystem = null;
+
+    private boolean isJspPrefixHijacked;
+
+    // Set of all element and attribute prefixes used in this translation unit
+    private HashSet prefixes;
+
+    private boolean hasJspRoot = false;
+    private Vector includePrelude;
+    private Vector includeCoda;
+    private Vector pluginDcls;      // Id's for tagplugin declarations
+
+
+    PageInfo(BeanRepository beanRepository, String jspFile) {
+
+        this.jspFile = jspFile;
+        this.beanRepository = beanRepository;
+        this.taglibsMap = new HashMap();
+        this.jspPrefixMapper = new HashMap();
+        this.xmlPrefixMapper = new HashMap();
+        this.nonCustomTagPrefixMap = new HashMap();
+        this.imports = new Vector();
+        this.dependants = new Vector();
+        this.includePrelude = new Vector();
+        this.includeCoda = new Vector();
+        this.pluginDcls = new Vector();
+        this.prefixes = new HashSet();
+
+        // Enter standard imports
+        for(int i = 0; i < Constants.STANDARD_IMPORTS.length; i++)
+            imports.add(Constants.STANDARD_IMPORTS[i]);
+    }
+
+    /**
+     * Check if the plugin ID has been previously declared.  Make a not
+     * that this Id is now declared.
+     * @return true if Id has been declared.
+     */
+    public boolean isPluginDeclared(String id) {
+        if (pluginDcls.contains(id))
+            return true;
+        pluginDcls.add(id);
+        return false;
+    }
+
+    public void addImports(List imports) {
+        this.imports.addAll(imports);
+    }
+
+    public void addImport(String imp) {
+        this.imports.add(imp);
+    }
+
+    public List getImports() {
+        return imports;
+    }
+
+    public String getJspFile() {
+        return jspFile;
+    }
+
+    public void addDependant(String d) {
+        if (!dependants.contains(d) && !jspFile.equals(d))
+                dependants.add(d);
+    }
+
+    public List getDependants() {
+        return dependants;
+    }
+
+    public BeanRepository getBeanRepository() {
+        return beanRepository;
+    }
+
+    public void setScriptless(boolean s) {
+        scriptless = s;
+    }
+
+    public boolean isScriptless() {
+        return scriptless;
+    }
+
+    public void setScriptingInvalid(boolean s) {
+        scriptingInvalid = s;
+    }
+
+    public boolean isScriptingInvalid() {
+        return scriptingInvalid;
+    }
+
+    public List getIncludePrelude() {
+        return includePrelude;
+    }
+
+    public void setIncludePrelude(Vector prelude) {
+        includePrelude = prelude;
+    }
+
+    public List getIncludeCoda() {
+        return includeCoda;
+    }
+
+    public void setIncludeCoda(Vector coda) {
+        includeCoda = coda;
+    }
+
+    public void setHasJspRoot(boolean s) {
+        hasJspRoot = s;
+    }
+
+    public boolean hasJspRoot() {
+        return hasJspRoot;
+    }
+
+    public String getOmitXmlDecl() {
+        return omitXmlDecl;
+    }
+
+    public void setOmitXmlDecl(String omit) {
+        omitXmlDecl = omit;
+    }
+
+    public String getDoctypeName() {
+        return doctypeName;
+    }
+
+    public void setDoctypeName(String doctypeName) {
+        this.doctypeName = doctypeName;
+    }
+
+    public String getDoctypeSystem() {
+        return doctypeSystem;
+    }
+
+    public void setDoctypeSystem(String doctypeSystem) {
+        this.doctypeSystem = doctypeSystem;
+    }
+
+    public String getDoctypePublic() {
+        return doctypePublic;
+    }
+
+    public void setDoctypePublic(String doctypePublic) {
+        this.doctypePublic = doctypePublic;
+    }
+
+    /* Tag library and XML namespace management methods */
+
+    public void setIsJspPrefixHijacked(boolean isHijacked) {
+        isJspPrefixHijacked = isHijacked;
+    }
+
+    public boolean isJspPrefixHijacked() {
+        return isJspPrefixHijacked;
+    }
+
+    /*
+     * Adds the given prefix to the set of prefixes of this translation unit.
+     *
+     * @param prefix The prefix to add
+     */
+    public void addPrefix(String prefix) {
+        prefixes.add(prefix);
+    }
+
+    /*
+     * Checks to see if this translation unit contains the given prefix.
+     *
+     * @param prefix The prefix to check
+     *
+     * @return true if this translation unit contains the given prefix, false
+     * otherwise
+     */
+    public boolean containsPrefix(String prefix) {
+        return prefixes.contains(prefix);
+    }
+
+    /*
+     * Maps the given URI to the given tag library.
+     *
+     * @param uri The URI to map
+     * @param info The tag library to be associated with the given URI
+     */
+    public void addTaglib(String uri, TagLibraryInfo info) {
+        taglibsMap.put(uri, info);
+    }
+
+    /*
+     * Gets the tag library corresponding to the given URI.
+     *
+     * @return Tag library corresponding to the given URI
+     */
+    public TagLibraryInfo getTaglib(String uri) {
+        return (TagLibraryInfo) taglibsMap.get(uri);
+    }
+
+    /*
+     * Gets the collection of tag libraries that are associated with a URI
+     *
+     * @return Collection of tag libraries that are associated with a URI
+     */
+    public Collection getTaglibs() {
+        return taglibsMap.values();
+    }
+
+    /*
+     * Checks to see if the given URI is mapped to a tag library.
+     *
+     * @param uri The URI to map
+     *
+     * @return true if the given URI is mapped to a tag library, false
+     * otherwise
+     */
+    public boolean hasTaglib(String uri) {
+        return taglibsMap.containsKey(uri);
+    }
+
+    /*
+     * Maps the given prefix to the given URI.
+     *
+     * @param prefix The prefix to map
+     * @param uri The URI to be associated with the given prefix
+     */
+    public void addPrefixMapping(String prefix, String uri) {
+        jspPrefixMapper.put(prefix, uri);
+    }
+
+    /*
+     * Pushes the given URI onto the stack of URIs to which the given prefix
+     * is mapped.
+     *
+     * @param prefix The prefix whose stack of URIs is to be pushed
+     * @param uri The URI to be pushed onto the stack
+     */
+    public void pushPrefixMapping(String prefix, String uri) {
+        LinkedList stack = (LinkedList) xmlPrefixMapper.get(prefix);
+        if (stack == null) {
+            stack = new LinkedList();
+            xmlPrefixMapper.put(prefix, stack);
+        }
+        stack.addFirst(uri);
+    }
+
+    /*
+     * Removes the URI at the top of the stack of URIs to which the given
+     * prefix is mapped.
+     *
+     * @param prefix The prefix whose stack of URIs is to be popped
+     */
+    public void popPrefixMapping(String prefix) {
+        LinkedList stack = (LinkedList) xmlPrefixMapper.get(prefix);
+        if (stack == null || stack.size() == 0) {
+            // XXX throw new Exception("XXX");
+        }
+        stack.removeFirst();
+    }
+
+    /*
+     * Returns the URI to which the given prefix maps.
+     *
+     * @param prefix The prefix whose URI is sought
+     *
+     * @return The URI to which the given prefix maps
+     */
+    public String getURI(String prefix) {
+
+        String uri = null;
+
+        LinkedList stack = (LinkedList) xmlPrefixMapper.get(prefix);
+        if (stack == null || stack.size() == 0) {
+            uri = (String) jspPrefixMapper.get(prefix);
+        } else {
+            uri = (String) stack.getFirst();
+        }
+
+        return uri;
+    }
+
+
+    /* Page/Tag directive attributes */
+
+    /*
+     * language
+     */
+    public void setLanguage(String value, Node n, ErrorDispatcher err,
+                boolean pagedir)
+        throws JasperException {
+
+        if (!"java".equalsIgnoreCase(value)) {
+            if (pagedir)
+                err.jspError(n, "jsp.error.page.language.nonjava");
+            else
+                err.jspError(n, "jsp.error.tag.language.nonjava");
+        }
+
+        language = value;
+    }
+
+    public String getLanguage(boolean useDefault) {
+        return (language == null && useDefault ? defaultLanguage : language);
+    }
+
+    public String getLanguage() {
+        return getLanguage(true);
+    }
+
+
+    /*
+     * extends
+     */
+    public void setExtends(String value, Node.PageDirective n) {
+
+        xtends = value;
+
+        /*
+         * If page superclass is top level class (i.e. not in a package)
+         * explicitly import it. If this is not done, the compiler will assume
+         * the extended class is in the same pkg as the generated servlet.
+         */
+        if (value.indexOf('.') < 0)
+            n.addImport(value);
+    }
+
+    /**
+     * Gets the value of the 'extends' page directive attribute.
+     *
+     * @param useDefault TRUE if the default
+     * (org.apache.jasper.runtime.HttpJspBase) should be returned if this
+     * attribute has not been set, FALSE otherwise
+     *
+     * @return The value of the 'extends' page directive attribute, or the
+     * default (org.apache.jasper.runtime.HttpJspBase) if this attribute has
+     * not been set and useDefault is TRUE
+     */
+    public String getExtends(boolean useDefault) {
+        return (xtends == null && useDefault ? defaultExtends : xtends);
+    }
+
+    /**
+     * Gets the value of the 'extends' page directive attribute.
+     *
+     * @return The value of the 'extends' page directive attribute, or the
+     * default (org.apache.jasper.runtime.HttpJspBase) if this attribute has
+     * not been set
+     */
+    public String getExtends() {
+        return getExtends(true);
+    }
+
+
+    /*
+     * contentType
+     */
+    public void setContentType(String value) {
+        contentType = value;
+    }
+
+    public String getContentType() {
+        return contentType;
+    }
+
+
+    /*
+     * buffer
+     */
+    public void setBufferValue(String value, Node n, ErrorDispatcher err)
+        throws JasperException {
+
+        if ("none".equalsIgnoreCase(value))
+            buffer = 0;
+        else {
+            if (value == null || !value.endsWith("kb"))
+                err.jspError(n, "jsp.error.page.invalid.buffer");
+            try {
+                Integer k = new Integer(value.substring(0, value.length()-2));
+                buffer = k.intValue() * 1024;
+            } catch (NumberFormatException e) {
+                err.jspError(n, "jsp.error.page.invalid.buffer");
+            }
+        }
+
+        bufferValue = value;
+    }
+
+    public String getBufferValue() {
+        return bufferValue;
+    }
+
+    public int getBuffer() {
+        return buffer;
+    }
+
+
+    /*
+     * session
+     */
+    public void setSession(String value, Node n, ErrorDispatcher err)
+        throws JasperException {
+
+        if ("true".equalsIgnoreCase(value))
+            isSession = true;
+        else if ("false".equalsIgnoreCase(value))
+            isSession = false;
+        else
+            err.jspError(n, "jsp.error.page.invalid.session");
+
+        session = value;
+    }
+
+    public String getSession() {
+        return session;
+    }
+
+    public boolean isSession() {
+        return isSession;
+    }
+
+
+    /*
+     * autoFlush
+     */
+    public void setAutoFlush(String value, Node n, ErrorDispatcher err)
+        throws JasperException {
+
+        if ("true".equalsIgnoreCase(value))
+            isAutoFlush = true;
+        else if ("false".equalsIgnoreCase(value))
+            isAutoFlush = false;
+        else
+            err.jspError(n, "jsp.error.autoFlush.invalid");
+
+        autoFlush = value;
+    }
+
+    public String getAutoFlush() {
+        return autoFlush;
+    }
+
+    public boolean isAutoFlush() {
+        return isAutoFlush;
+    }
+
+
+    /*
+     * isThreadSafe
+     */
+    public void setIsThreadSafe(String value, Node n, ErrorDispatcher err)
+        throws JasperException {
+
+        if ("true".equalsIgnoreCase(value))
+            isThreadSafe = true;
+        else if ("false".equalsIgnoreCase(value))
+            isThreadSafe = false;
+        else
+            err.jspError(n, "jsp.error.page.invalid.isthreadsafe");
+
+        isThreadSafeValue = value;
+    }
+
+    public String getIsThreadSafe() {
+        return isThreadSafeValue;
+    }
+
+    public boolean isThreadSafe() {
+        return isThreadSafe;
+    }
+
+
+    /*
+     * info
+     */
+    public void setInfo(String value) {
+        info = value;
+    }
+
+    public String getInfo() {
+        return info;
+    }
+
+
+    /*
+     * errorPage
+     */
+    public void setErrorPage(String value) {
+        errorPage = value;
+    }
+
+    public String getErrorPage() {
+        return errorPage;
+    }
+
+
+    /*
+     * isErrorPage
+     */
+    public void setIsErrorPage(String value, Node n, ErrorDispatcher err)
+        throws JasperException {
+
+        if ("true".equalsIgnoreCase(value))
+            isErrorPage = true;
+        else if ("false".equalsIgnoreCase(value))
+            isErrorPage = false;
+        else
+            err.jspError(n, "jsp.error.page.invalid.iserrorpage");
+
+        isErrorPageValue = value;
+    }
+
+    public String getIsErrorPage() {
+        return isErrorPageValue;
+    }
+
+    public boolean isErrorPage() {
+        return isErrorPage;
+    }
+
+
+    /*
+     * isELIgnored
+     */
+    public void setIsELIgnored(String value, Node n, ErrorDispatcher err,
+                   boolean pagedir)
+        throws JasperException {
+
+        if ("true".equalsIgnoreCase(value))
+            isELIgnored = true;
+        else if ("false".equalsIgnoreCase(value))
+            isELIgnored = false;
+        else {
+            if (pagedir)
+                err.jspError(n, "jsp.error.page.invalid.iselignored");
+            else
+                err.jspError(n, "jsp.error.tag.invalid.iselignored");
+        }
+
+        isELIgnoredValue = value;
+    }
+    
+    /*
+     * deferredSyntaxAllowedAsLiteral
+     */
+    public void setDeferredSyntaxAllowedAsLiteral(String value, Node n, ErrorDispatcher err,
+                   boolean pagedir)
+        throws JasperException {
+
+        if ("true".equalsIgnoreCase(value))
+            deferredSyntaxAllowedAsLiteral = true;
+        else if ("false".equalsIgnoreCase(value))
+            deferredSyntaxAllowedAsLiteral = false;
+        else {
+            if (pagedir)
+                err.jspError(n, "jsp.error.page.invalid.deferredsyntaxallowedasliteral");
+            else
+                err.jspError(n, "jsp.error.tag.invalid.deferredsyntaxallowedasliteral");
+        }
+
+        deferredSyntaxAllowedAsLiteralValue = value;
+    }
+    
+    /*
+     * trimDirectiveWhitespaces
+     */
+    public void setTrimDirectiveWhitespaces(String value, Node n, ErrorDispatcher err,
+                   boolean pagedir)
+        throws JasperException {
+
+        if ("true".equalsIgnoreCase(value))
+            trimDirectiveWhitespaces = true;
+        else if ("false".equalsIgnoreCase(value))
+            trimDirectiveWhitespaces = false;
+        else {
+            if (pagedir)
+                err.jspError(n, "jsp.error.page.invalid.trimdirectivewhitespaces");
+            else
+                err.jspError(n, "jsp.error.tag.invalid.trimdirectivewhitespaces");
+        }
+
+        trimDirectiveWhitespacesValue = value;
+    }
+
+    public void setELIgnored(boolean s) {
+        isELIgnored = s;
+    }
+
+    public String getIsELIgnored() {
+        return isELIgnoredValue;
+    }
+
+    public boolean isELIgnored() {
+        return isELIgnored;
+    }
+
+    public void putNonCustomTagPrefix(String prefix, Mark where) {
+        nonCustomTagPrefixMap.put(prefix, where);
+    }
+
+    public Mark getNonCustomTagPrefix(String prefix) {
+        return (Mark) nonCustomTagPrefixMap.get(prefix);
+    }
+    
+    public String getDeferredSyntaxAllowedAsLiteral() {
+        return deferredSyntaxAllowedAsLiteralValue;
+    }
+
+    public boolean isDeferredSyntaxAllowedAsLiteral() {
+        return deferredSyntaxAllowedAsLiteral;
+    }
+
+    public void setDeferredSyntaxAllowedAsLiteral(boolean isELDeferred) {
+        this.deferredSyntaxAllowedAsLiteral = isELDeferred;
+    }
+
+    public ExpressionFactory getExpressionFactory() {
+        return expressionFactory;
+    }
+
+    public String getTrimDirectiveWhitespaces() {
+        return trimDirectiveWhitespacesValue;
+    }
+
+    public boolean isTrimDirectiveWhitespaces() {
+        return trimDirectiveWhitespaces;
+    }
+
+    public void setTrimDirectiveWhitespaces(boolean trimDirectiveWhitespaces) {
+        this.trimDirectiveWhitespaces = trimDirectiveWhitespaces;
+    }
+}