/*
* Copyright (c) 1998-2011 Caucho Technology -- all rights reserved
*
* This file is part of Resin(R) Open Source
*
* Each copy or derived work must preserve the copyright notice and this
* notice unmodified.
*
* Resin Open Source is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Resin Open Source is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
* of NON-INFRINGEMENT. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with Resin Open Source; if not, write to the
* Free SoftwareFoundation, Inc.
* 59 Temple Place, Suite 330
* Boston, MA 02111-1307 USA
*
* @author Scott Ferguson
*/
package com.caucho.jsp.java;
import com.caucho.VersionFactory;
import com.caucho.config.types.Signature;
import com.caucho.jsp.JspParseException;
import com.caucho.jsp.ParseTagManager;
import com.caucho.jsp.TempTagInfo;
import com.caucho.jsp.cfg.TldAttribute;
import com.caucho.jsp.cfg.TldTag;
import com.caucho.jsp.cfg.TldVariable;
import com.caucho.util.L10N;
import javax.servlet.jsp.tagext.TagInfo;
import javax.servlet.jsp.tagext.TagLibraryInfo;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Generates JSP code. JavaGenerator, JavaScriptGenerator, and
* StaticGenerator specialize the JspGenerator for language-specific
* requirements.
*
* <p>JspParser parses the JSP file into an XML-DOM tree. JspGenerator
* generates code from that tree.
*/
public class JavaTagGenerator extends JavaJspGenerator {
static final L10N L = new L10N(JavaTagGenerator.class);
static final Logger log
= Logger.getLogger(JavaTagGenerator.class.getName());
private static HashSet<String> _reserved
= new HashSet<String>();
private String _description = null;
private String _displayName = null;
private String _smallIcon = null;
private String _largeIcon = null;
private String _example = null;
private String _bodyContent = null;
private String _dynamicAttributes = null;
private ArrayList<TldAttribute> _attributes = new ArrayList<TldAttribute>();
private ArrayList<TldVariable> _variables = new ArrayList<TldVariable>();
private TempTagInfo _tagInfo = new TempTagInfo();
public JavaTagGenerator(ParseTagManager tagManager)
{
super(tagManager);
setOmitXmlDeclaration(true);
}
public void init()
{
super.init();
setOmitXmlDeclaration(true);
}
/**
* Returns true if the XML declaration should be ignored.
*/
/*
boolean isOmitXmlDeclaration()
{
// tags always omit the declaration
return true;
}
*/
public void setDescription(String description)
{
_description = description;
}
public String getDescription()
{
return _description;
}
public void setDisplayName(String displayName)
{
_displayName = displayName;
}
public String getDisplayName()
{
return _displayName;
}
public void setSmallIcon(String smallIcon)
{
_smallIcon = smallIcon;
}
public String getSmallIcon()
{
return _smallIcon;
}
public void setLargeIcon(String largeIcon)
{
_largeIcon = largeIcon;
}
public String getLargeIcon()
{
return _largeIcon;
}
public void setExample(String example)
{
_example = example;
}
public String getExample()
{
return _example;
}
/**
* Sets the body content.
*/
public void setBodyContent(String bodyContent)
{
_bodyContent = bodyContent;
}
/**
* Gets the body content.
*/
public String getBodyContent()
{
return _bodyContent;
}
/**
* Sets the name of the dynamic attributes map
*/
public void setDynamicAttributes(String dynamicAttributes)
{
_dynamicAttributes = dynamicAttributes;
}
/**
* Gets the body content.
*/
public String getDynamicAttributes()
{
return _dynamicAttributes;
}
/**
* Adds an attribute.
*/
public void addAttribute(TldAttribute attribute)
{
_attributes.add(attribute);
}
/**
* Returns the attributes.
*/
public ArrayList<TldAttribute> getAttributes()
{
return _attributes;
}
/**
* Finds an attribute.
*/
public TldAttribute findAttribute(String name)
{
for (int i = 0; i < _attributes.size(); i++) {
TldAttribute attr = _attributes.get(i);
if (name.equals(attr.getName()))
return attr;
}
return null;
}
/**
* Adds a variable.
*/
public void addVariable(TldVariable var)
{
_variables.add(var);
}
/**
* Finds a variable.
*/
public TldVariable findVariable(String name)
{
for (int i = 0; i < _variables.size(); i++) {
TldVariable var = _variables.get(i);
// jsp/1071, jsp/106g (tck)
if (name.equals(var.getNameGiven())
|| name.equals(var.getAlias()))
return var;
}
return null;
}
/**
* Finds a variable.
*/
public TldVariable findNameFromAttributeVariable(String name)
{
for (int i = 0; i < _variables.size(); i++) {
TldVariable var = _variables.get(i);
// jsp/106g (tck)
if (name.equals(var.getNameFromAttribute()))
return var;
}
return null;
}
/**
* Returns the variables.
*/
public ArrayList<TldVariable> getVariables()
{
return _variables;
}
public boolean isTag()
{
return true;
}
/**
* Returns true for XML.
*/
boolean isXml()
{
return _parseState.isXml();
}
/**
* Generates the Java code.
*/
protected void generate(JspJavaWriter out)
throws Exception
{
out.setLineMap(_lineMap);
generateClassHeader(out);
generateAttributes(out);
if (_dynamicAttributes != null)
generateDynamicAttributes(out);
generateDoTag(out, _rootNode);
// if (isStaticDoTag())
// generateStaticDoTag(out, _rootNode);
generateDoTagImpl(out, _rootNode);
generateTagInfo(out);
generateClassFooter(out);
}
protected boolean isStaticDoTag()
{
// return ! hasScripting();
return false;
}
/**
* Generates the class header.
*
* @param doc the XML document representing the JSP page.
*/
protected void generateClassHeader(JspJavaWriter out)
throws IOException, JspParseException
{
out.println("/*");
out.println(" * JSP-Tag generated by " + VersionFactory.getFullVersion());
out.println(" */" );
out.println();
if (_pkg != null && ! _pkg.equals(""))
out.println("package " + _pkg + ";");
out.println("import javax.servlet.*;");
out.println("import javax.servlet.jsp.*;");
out.println("import javax.servlet.http.*;");
fillSingleTaglibImports();
ArrayList<String> imports = _parseState.getImportList();
for (int i = 0; i < imports.size(); i++) {
String name = imports.get(i);
out.print("import ");
out.print(name);
out.println(";");
}
_parseState.addImport("javax.servlet.*");
_parseState.addImport("javax.servlet.jsp.*");
_parseState.addImport("javax.servlet.http.*");
_parseState.addImport("java.lang.*");
out.println();
out.print("public class ");
out.print(_className);
if (hasScripting())
out.print(" extends com.caucho.jsp.java.JspTagSupport");
else
out.print(" extends com.caucho.jsp.java.JspTagFileSupport");
if (_dynamicAttributes != null)
out.print(" implements javax.servlet.jsp.tagext.DynamicAttributes");
out.println(" {");
out.pushDepth();
// jsp/102e, jsp/102g
if (_rootNode != null && _rootNode.hasCustomTag()) {
out.println("public static final boolean _caucho_hasCustomTag = true;");
} else {
out.println("public static final boolean _caucho_hasCustomTag = false;");
}
out.print("static "); // XXX: this shouldn't be created each tag
out.println("private final java.util.HashMap<String,java.lang.reflect.Method> _jsp_functionMap = new java.util.HashMap<String,java.lang.reflect.Method>();");
// jsp/107{0,1}
out.println("private static com.caucho.jsp.PageManager _jsp_pageManager;");
out.println("private boolean _caucho_isDead;");
out.println("private boolean _caucho_isNotModified;");
for (int i = 0; i < _declarations.size(); i++) {
JspDeclaration decl = _declarations.get(i);
out.println();
decl.generateDeclaration(out);
}
}
/**
* Generates the attribute definitions.
*
* @param out the writer to the .java source
*/
protected void generateAttributes(JspJavaWriter out)
throws IOException, JspParseException
{
for (int i = 0; i < _attributes.size(); i++) {
TldAttribute attr = _attributes.get(i);
String name = attr.getName();
String upperName;
char ch = name.charAt(0);
upperName = Character.toUpperCase(ch) + name.substring(1);
Class cl = attr.getType();
if (cl == null)
cl = String.class;
String type = cl.getName();
String isSetName = "_jsp_" + name + "_isSet";
String fieldName = toFieldName(name);
out.println();
out.print("private ");
out.printClass(cl);
out.println(" " + fieldName + ";");
out.println("private boolean " + isSetName + ";");
out.println();
out.print("public void set" + upperName + "(");
out.printClass(cl);
out.println(" value)");
out.println("{");
out.pushDepth();
out.println("this." + isSetName + " = true;");
out.println("this." + fieldName + " = value;");
out.popDepth();
out.println("}");
/*
// jsp/101f
out.println();
out.println("public " + type + " get" + upperName + "()");
out.println("{");
out.pushDepth();
out.println("return " + fieldName + ";");
out.popDepth();
out.println("}");
*/
}
}
/**
* Generates the attribute definitions.
*
* @param out the writer to the .java source
*/
protected void generateDynamicAttributes(JspJavaWriter out)
throws IOException, JspParseException
{
String dyn = toFieldName(_dynamicAttributes);
out.println();
out.println("java.util.HashMap " + dyn + " = new java.util.HashMap();");
out.println();
out.println("public void setDynamicAttribute(String uri, String localName, Object value)");
out.println(" throws javax.servlet.jsp.JspException");
out.println("{");
out.println(" if (uri == null || \"\".equals(uri))");
out.println(" " + dyn + ".put(localName, value);");
out.println("}");
}
/**
* Prints the _jspService header
*/
protected void generateDoTag(JspJavaWriter out, JspNode node)
throws Exception
{
out.println();
out.println("public void doTag()");
out.println(" throws javax.servlet.jsp.JspException, java.io.IOException");
out.println("{");
out.pushDepth();
out.println("javax.servlet.jsp.JspContext _jsp_parentContext = getJspContext();");
out.println("com.caucho.jsp.PageContextWrapper pageContext = _jsp_pageManager.createPageContextWrapper(_jsp_parentContext);");
// jsp/1056
out.println("setJspContext(pageContext);");
if (false && hasScripting()) {
out.println("javax.servlet.http.HttpServletRequest request = (javax.servlet.http.HttpServletRequest) pageContext.getRequest();");
out.println("javax.servlet.http.HttpServletResponse response = (javax.servlet.http.HttpServletResponse) pageContext.getResponse();");
out.println("javax.servlet.http.HttpSession session = pageContext.getSession();");
out.println("javax.servlet.ServletContext application = pageContext.getServletContext();");
out.println("javax.servlet.ServletConfig config = pageContext.getServletConfig();");
}
out.println("com.caucho.jsp.PageContextWrapper jspContext = pageContext;");
out.println("javax.el.ELContext _jsp_env = pageContext.getELContext();");
out.println("javax.servlet.jsp.JspWriter out = pageContext.getOut();");
// generateTagAttributes(out);
//if (hasScripting())
// generatePrologue(out);
out.println("try {");
out.pushDepth();
// jsp/10a2
if (false && hasScripting()) {
out.println("TagState _jsp_state = new TagState();");
// jsp/100h
out.println("javax.servlet.jsp.tagext.JspTag _jsp_parent_tag");
out.println(" = new javax.servlet.jsp.tagext.TagAdapter(this);");
node.generate(out);
generateTagVariablesAtEnd(out);
} else {
out.println("doTag(_jsp_parentContext, pageContext, out, null, this);");
}
out.popDepth();
out.println("} catch (Throwable e) {");
out.println(" if (e instanceof java.io.IOException)");
out.println(" throw (java.io.IOException) e;");
out.println(" throw com.caucho.jsp.QJspException.createJspException(e);");
out.println("}");
if (hasScripting() && _variables.size() > 0) {
out.println("finally {");
out.pushDepth();
// generateTagVariablesAtEnd(out);
out.println("setJspContext(_jsp_parentContext);");
out.println("_jsp_pageManager.freePageContextWrapper(pageContext);");
out.popDepth();
out.println("}");
}
out.popDepth();
out.println("}");
}
/**
* Generates the attribute definitions.
*
* @param out the writer to the .java source
*/
protected void generateTagAttributes(JspJavaWriter out)
throws IOException, JspParseException
{
for (int i = 0; i < _attributes.size(); i++) {
TldAttribute attr = _attributes.get(i);
String name = attr.getName();
String upperName;
char ch = name.charAt(0);
upperName = Character.toUpperCase(ch) + name.substring(1);
Class cl = attr.getType();
if (cl == null)
cl = String.class;
String type = cl.getName();
String isSetName = "_jsp_" + name + "_isSet";
String fieldName = toFieldName(name);
out.println("if (" + isSetName + ")");
out.println(" pageContext.setAttribute(\"" + name + "\", " +
JspNode.toELObject(fieldName, cl) + ");");
}
// jsp/10a1
if (_dynamicAttributes != null) {
out.println("pageContext.setAttribute(\"" + _dynamicAttributes + "\"," +
toFieldName(_dynamicAttributes) + ");");
}
}
/**
* Prints the _jspService header
*/
protected void generateDoTagImpl(JspJavaWriter out, JspNode node)
throws Exception
{
out.println();
out.println("public void doTag(javax.servlet.jsp.JspContext _jsp_parentContext,");
out.println(" com.caucho.jsp.PageContextWrapper pageContext,");
out.println(" javax.servlet.jsp.JspWriter out,");
out.println(" javax.servlet.jsp.tagext.JspFragment _jspBody,");
out.println(" javax.servlet.jsp.tagext.JspTag jsp_parent_tag)");
out.println(" throws Throwable");
out.println("{");
out.pushDepth();
out.println("javax.el.ELContext _jsp_env = pageContext.getELContext();");
if (node.hasScripting()) {
out.println("javax.servlet.http.HttpServletRequest request = (javax.servlet.http.HttpServletRequest) pageContext.getRequest();");
out.println("javax.servlet.http.HttpServletResponse response = (javax.servlet.http.HttpServletResponse) pageContext.getResponse();");
out.println("javax.servlet.http.HttpSession session = pageContext.getSession();");
out.println("javax.servlet.ServletContext application = pageContext.getServletContext();");
out.println("javax.servlet.ServletConfig config = pageContext.getServletConfig();");
out.println("com.caucho.jsp.PageContextWrapper jspContext = pageContext;");
}
/*
out.println("if (_jspBody != null)");
out.println(" setJspBody(_jspBody);"); // jsp/1025 vs jsp/102h
*/
out.println("TagState _jsp_state = new TagState();");
out.println("javax.servlet.jsp.tagext.JspTag _jsp_parent_tag = jsp_parent_tag;");
generateTagAttributes(out);
generatePrologue(out);
//out.println("try {");
//out.pushDepth();
node.generate(out);
//out.popDepth();
//out.println("} finally {");
//out.pushDepth();
generateTagVariablesAtEnd(out);
//out.println("_jsp_pageManager.freePageContextWrapper(pageContext);");
//out.popDepth();
//out.println("}");
out.popDepth();
out.println("}");
}
/**
* Generates prologue stuff
*
* @param out the writer to the .java source
*/
protected void generatePrologue(JspJavaWriter out)
throws Exception
{
_rootNode.generatePrologue(out);
for (int i = 0; i < _variables.size(); i++) {
TldVariable var = _variables.get(i);
if (var.getNameFromAttribute() != null) {
out.print("String _jsp_var_from_attribute_" + i + " = (String) ");
out.println("pageContext.getAttribute(\"" +
var.getNameFromAttribute() + "\");");
}
if ("AT_END".equals(var.getScope()))
continue;
String srcName = var.getNameGiven();
if (srcName == null)
srcName = var.getAlias();
String dstName;
if (var.getNameGiven() != null)
dstName = "\"" + var.getNameGiven() + "\"";
else
dstName = "_jsp_var_from_attribute_" + i;
if ("NESTED".equals(var.getScope())) {
out.print("Object _jsp_nested_var_" + i + " = ");
out.println("_jsp_parentContext.getAttribute(" + dstName + ");");
}
/*
else {
out.print("pageContext.setAttribute(\"" + srcName + "\",");
out.println("_jsp_parentContext.getAttribute(" + dstName + "));");
}
*/
}
}
/**
* Generates the variable setting.
*
* @param out the writer to the .java source
*/
protected void generateTagVariablesAtEnd(JspJavaWriter out)
throws IOException, JspParseException
{
for (int i = 0; i < _variables.size(); i++) {
TldVariable var = _variables.get(i);
String srcName = var.getNameGiven();
if (srcName == null)
srcName = var.getAlias();
String dstName;
if (var.getNameGiven() != null)
dstName = "\"" + var.getNameGiven() + "\"";
else
dstName = "_jsp_var_from_attribute_" + i;
if ("NESTED".equals(var.getScope())) {
out.println("_jsp_parentContext.setAttribute(" + dstName + ", _jsp_nested_var_" + i + ");");
}
else {
out.print("_jsp_parentContext.setAttribute(" + dstName + ",");
out.println("pageContext.getAttribute(\"" + srcName + "\"));");
}
}
}
public TagInfo generateTagInfo(String className, TagLibraryInfo taglib)
{
init(className);
TldTag tag = new TldTag();
for (int i = 0; i < _attributes.size(); i++) {
TldAttribute attr = _attributes.get(i);
tag.addAttribute(attr);
}
for (int i = 0; i < _variables.size(); i++) {
TldVariable var = _variables.get(i);
try {
tag.addVariable(var);
} catch (Exception e) {
log.log(Level.WARNING, e.toString(), e);
}
}
String bodyContent = _bodyContent;
if (bodyContent == null)
bodyContent = "scriptless";
return new TagInfoExt(tag.getName(),
_fullClassName,
bodyContent,
getDescription(),
taglib,
null,
tag.getAttributes(),
getDisplayName(),
getSmallIcon(),
getLargeIcon(),
tag.getVariables(),
_dynamicAttributes != null,
_dynamicAttributes,
null);
}
/**
* Generates the attribute definitions.
*
* @param out the writer to the .java source
*/
protected void generateTagInfo(JspJavaWriter out)
throws IOException, JspParseException
{
/*
out.println();
out.println("public javax.servlet.jsp.tagext.TagInfo _caucho_getTagInfo()");
out.println(" throws com.caucho.config.ConfigException");
out.println("{");
out.pushDepth();
out.println(" return _caucho_getTagInfo(_caucho_getTagLibrary());");
out.popDepth();
out.println("}");
*/
out.println();
out.println("public javax.servlet.jsp.tagext.TagInfo _caucho_getTagInfo(javax.servlet.jsp.tagext.TagLibraryInfo taglib)");
out.println(" throws com.caucho.config.ConfigException");
out.println("{");
out.pushDepth();
out.println("com.caucho.jsp.cfg.TldTag tag = new com.caucho.jsp.cfg.TldTag();");
out.println("tag.setName(\"test\");");
out.println("com.caucho.jsp.cfg.TldAttribute attr;");
for (int i = 0; i < _attributes.size(); i++) {
TldAttribute attr = _attributes.get(i);
out.println("attr = new com.caucho.jsp.cfg.TldAttribute();");
out.println("attr.setName(\"" + attr.getName() + "\");");
Class type = attr.getType();
if (type != null) {
out.print("attr.setType(");
out.printClass(type);
out.println(".class);");
}
out.println("attr.setRtexprvalue(" + attr.getRtexprvalue() + ");");
out.println("attr.setRequired(" + attr.getRequired() + ");");
if (attr.getDeferredValue() != null) {
out.println("attr.setDeferredValue(new com.caucho.jsp.cfg.TldAttribute.DeferredValue());");
if (attr.getDeferredValue().getType() != null) {
out.print("attr.getDeferredValue().setType(\"");
out.printJavaString(attr.getDeferredValue().getType());
out.println("\");");
}
}
if (attr.getDeferredMethod() != null) {
out.println("attr.setDeferredMethod(new com.caucho.jsp.cfg.TldAttribute.DeferredMethod());");
Signature sig = attr.getDeferredMethod().getMethodSignature();
if (sig != null) {
out.print("attr.getDeferredMethod().setMethodSignature(");
out.print("new com.caucho.config.types.Signature(\"");
out.printJavaString(sig.getSignature());
out.println("\"));");
}
}
out.println("tag.addAttribute(attr);");
}
out.println("com.caucho.jsp.cfg.TldVariable var;");
for (int i = 0; i < _variables.size(); i++) {
TldVariable var = _variables.get(i);
out.println("var = new com.caucho.jsp.cfg.TldVariable();");
if (var.getNameGiven() != null)
out.println("var.setNameGiven(\"" + var.getNameGiven() + "\");");
if (var.getNameFromAttribute() != null)
out.println("var.setNameFromAttribute(\"" + var.getNameFromAttribute() + "\");");
String type = var.getVariableClass();
if (type != null)
out.println("var.setVariableClass(\"" + type + "\");");
out.println("var.setDeclare(" + var.getDeclare() + ");");
if (var.getScope() != null)
out.println("var.setScope(\"" + var.getScope() + "\");");
out.println("tag.addVariable(var);");
}
String bodyContent = _bodyContent;
if (bodyContent == null)
bodyContent = "scriptless";
out.println("return new com.caucho.jsp.java.TagInfoExt(tag.getName(),");
out.println(" getClass().getName(),");
out.println(" \"" + bodyContent + "\",");
out.print(" \"");
if (_description != null)
out.printJavaString(_description);
else
out.printJavaString("A simple tag");
out.println("\",");
out.println(" taglib,");
out.println(" null,");
out.println(" tag.getAttributes(),");
if (_displayName != null) {
out.print(" \"");
out.printJavaString(_displayName);
out.println("\",");
}
else {
out.println(" null,");
}
if (_smallIcon != null) {
out.print(" \"");
out.printJavaString(_smallIcon);
out.println("\",");
}
else {
out.println(" null,");
}
if (_largeIcon != null) {
out.print(" \"");
out.printJavaString(_largeIcon);
out.println("\",");
}
else {
out.println(" null,");
}
out.println(" tag.getVariables(),");
out.println(" " + (_dynamicAttributes != null) + ",");
if (_dynamicAttributes != null)
out.println(" \"" + _dynamicAttributes + "\",");
else
out.println(" null,");
out.println(" _caucho_depends.getDependencies());");
out.popDepth();
out.println("}");
out.println();
out.println("public String _caucho_getDynamicAttributes()");
out.println("{");
out.pushDepth();
if (_dynamicAttributes != null)
out.println("return \"" + _dynamicAttributes + "\";");
else
out.println("return null;");
out.popDepth();
out.println("}");
generateTagLibrary(out);
}
/**
* Generates the attribute definitions.
*
* @param out the writer to the .java source
*/
protected void generateTagLibrary(JspJavaWriter out)
throws IOException, JspParseException
{
out.println();
out.println("private javax.servlet.jsp.tagext.TagLibraryInfo _caucho_getTagLibrary()");
out.println(" throws com.caucho.config.ConfigException");
out.println("{");
out.pushDepth();
out.println("return new com.caucho.jsp.java.TagTaglib(\"x\", \"http://test.com\");");
out.popDepth();
out.println("}");
}
private String toFieldName(String name)
{
/*n
if (hasScripting() && ! _reserved.contains(name))
return name;
else
return "_" + name;
*/
if (! _reserved.contains(name))
return name;
else
return "_" + name;
}
static {
_reserved.add("public");
_reserved.add("private");
_reserved.add("protected");
_reserved.add("static");
_reserved.add("final");
_reserved.add("class");
_reserved.add("module");
_reserved.add("interface");
_reserved.add("extends");
_reserved.add("implements");
_reserved.add("package");
_reserved.add("import");
_reserved.add("new");
_reserved.add("if");
_reserved.add("else");
_reserved.add("for");
_reserved.add("do");
_reserved.add("while");
_reserved.add("break");
_reserved.add("continue");
_reserved.add("switch");
_reserved.add("case");
_reserved.add("default");
_reserved.add("throw");
_reserved.add("enum");
_reserved.add("throws");
_reserved.add("void");
_reserved.add("boolean");
_reserved.add("byte");
_reserved.add("char");
_reserved.add("short");
_reserved.add("int");
_reserved.add("long");
_reserved.add("float");
_reserved.add("true");
_reserved.add("false");
_reserved.add("null");
}
}