📄 pagedataimpl.java
字号:
/*
* 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);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -