001: /*
002: * The Apache Software License, Version 1.1
003: *
004: * Copyright (c) 1999 The Apache Software Foundation. All rights
005: * reserved.
006: *
007: * Redistribution and use in source and binary forms, with or without
008: * modification, are permitted provided that the following conditions
009: * are met:
010: *
011: * 1. Redistributions of source code must retain the above copyright
012: * notice, this list of conditions and the following disclaimer.
013: *
014: * 2. Redistributions in binary form must reproduce the above copyright
015: * notice, this list of conditions and the following disclaimer in
016: * the documentation and/or other materials provided with the
017: * distribution.
018: *
019: * 3. The end-user documentation included with the redistribution, if
020: * any, must include the following acknowlegement:
021: * "This product includes software developed by the
022: * Apache Software Foundation (http://www.apache.org/)."
023: * Alternately, this acknowlegement may appear in the software itself,
024: * if and wherever such third-party acknowlegements normally appear.
025: *
026: * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
027: * Foundation" must not be used to endorse or promote products derived
028: * from this software without prior written permission. For written
029: * permission, please contact apache@apache.org.
030: *
031: * 5. Products derived from this software may not be called "Apache"
032: * nor may "Apache" appear in their names without prior written
033: * permission of the Apache Group.
034: *
035: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
036: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
037: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
038: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
039: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
040: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
041: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
042: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
043: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
044: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
045: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
046: * SUCH DAMAGE.
047: * ====================================================================
048: *
049: * This software consists of voluntary contributions made by many
050: * individuals on behalf of the Apache Software Foundation. For more
051: * information on the Apache Software Foundation, please see
052: * <http://www.apache.org/>.
053: *
054: */
055: package com.sun.portal.providers.jsp.jasper3.jasper.compiler;
056:
057: import java.util.Hashtable;
058: import java.util.Stack;
059: import java.util.Enumeration;
060: import java.lang.reflect.Method;
061:
062: import javax.servlet.jsp.tagext.TagLibraryInfo;
063: import javax.servlet.jsp.tagext.TagInfo;
064: import javax.servlet.jsp.tagext.TagAttributeInfo;
065: import javax.servlet.jsp.tagext.VariableInfo;
066: import javax.servlet.jsp.tagext.TagData;
067: import javax.servlet.jsp.tagext.Tag;
068: import javax.servlet.jsp.tagext.BodyTag;
069:
070: import com.sun.portal.providers.jsp.jasper3.jasper.JasperException;
071: import com.sun.portal.providers.jsp.jasper3.jasper.JspCompilationContext;
072: import com.sun.portal.providers.jsp.jasper3.jasper.Constants;
073:
074: import com.sun.portal.providers.jsp.jasper3.jasper.compiler.ServletWriter;
075:
076: /**
077: * Custom tag support.
078: *
079: * @author Anil K. Vijendran
080: */
081: public class TagBeginGenerator extends TagGeneratorBase implements
082: ServiceMethodPhase {
083: String prefix;
084: String shortTagName;
085: Hashtable attrs;
086: TagLibraryInfo tli;
087: TagInfo ti;
088: TagAttributeInfo[] attributes;
089: String baseVarName, thVarName;
090: TagCache tc;
091: TagData tagData;
092: Mark start;
093: TagLibraries libraries;
094:
095: public TagBeginGenerator(Mark start, String prefix,
096: String shortTagName, Hashtable attrs, TagLibraryInfo tli,
097: TagInfo ti, TagLibraries libraries, Stack tagHandlerStack,
098: Hashtable tagVarNumbers) throws JasperException {
099: setTagHandlerStack(tagHandlerStack);
100: setTagVarNumbers(tagVarNumbers);
101: this .prefix = prefix;
102: this .shortTagName = shortTagName;
103: this .attrs = attrs;
104: this .tli = tli;
105: this .ti = ti;
106: this .attributes = ti.getAttributes();
107: this .baseVarName = getTagVarName(prefix, shortTagName);
108: this .thVarName = "_jspx_th_" + baseVarName;
109: this .start = start;
110: this .libraries = libraries;
111: }
112:
113: public void init(JspCompilationContext ctxt) throws JasperException {
114: validate();
115: tc = libraries.getTagCache(prefix, shortTagName);
116: if (tc == null) {
117: tc = new TagCache(shortTagName);
118:
119: ClassLoader cl = ctxt.getClassLoader();
120: Class clz = null;
121: try {
122: clz = cl.loadClass(ti.getTagClassName());
123: } catch (Exception ex) {
124: throw new CompileException(start, Constants
125: .getString("jsp.error.unable.loadclass",
126: new Object[] { ti.getTagClassName(),
127: ex.getMessage() }));
128: }
129: tc.setTagHandlerClass(clz);
130: libraries.putTagCache(prefix, shortTagName, tc);
131: }
132: }
133:
134: void validate() throws JasperException {
135:
136: // Sigh! I wish I didn't have to clone here.
137: Hashtable attribs = (Hashtable) attrs.clone();
138:
139: // First make sure all required attributes are indeed present.
140: for (int i = 0; i < attributes.length; i++)
141: if (attributes[i].isRequired()
142: && attribs.get(attributes[i].getName()) == null)
143: throw new CompileException(start, Constants
144: .getString("jsp.error.missing_attribute",
145: new Object[] { attributes[i].getName(),
146: shortTagName }));
147: // Now make sure there are no invalid attributes...
148: Enumeration e = attribs.keys();
149: while (e.hasMoreElements()) {
150: String attr = (String) e.nextElement();
151: boolean found = false;
152: for (int i = 0; i < attributes.length; i++)
153: if (attr.equals(attributes[i].getName())) {
154: found = true;
155: if (attributes[i].canBeRequestTime()
156: && JspUtil.isExpression((String) attribs
157: .get(attr)))
158: attribs.put(attr, TagData.REQUEST_TIME_VALUE);
159: }
160:
161: if (!found)
162: throw new CompileException(start, Constants.getString(
163: "jsp.error.bad_attribute",
164: new Object[] { attr }));
165: }
166:
167: tagData = new TagData(attribs);
168: if (!ti.isValid(tagData))
169: throw new CompileException(start, Constants
170: .getString("jsp.error.invalid_attributes"));
171: }
172:
173: private final void generateSetters(ServletWriter writer,
174: String parent) throws JasperException {
175: writer.println(thVarName + ".setPageContext(pageContext);");
176: writer.println(thVarName + ".setParent(" + parent + ");");
177:
178: if (attributes.length != 0)
179: for (int i = 0; i < attributes.length; i++) {
180: String attrValue = (String) attrs.get(attributes[i]
181: .getName());
182: if (attrValue != null) {
183: String attrName = attributes[i].getName();
184: Method m = tc.getSetterMethod(attrName);
185: if (m == null)
186: throw new CompileException(
187: start,
188: Constants
189: .getString(
190: "jsp.error.unable.to_find_method",
191: new Object[] { attrName }));
192: Class c[] = m.getParameterTypes();
193: // assert(c.length > 0)
194:
195: if (attributes[i].canBeRequestTime()) {
196: if (JspUtil.isExpression(attrValue))
197: attrValue = JspUtil.getExpr(attrValue);
198: else
199: attrValue = convertString(c[0], attrValue,
200: writer, attrName);
201: } else
202: attrValue = convertString(c[0], attrValue,
203: writer, attrName);
204: writer.println(thVarName + "." + m.getName() + "("
205: + attrValue + ");");
206: }
207: }
208: }
209:
210: public String convertString(Class c, String s,
211: ServletWriter writer, String attrName)
212: throws JasperException {
213: if (c == String.class) {
214: return writer.quoteString(s);
215: } else if (c == boolean.class) {
216: return Boolean.valueOf(s).toString();
217: } else if (c == Boolean.class) {
218: return "new Boolean(" + Boolean.valueOf(s).toString() + ")";
219: } else if (c == byte.class) {
220: return "((byte)" + Byte.valueOf(s).toString() + ")";
221: } else if (c == Byte.class) {
222: return "new Byte((byte)" + Byte.valueOf(s).toString() + ")";
223: } else if (c == char.class) {
224: // non-normative, because a normative method would fail to compile
225: if (s.length() > 1) {
226: char ch = s.charAt(0);
227: // this trick avoids escaping issues
228: return "((char) " + (int) ch + ")";
229: } else {
230: throw new NumberFormatException(Constants.getString(
231: "jsp.error.bad_string_char", new Object[0]));
232: }
233: } else if (c == Character.class) {
234: // non-normative, because a normative method would fail to compile
235: if (s.length() > 1) {
236: char ch = s.charAt(0);
237: // this trick avoids escaping issues
238: return "new Character((char) " + (int) ch + ")";
239: } else {
240: throw new NumberFormatException(Constants
241: .getString("jsp.error.bad_string_Character",
242: new Object[0]));
243: }
244: } else if (c == double.class) {
245: return Double.valueOf(s).toString();
246: } else if (c == Double.class) {
247: return "new Double(" + Double.valueOf(s).toString() + ")";
248: } else if (c == float.class) {
249: return Float.valueOf(s).toString() + "f";
250: } else if (c == Float.class) {
251: return "new Float(" + Float.valueOf(s).toString() + "f)";
252: } else if (c == int.class) {
253: return Integer.valueOf(s).toString();
254: } else if (c == Integer.class) {
255: return "new Integer(" + Integer.valueOf(s).toString() + ")";
256: } else if (c == long.class) {
257: return Long.valueOf(s).toString() + "l";
258: } else if (c == Long.class) {
259: return "new Long(" + Long.valueOf(s).toString() + "l)";
260: } else {
261: throw new CompileException(start, Constants.getString(
262: "jsp.error.unable.to_convert_string", new Object[] {
263: c.getName(), attrName }));
264: }
265: }
266:
267: public void generateServiceMethodStatements(ServletWriter writer)
268: throws JasperException {
269: TagVariableData top = topTag();
270: String parent = top == null ? null : top.tagHandlerInstanceName;
271:
272: String evalVar = "_jspx_eval_" + baseVarName;
273: tagBegin(new TagVariableData(thVarName, evalVar));
274:
275: writer.println("/* ---- " + prefix + ":" + shortTagName
276: + " ---- */");
277:
278: writer.println(ti.getTagClassName() + " " + thVarName
279: + " = new " + ti.getTagClassName() + "();");
280:
281: generateSetters(writer, parent);
282:
283: VariableInfo[] vi = ti.getVariableInfo(tagData);
284:
285: // Just declare AT_BEGIN here...
286: declareVariables(writer, vi, true, false, VariableInfo.AT_BEGIN);
287:
288: // A@ changes for fixing the try/finally problem found in the reliability testing
289: //writer.println("try {");
290:
291: writer.pushIndent();
292:
293: writer.println("int " + evalVar + " = " + thVarName
294: + ".doStartTag();");
295:
296: boolean implements BodyTag = BodyTag.class.isAssignableFrom(tc
297: .getTagHandlerClass());
298:
299: // Need to update AT_BEGIN variables here
300: declareVariables(writer, vi, false, true, VariableInfo.AT_BEGIN);
301:
302: // FIXME: I'm not too sure if this is the right approach. I don't like
303: // throwing English language strings into the generated servlet.
304: // Perhaps, I'll just define an inner classes as necessary for these
305: // types of exceptions? -akv
306:
307: if (implements BodyTag) {
308: writer.println("if (" + evalVar
309: + " == Tag.EVAL_BODY_INCLUDE)");
310: writer.pushIndent();
311: writer
312: .println("throw new JspTagException(\"Since tag handler "
313: + tc.getTagHandlerClass()
314: + " implements BodyTag, it can't return Tag.EVAL_BODY_INCLUDE\");");
315: writer.popIndent();
316: } else {
317: writer.println("if (" + evalVar
318: + " == BodyTag.EVAL_BODY_TAG)");
319: writer.pushIndent();
320: writer
321: .println("throw new JspTagException(\"Since tag handler "
322: + tc.getTagHandlerClass()
323: + " does not implement BodyTag, it can't return BodyTag.EVAL_BODY_TAG\");");
324: writer.popIndent();
325: }
326:
327: writer.println("if (" + evalVar + " != Tag.SKIP_BODY) {");
328: writer.pushIndent();
329:
330: if (implements BodyTag) {
331: writer.println("try {");
332: writer.pushIndent();
333:
334: writer.println("if (" + evalVar
335: + " != Tag.EVAL_BODY_INCLUDE) {");
336: writer.pushIndent();
337:
338: writer.println("out = pageContext.pushBody();");
339: writer.println(thVarName
340: + ".setBodyContent((BodyContent) out);");
341:
342: writer.popIndent();
343: writer.println("}");
344:
345: writer.println(thVarName + ".doInitBody();");
346: }
347:
348: writer.println("do {");
349: writer.pushIndent();
350: // Need to declare and update NESTED variables here
351: declareVariables(writer, vi, true, true, VariableInfo.NESTED);
352: // Need to update AT_BEGIN variables here
353: declareVariables(writer, vi, false, true, VariableInfo.AT_BEGIN);
354: }
355:
356: public void generate(ServletWriter writer, Class phase)
357: throws JasperException {
358: generateServiceMethodStatements(writer);
359: }
360: }
|