001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: *
023: * Free Software Foundation, Inc.
024: * 59 Temple Place, Suite 330
025: * Boston, MA 02111-1307 USA
026: *
027: * @author Scott Ferguson
028: */
029:
030: package com.caucho.jsp.java;
031:
032: import com.caucho.jsp.*;
033: import com.caucho.config.*;
034: import com.caucho.util.*;
035: import com.caucho.xml.QName;
036: import com.caucho.vfs.*;
037:
038: import javax.servlet.jsp.tagext.*;
039: import javax.faces.component.*;
040: import javax.faces.event.*;
041: import javax.el.*;
042: import java.lang.reflect.*;
043: import java.util.*;
044: import java.io.*;
045:
046: /**
047: * Represents a custom tag.
048: */
049: public class JsfTagNode extends JsfNode {
050: private JspNode _next;
051: private Class _componentClass;
052:
053: private String _facetName;
054:
055: private Attr _idAttr;
056: private String _prevJsfId;
057:
058: private Attr _bindingAttr;
059:
060: private ArrayList<Attr> _attrList = new ArrayList<Attr>();
061:
062: public void setComponentClass(Class cl) {
063: _componentClass = cl;
064: }
065:
066: public void setNext(JspNode next) {
067: _next = next;
068: }
069:
070: /**
071: * Adds an attribute.
072: */
073: public void addAttribute(QName qName, String value)
074: throws JspParseException {
075: String name = qName.getName();
076:
077: String setterName = ("set"
078: + Character.toUpperCase(name.charAt(0)) + name
079: .substring(1));
080:
081: if (name.equals("action")
082: && ActionSource2.class
083: .isAssignableFrom(_componentClass))
084: setterName = "setActionExpression";
085: else if (name.equals("actionListener")
086: && ActionSource2.class
087: .isAssignableFrom(_componentClass))
088: setterName = "addActionListener";
089:
090: Method method = findSetter(_componentClass, setterName);
091:
092: if (method != null) {
093: _attrList.add(new Attr(name, method, value));
094: } else if (name.equals("binding")) {
095: if (!value.startsWith("#{"))
096: throw error(L
097: .l(
098: "JSF binding attribute requires a deferred value at '{0}'",
099: value));
100:
101: Attr attr = new Attr(name, method, value);
102:
103: _bindingAttr = attr;
104: _attrList.add(attr);
105: } else {
106: super .addAttribute(qName, value);
107: }
108: }
109:
110: /**
111: * Adds a JspAttribute attribute.
112: *
113: * @param qName the name of the attribute.
114: * @param value the value of the attribute.
115: */
116: public void addAttribute(QName qName, JspAttribute value)
117: throws JspParseException {
118: if (value.isStatic()) {
119: addAttribute(qName, value.getStaticText().trim());
120: } else {
121: String name = qName.getName();
122:
123: String setterName = ("set"
124: + Character.toUpperCase(name.charAt(0)) + name
125: .substring(1));
126:
127: Method method = findSetter(_componentClass, setterName);
128:
129: if (method != null) {
130: _attrList.add(new Attr(name, method, value));
131: } else {
132: super .addAttribute(qName, value);
133: return;
134: }
135: }
136: }
137:
138: /**
139: * Called after all the attributes from the tag.
140: */
141: public void endAttributes() throws JspParseException {
142: if (_parent instanceof JsfFacetNode)
143: _facetName = ((JsfFacetNode) _parent).getName();
144:
145: _idAttr = findAttribute("id");
146:
147: if (_idAttr != null)
148: addJsfId(_parent);
149: else if (isJsfIdRequired())
150: addJsfId(this );
151:
152: if (_idAttr == null) {
153: _prevJsfId = getPrevJsfId();
154: }
155: }
156:
157: public void endElement() {
158: if (isJsfParentRequired()) {
159: addJsfId(this );
160: }
161: }
162:
163: String getJsfId() {
164: if (_idAttr != null)
165: return _idAttr.getValue();
166: else
167: return null;
168: }
169:
170: private boolean isJsfIdRequired() {
171: if (EditableValueHolder.class.isAssignableFrom(_componentClass))
172: return true;
173: else if (ActionSource.class.isAssignableFrom(_componentClass))
174: return true;
175: else if (ActionSource2.class.isAssignableFrom(_componentClass))
176: return true;
177: else if (_bindingAttr != null)
178: return true;
179: else if (UISelectItem.class.isAssignableFrom(_componentClass))
180: return true;
181: else if (UISelectItems.class.isAssignableFrom(_componentClass))
182: return true;
183:
184: JspNode parent = _parent;
185:
186: ArrayList<JspNode> children = parent.getChildren();
187:
188: boolean isJsfIdRequired = false;
189:
190: for (int i = 0; i < children.size(); i++) {
191: JspNode child = children.get(i);
192:
193: if (child == this )
194: return isJsfIdRequired;
195: else if (child instanceof JsfTagNode) {
196: JsfTagNode jsfNode = (JsfTagNode) child;
197: String id = jsfNode.getJsfId();
198:
199: if (id != null)
200: isJsfIdRequired = false;
201: } else if (child.isJsfParentRequired())
202: isJsfIdRequired = true;
203: }
204:
205: return false;
206: }
207:
208: private String getPrevJsfId() {
209: JspNode parent = _parent;
210:
211: ArrayList<JspNode> children = parent.getChildren();
212:
213: if (children != null) {
214: boolean isFound = false;
215:
216: for (int i = children.size() - 1; i >= 0; i--) {
217: JspNode child = children.get(i);
218:
219: if (child == this )
220: isFound = true;
221: else if (isFound && child instanceof JsfTagNode) {
222: JsfTagNode jsfNode = (JsfTagNode) child;
223: String id = jsfNode.getJsfId();
224:
225: if (id != null)
226: return id;
227: }
228: }
229: }
230:
231: return null;
232: }
233:
234: private static void addJsfId(JspNode node) {
235: if (node == null)
236: return;
237:
238: addJsfId(node.getParent());
239:
240: if (node instanceof JsfTagNode) {
241: JsfTagNode jsfNode = (JsfTagNode) node;
242:
243: if (jsfNode._idAttr != null)
244: return;
245:
246: jsfNode._idAttr = jsfNode.findAttribute("id");
247:
248: if (jsfNode._idAttr == null) {
249: Method method = jsfNode.findSetter(
250: jsfNode._componentClass, "setId");
251:
252: if (method == null)
253: throw new IllegalStateException(
254: jsfNode._componentClass + " id");
255:
256: String id = "j_id_" + jsfNode._gen.generateJspId();
257:
258: jsfNode._idAttr = new Attr("id", method, id);
259:
260: jsfNode._attrList.add(jsfNode._idAttr);
261: }
262: }
263: }
264:
265: private Attr findAttribute(String name) {
266: for (int i = 0; i < _attrList.size(); i++) {
267: Attr attr = _attrList.get(i);
268:
269: if (attr.getName().equals(name))
270: return attr;
271: }
272:
273: return null;
274: }
275:
276: /**
277: * Generates the XML text representation for the tag validation.
278: *
279: * @param os write stream to the generated XML.
280: */
281: public void printXml(WriteStream os) throws IOException {
282: if (_next != null)
283: _next.printXml(os);
284: }
285:
286: /**
287: * generates prologue data.
288: */
289: @Override
290: public void generatePrologue(JspJavaWriter out) throws Exception {
291: _var = "_jsp_comp" + _gen.uniqueId();
292:
293: super .generatePrologue(out);
294: }
295:
296: /**
297: * Generates the code for a custom tag.
298: *
299: * @param out the output writer for the generated java.
300: */
301: public void generate(JspJavaWriter out) throws Exception {
302: String contextVar = "null";
303:
304: if (_gen.isJsfPrologueInit())
305: contextVar = "_jsp_faces_context";
306:
307: String parentVar = _parent.getJsfVar();
308:
309: String parentBodyVar = _parent.getJsfBodyVar();
310:
311: String prevId;
312:
313: String oldParentVar = null;
314:
315: String bindingVar = null;
316:
317: if (isJsfParentRequired()) {
318: oldParentVar = "_jsp_jsf_parent_" + _gen.uniqueId();
319:
320: out
321: .println("Object "
322: + oldParentVar
323: + " = request.getAttribute(\"caucho.jsf.parent\");");
324: }
325:
326: if (_prevJsfId != null)
327: prevId = "\"" + _prevJsfId + "\"";
328: else
329: prevId = null;
330:
331: if (parentBodyVar != null) {
332: out.println("com.caucho.jsp.jsf.JsfTagUtil.addVerbatim("
333: + parentVar + ", " + prevId + ", " + parentBodyVar
334: + ");");
335: }
336:
337: if (!hasBodyContent()) {
338: } else if (parentBodyVar != null)
339: _bodyVar = parentBodyVar;
340: else {
341: _bodyVar = "_jsp_body" + _gen.uniqueId();
342:
343: out
344: .println("com.caucho.jsp.BodyContentImpl "
345: + _bodyVar
346: + " = (com.caucho.jsp.BodyContentImpl) pageContext.pushBody();");
347: out.println("out = " + _bodyVar + ";");
348: }
349:
350: String className;
351:
352: if (_bindingAttr != null)
353: className = UIComponent.class.getName();
354: else
355: className = _componentClass.getName();
356:
357: out.println(className + " " + _var + ";");
358:
359: if (_bindingAttr != null) {
360: bindingVar = ("_caucho_value_expr_" + _gen.addValueExpr(
361: _bindingAttr.getValue(), UIComponent.class
362: .getName()));
363: }
364:
365: if (_facetName != null) {
366: out.print(_var + " = (" + className + ")");
367: out.println(" com.caucho.jsp.jsf.JsfTagUtil.findFacet("
368: + contextVar + ", request" + ", " + parentVar
369: + ", \"" + _facetName + "\");");
370:
371: out.println("if (" + _var + " == null) {");
372: out.pushDepth();
373:
374: out.print(_var + " = (" + className + ")");
375: out.println(" com.caucho.jsp.jsf.JsfTagUtil.addFacet("
376: + contextVar + ", request" + ", " + parentVar
377: + ", \"" + _facetName + "\"" + ", " + bindingVar
378: + ", " + _componentClass.getName() + ".class);");
379: } else if (_idAttr != null) {
380: out.print(_var + " = (" + className + ")");
381: out
382: .println(" com.caucho.jsp.jsf.JsfTagUtil.findPersistent("
383: + contextVar
384: + ", request"
385: + ", "
386: + parentVar
387: + ", \""
388: + _idAttr.getValue()
389: + "\");");
390:
391: out.println("if (" + _var + " == null) {");
392: out.pushDepth();
393:
394: out.print(_var + " = (" + className + ")");
395: out.println(" com.caucho.jsp.jsf.JsfTagUtil.addPersistent("
396: + contextVar + ", request" + ", " + parentVar
397: + ", " + bindingVar + ", "
398: + _componentClass.getName() + ".class);");
399: } else {
400: out.print(_var + " = (" + className + ")");
401:
402: out.println(" com.caucho.jsp.jsf.JsfTagUtil.addTransient("
403: + contextVar + ", request" + ", " + parentVar
404: + ", " + prevId + ", " + _componentClass.getName()
405: + ".class);");
406: }
407:
408: for (int i = 0; i < _attrList.size(); i++) {
409: Attr attr = (Attr) _attrList.get(i);
410:
411: Method method = attr.getMethod();
412: Class type = null;
413:
414: if (method != null)
415: type = method.getParameterTypes()[0];
416: else if (attr.getName().equals("binding"))
417: type = UIComponent.class;
418:
419: JspAttribute jspAttr = attr.getAttr();
420: String value = attr.getValue();
421:
422: if (jspAttr != null) {
423: generateSetParameter(out, _var, jspAttr, method, true,
424: null, false, null);
425: } else if (ActionListener.class.isAssignableFrom(type)) {
426: String exprVar = "_caucho_method_expr_"
427: + _gen
428: .addMethodExpr(value,
429: "void foo(javax.faces.event.ActionEvent)");
430:
431: out
432: .println(_var
433: + ".addActionListener(new javax.faces.event.MethodExpressionActionListener("
434: + exprVar + "));");
435: } else if ("validator".equals(attr.getName())
436: && UIInput.class.isAssignableFrom(_componentClass)) {
437: out
438: .print("((javax.faces.component.UIInput)"
439: + _var
440: + ").addValidator(new javax.faces.validator.MethodExpressionValidator(");
441:
442: String signature = "void foo(javax.faces.context.FacesContext, javax.faces.component.UIComponent, java.lang.Object)";
443:
444: String exprVar = "_caucho_method_expr_"
445: + _gen.addMethodExpr(value, signature);
446:
447: out.println(exprVar + "));");
448: } else if ("valueChangeListener".equals(attr.getName())
449: && UIInput.class.isAssignableFrom(_componentClass)) {
450: out
451: .print("((javax.faces.component.UIInput)"
452: + _var
453: + ").addValueChangeListener(new javax.faces.event.MethodExpressionValueChangeListener(");
454:
455: String signature = "void foo(javax.faces.event.ValueChangeEvent)";
456:
457: String exprVar = "_caucho_method_expr_"
458: + _gen.addMethodExpr(value, signature);
459:
460: out.println(exprVar + "));");
461: } else if (_bindingAttr != null
462: && !"id".equals(attr.getName())
463: || (value.indexOf("#{") >= 0
464: && !ValueExpression.class
465: .isAssignableFrom(type) && !MethodExpression.class
466: .isAssignableFrom(type))) {
467: // jsf/3153
468: out.print(_var + ".setValueExpression(\""
469: + attr.getName() + "\", ");
470:
471: String exprVar = "_caucho_value_expr_"
472: + _gen.addValueExpr(value, type.getName());
473:
474: out.println(exprVar + ");");
475: } else {
476: out.print(_var + "." + method.getName() + "(");
477:
478: out.print(generateParameterValue(type, value, true,
479: null, false));
480:
481: out.println(");");
482: }
483: }
484:
485: if (_idAttr != null || _facetName != null) {
486: if (oldParentVar != null)
487: out
488: .println("request.setAttribute(\"caucho.jsf.parent\""
489: + ", new com.caucho.jsp.jsf.JsfComponentTag("
490: + _var + ", true, " + _bodyVar + "));");
491:
492: out.popDepth();
493: out.println("}");
494:
495: if (oldParentVar != null) {
496: out.println("else");
497: out
498: .println(" request.setAttribute(\"caucho.jsf.parent\""
499: + ", new com.caucho.jsp.jsf.JsfComponentTag("
500: + _var + ", false, " + _bodyVar + "));");
501: }
502: }
503:
504: generateChildren(out);
505:
506: if (oldParentVar != null) {
507: out.println("request.setAttribute(\"caucho.jsf.parent\", "
508: + oldParentVar + ");");
509: }
510:
511: if (_bodyVar != null && parentBodyVar == null) {
512: out.println("out = pageContext.popBody();");
513: out.println("pageContext.releaseBody(" + _bodyVar + ");");
514: }
515: }
516: }
|