/*
* 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.xml.QName;
import javax.servlet.jsp.tagext.JspFragment;
import javax.servlet.jsp.tagext.TagAttributeInfo;
import javax.servlet.jsp.tagext.VariableInfo;
import java.io.IOException;
import java.util.ArrayList;
import java.lang.reflect.Field;
/**
* Represents a custom tag.
*/
public class TagFileTag extends GenericTag {
private boolean _oldLocalScriptingInvalid;
private JspBody _body;
private int _maxFragmentIndex;
private String _contextVarName;
private Boolean _hasCustomTag;
/**
* Called when the attributes end.
*/
public void endAttributes()
{
_oldLocalScriptingInvalid = _parseState.isLocalScriptingInvalid();
_parseState.setLocalScriptingInvalid(true);
}
/**
* Adds a child node.
*/
public void endElement()
throws Exception
{
super.endElement();
_parseState.setLocalScriptingInvalid(_oldLocalScriptingInvalid);
if (_children == null || _children.size() == 0)
return;
for (int i = 0; i < _children.size(); i++) {
JspNode node = _children.get(i);
if (node instanceof JspBody) {
if (_body != null)
throw error(L.l("Only one <jsp:body> is allowed as a child of a tag."));
_body = (JspBody) node;
_children.remove(i);
return;
}
}
for (int i = 0; i < _children.size(); i++) {
JspNode node = _children.get(i);
if (! (node instanceof JspAttribute)) {
if (_body == null) {
_body = new JspBody();
_body.setParent(this);
_body.setGenerator(_gen);
_body.endAttributes();
}
_body.addChild(node);
}
}
_body.endElement();
_children = null;
}
@Override
public boolean hasCustomTag()
{
return true;
/*
if (true) return true;
if (Boolean.TRUE.equals(_hasCustomTag))
return true;
if (_hasCustomTag == null && _tagClass != null) {
try {
Field hasCustomTagField = _tagClass.getDeclaredField("_caucho_hasCustomTag");
_hasCustomTag = (Boolean) hasCustomTagField.get(null);
if (Boolean.TRUE.equals(_hasCustomTag))
return true;
} catch (NoSuchFieldException e) {
//
} catch (IllegalAccessException e) {
//
}
}
return super.hasCustomTag() || (_body != null && _body.hasCustomTag());
*/
}
/**
* Generates code before the actual JSP.
*/
@Override
public void generateTagState(JspJavaWriter out)
throws Exception
{
if (! isDeclaringInstance())
return;
out.print("private ");
out.print(getTagClassName());
out.println(" " + _tag.getId() + ";");
out.println();
out.print("final ");
out.print(getTagClassName());
// out.println(" get" + _tag.getId() + "(PageContext pageContext, javax.servlet.jsp.tagext.JspTag _jsp_parent_tag) throws Throwable");
out.println(" get" + _tag.getId() + "() throws Throwable");
out.println("{");
out.pushDepth();
out.println("if (" + _tag.getId() + " == null) {");
out.pushDepth();
out.println(_tag.getId() + " = new " + getTagClassName() + "();");
out.popDepth();
out.println("}");
out.println();
out.println("return " + _tag.getId() + ";");
out.popDepth();
out.println("}");
super.generateTagState(out);
}
/**
* Generates the code for a custom tag.
*
* @param out the output writer for the generated java.
*/
public void generateDeclaration(JspJavaWriter out)
throws IOException
{
super.generateDeclaration(out);
/*
out.println();
out.println("private static final com.caucho.jsp.java.JspTagFileSupport " + name + " = ");
out.println(" new " + className + "();");
*/
}
/**
* Returns true if the tag file invocation contains a child tag.
*/
@Override
public boolean hasTag()
{
return super.hasTag() || _body != null && _body.hasTag();
}
/**
* Returns null, since tag files aren't parent tags.
*/
/*
public String getCustomTagName()
{
return null;
}
*/
public String getTagClassName()
{
return _tagInfo.getTagClassName();
}
/**
* Generates code before the actual JSP.
*/
public void generatePrologue(JspJavaWriter out)
throws Exception
{
super.generatePrologue(out);
if (_body != null) {
_body.setJspFragment(true);
_body.generateFragmentPrologue(out);
}
if (isDeclaringInstance()) {
out.println(getTagClassName() + " " + getCustomTagName() + ";");
}
}
/**
* Generates the code for a custom tag.
*
* @param out the output writer for the generated java.
*/
public void generate(JspJavaWriter out)
throws Exception
{
String className = getTagClassName();
_gen.addTagFileClass(className);
String parentTagName;
JspNode parentTagNode = getParent().getParentTagNode();
if (parentTagNode == null) {
parentTagName = null;
}
else if (parentTagNode.isSimpleTag()) {
parentTagName = null;
String parentName = parentTagNode.getCustomTagName();
out.println("if (" + parentName + "_adapter == null)");
out.println(" " + parentName + "_adapter = new javax.servlet.jsp.tagext.TagAdapter(" + parentName + ");");
}
else {
parentTagName = parentTagNode.getCustomTagName();
}
String customTagName = getCustomTagName();
String name = className;
out.println(customTagName + " = _jsp_state.get" + _tag.getId() + "();");
String childContext = fillTagFileAttributes(out, name, customTagName);
if (true || _body != null) {
// jsp/1025
out.print(customTagName + ".setJspBody(");
if (_body != null)
generateFragment(out, _body, "pageContext", false);
else
out.print("null");
out.println(");");
}
out.print(customTagName + ".doTag(pageContext, " + childContext + ", out, ");
/*
if (_body != null)
generateFragment(out, _body, "pageContext");
else
out.print("null");
*/
out.print(customTagName + ".getJspBody()");
out.print(", " + parentTagName);
out.println(");");
printVarDeclaration(out, VariableInfo.AT_END);
}
public String fillTagFileAttributes(JspJavaWriter out,
String tagName,
String customTagName)
throws Exception
{
_contextVarName = "_jsp_context" + _gen.uniqueId();
String name = _contextVarName;
out.println("com.caucho.jsp.PageContextWrapper " + name);
out.println(" = _jsp_pageManager.createPageContextWrapper(pageContext);");
TagAttributeInfo attrs[] = _tagInfo.getAttributes();
// clear any attributes mentioned in the taglib that aren't set
for (int i = 0; attrs != null && i < attrs.length; i++) {
int p = indexOf(_attributeNames, attrs[i].getName());
if (p < 0 && attrs[i].isRequired()) {
throw error(L.l("required attribute '{0}' missing from <{1}>",
attrs[i].getName(),
getTagName()));
}
}
boolean isDynamic = _tagInfo.hasDynamicAttributes();
String mapAttribute = null;
String mapName = null;
if (isDynamic) {
TagInfoExt tagInfoImpl = (TagInfoExt) _tagInfo;
mapAttribute = tagInfoImpl.getDynamicAttributesName();
}
// fill all mentioned attributes
for (int i = 0; i < _attributeNames.size(); i++) {
QName attrName = _attributeNames.get(i);
Object value = _attributeValues.get(i);
TagAttributeInfo attribute = null;
int j = 0;
for (j = 0; attrs != null && j < attrs.length; j++) {
if (attrs[j].getName().equals(attrName.getName())) {
attribute = attrs[j];
break;
}
}
if (attribute == null && ! isDynamic)
throw error(L.l("unexpected attribute `{0}' in <{1}>",
attrName.getName(), getTagName()));
boolean rtexprvalue = true;
Class cl = null;
if (attribute != null) {
String typeName = attribute.getTypeName();
if (typeName == null)
typeName = String.class.getName();
cl = _gen.loadBeanClass(typeName);
rtexprvalue = attribute.canBeRequestTime();
}
if (cl == null)
cl = String.class;
if (attribute == null) {
/*
if (mapName == null) {
mapName = "_jsp_map_" + _gen.uniqueId();
out.println("java.util.HashMap " + mapName + " = new java.util.HashMap(8);");
out.println(name + ".setAttribute(\"" + mapAttribute + "\", " + mapName + ");");
}
*/
out.print(customTagName + ".setDynamicAttribute(null, \"" + attrName.getName() + "\", ");
}
else
out.print(name + ".setAttribute(\"" + attrName.getName() + "\", ");
if (value instanceof JspNode) {
JspFragmentNode frag = (JspFragmentNode) value;
if (attribute != null &&
JspFragment.class.getName().equals(attribute.getTypeName())) {
out.println(generateFragment(frag, "pageContext") + ");");
}
else
out.println(frag.generateValue() + ");");
}
else {
String convValue = generateParameterValue(cl,
(String) value,
rtexprvalue,
attribute,
_parseState.isELIgnored());
// attribute.allowRtexpr());
out.println(toObject(cl, convValue) + ");");
String localName = attrName.getLocalName();
String upperName = Character.toUpperCase(localName.charAt(0)) + localName.substring(1);
if (attribute != null) {
// needed by TeamCity
out.println(customTagName + ".set" + upperName + "(" + convValue + ");");
}
else {
// out.println(customTagName + ".set" + upperName + "(" + convValue + ");");
}
}
/*
generateSetAttribute(out, customTagName, attrName, value,
rtexprvalue,
false, attribute);
*/
}
return name;
}
@Override
protected void addTagDepend()
{
}
private int indexOf(ArrayList<QName> names, String name)
{
for (int i = 0; i < names.size(); i++) {
if (names.get(i).getName().equals(name))
return i;
}
return -1;
}
private String toObject(Class cl, String value)
{
if (boolean.class.equals(cl))
return "new Boolean(" + value + ")";
else if (byte.class.equals(cl))
return "new Byte(" + value + ")";
else if (short.class.equals(cl))
return "new Short(" + value + ")";
else if (int.class.equals(cl))
return "new Integer(" + value + ")";
else if (long.class.equals(cl))
return "new Long(" + value + ")";
else if (char.class.equals(cl))
return "new Character(" + value + ")";
else if (float.class.equals(cl))
return "new Float(" + value + ")";
else if (double.class.equals(cl))
return "new Double(" + value + ")";
else
return value;
}
}