org.apache.jasper.compiler.PageDataImpl Maven / Gradle / Ivy
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 1997-2011 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can
* obtain a copy of the License at
* https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
* Copyright 2004 The Apache Software Foundation
*
* Licensed 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.nio.charset.Charset;
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 javax.servlet.jsp.tagext.PageData 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 = "\n";
private static final Charset CHARSET_UTF8 = Charset.forName("UTF-8");
// string buffer used to build XML view
private StringBuilder 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(),
compiler.getErrorDispatcher());
page.visit(firstPass);
// Second pass
buf = new StringBuilder();
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 StringBuilder into InputStream
return new ByteArrayInputStream(buf.toString().getBytes(CHARSET_UTF8));
}
/*
* 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;
private ErrorDispatcher err;
/*
* Constructor
*/
public FirstPassVisitor(Node.Root root, PageInfo pageInfo,
ErrorDispatcher err) {
this.root = root;
this.pageInfo = pageInfo;
this.err = err;
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 {
addRootAttributes(n.getTaglibAttributes());
addRootAttributes(n.getNonTaglibXmlnsAttributes());
addRootAttributes(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 addRootAttributes(Attributes attrs)
throws JasperException {
if (attrs != null) {
int len = attrs.getLength();
for (int i=0; i");
}
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 {
n.setJspId(jspId);
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 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 \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 "]]>")
* 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')) {
// 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\n");
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy