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: * Free SoftwareFoundation, Inc.
023: * 59 Temple Place, Suite 330
024: * Boston, MA 02111-1307 USA
025: *
026: * @author Scott Ferguson
027: */
028:
029: package com.caucho.jsp.java;
030:
031: import com.caucho.jsp.JspParseException;
032: import com.caucho.util.BeanUtil;
033: import com.caucho.vfs.WriteStream;
034: import com.caucho.xml.QName;
035:
036: import java.beans.BeanInfo;
037: import java.beans.Introspector;
038: import java.beans.PropertyDescriptor;
039: import java.beans.PropertyEditor;
040: import java.beans.PropertyEditorManager;
041: import java.io.IOException;
042: import java.lang.reflect.Method;
043: import java.util.logging.Level;
044:
045: /**
046: * Represents a Java scriptlet.
047: */
048: public class JspSetProperty extends JspContainerNode {
049: private static final QName NAME = new QName("name");
050: private static final QName PROPERTY = new QName("property");
051: private static final QName PARAM = new QName("param");
052: private static final QName VALUE = new QName("value");
053:
054: private String _name;
055: private String _property;
056: private String _param;
057:
058: /**
059: * Adds an attribute.
060: */
061: public void addAttribute(QName name, String value)
062: throws JspParseException {
063: if (NAME.equals(name))
064: _name = value;
065: else if (PROPERTY.equals(name))
066: _property = value;
067: else if (PARAM.equals(name))
068: _param = value;
069: else if (VALUE.equals(name))
070: super .addAttribute(name, value);
071: else
072: throw error(L
073: .l(
074: "`{0}' is an invalid attribute in <jsp:setProperty>",
075: name.getName()));
076: }
077:
078: /**
079: * Generates the XML text representation for the tag validation.
080: *
081: * @param os write stream to the generated XML.
082: */
083: public void printXml(WriteStream os) throws IOException {
084: os.print("<jsp:setProperty name=\"" + _name + "\"");
085: os.print(" property=\"" + _property + "\"/>");
086: }
087:
088: /**
089: * Generates the code for the scriptlet
090: *
091: * @param out the output writer for the generated java.
092: */
093: public void generate(JspJavaWriter out) throws Exception {
094: if (_name == null)
095: throw error(L
096: .l("<jsp:setProperty> expects a `name' attribute."));
097:
098: if (_property == null)
099: throw error(L
100: .l("<jsp:setProperty> expects a `property' attribute."));
101:
102: Object value = getAttribute("value");
103:
104: if (value == null) {
105: generateSetParamProperty(out, _name, _property, _param);
106: return;
107: }
108:
109: Class cl = _gen.getClass(_name);
110:
111: if (cl == null)
112: throw error(L
113: .l(
114: "`{0}' is an unknown bean in <jsp:setProperty>. All beans must be declared in a <jsp:useBean>.",
115: _name));
116:
117: PropertyDescriptor[] pds = Introspector.getBeanInfo(cl)
118: .getPropertyDescriptors();
119: for (int i = 0; i < pds.length; i++) {
120: if (pds[i].getName().equals(_property)
121: && pds[i].getWriteMethod() != null
122: && pds[i].getPropertyEditorClass() != null) {
123: generateSetParameter(out, _name, (String) value, pds[i]
124: .getWriteMethod(), pds[i]
125: .getPropertyEditorClass());
126: return;
127: }
128: }
129:
130: Method setMethod = BeanUtil.getSetMethod(cl, _property);
131: if (setMethod == null)
132: throw error(L.l("bean `{0}' has no set property `{1}'",
133: _name, _property));
134:
135: generateSetParameter(out, _name, value, setMethod, true,
136: "pageContext", false, null);
137: }
138:
139: private void generateSetParamProperty(JspJavaWriter out,
140: String name, String property, String param)
141: throws Exception {
142: boolean foundProp = property.equals("*");
143: Class cl = _gen.getClass(name);
144: if (cl == null)
145: throw error(L.l("{0} unknown variable `{1}'",
146: "jsp:setProperty", name));
147:
148: out.println("{");
149: out.pushDepth();
150: out.println("java.lang.String _jspParam;");
151: try {
152: Class beanClass = cl;
153: BeanInfo info = Introspector.getBeanInfo(beanClass);
154: Method[] methods = beanClass.getMethods();
155: boolean hasParams = false;
156: for (int i = 0; i < methods.length; i++) {
157: Method setMethod = methods[i];
158:
159: String methodName = setMethod.getName();
160:
161: if (!methodName.startsWith("set"))
162: continue;
163:
164: String propName = methodNameToPropertyName(info,
165: methodName);
166:
167: if (propName == null)
168: continue;
169:
170: if (!property.equals("*") && !propName.equals(property))
171: continue;
172:
173: Class[] params = setMethod.getParameterTypes();
174: if (params.length != 1)
175: continue;
176:
177: if (hasBetterMethod(methods, setMethod))
178: continue;
179:
180: Class paramType = params[0];
181: String type = paramType.getName();
182: String tail = null;
183: boolean isArray = false;
184:
185: String p = param;
186: if (p == null)
187: p = propName;
188:
189: if (!paramType.isArray())
190: tail = stringToValue(paramType, "_jspParam");
191:
192: PropertyEditor editor;
193:
194: if (tail != null) {
195: } else if (paramType.isArray()) {
196: Class compType = paramType.getComponentType();
197: if (!hasParams)
198: out.println("java.lang.String []_jspParams;");
199: hasParams = true;
200: out
201: .println("_jspParams = request.getParameterValues(\""
202: + p + "\");");
203: isArray = true;
204:
205: if (String.class.equals(compType)
206: || Object.class.equals(compType)) {
207: foundProp = true;
208: out.println("if (_jspParams != null)");
209: out.println(" " + name + "." + methodName
210: + "(_jspParams);");
211: } else if ((tail = stringToValue(compType,
212: "_jspParams[_jsp_i]")) != null) {
213: foundProp = true;
214: out.println("if (_jspParams != null) {");
215: out.println(" " + compType.getName()
216: + " []_jsp_values = " + " new "
217: + compType.getName()
218: + "[_jspParams.length];");
219: out
220: .println(" for (int _jsp_i = _jspParams.length - 1; _jsp_i >= 0; _jsp_i--)");
221: out.println(" _jsp_values[_jsp_i] = " + tail
222: + ";");
223: out.println(" " + name + "." + methodName
224: + "(_jsp_values);");
225: out.println("}");
226: } else if ((editor = PropertyEditorManager
227: .findEditor(paramType)) != null) {
228: foundProp = true;
229: out.println("if (_jspParams != null) {");
230: out.println(" " + compType.getName()
231: + " []_jsp_values = " + " new "
232: + compType.getName()
233: + "[_jspParams.length];");
234: out
235: .println(" java.beans.PropertyEditor _editor = "
236: + " java.beans.PropertyEditorManager.findEditor("
237: + compType.getName()
238: + ".class);");
239: out
240: .println(" for (int _jsp_i = _jspParams.length - 1; _jsp_i >= 0; _jsp_i--) {");
241: out
242: .println(" _editor.setAsText(_jspParams[_jsp_i]);");
243:
244: out.println(" _jsp_values[_jsp_i] = ("
245: + compType.getName()
246: + ") _editor.getValue();");
247:
248: out.println(" " + name + "." + methodName
249: + "(_jsp_values);");
250: out.println("}");
251: }
252: }
253:
254: if (isArray) {
255: } else if (tail != null) {
256: out.println("_jspParam = request.getParameter(\""
257: + p + "\");");
258: out
259: .println("if (_jspParam != null && ! _jspParam.equals(\"\"))");
260: out.println(" " + name + "." + methodName + "("
261: + tail + ");");
262: foundProp = true;
263: } else if ((editor = PropertyEditorManager
264: .findEditor(paramType)) != null) {
265: out.println("_jspParam = request.getParameter(\""
266: + p + "\");");
267: out
268: .println("if (_jspParam != null && ! _jspParam.equals(\"\")) {");
269: out
270: .println(" java.beans.PropertyEditor _editor = "
271: + " java.beans.PropertyEditorManager.findEditor("
272: + paramType.getName() + ".class);");
273: out.println(" _editor.setAsText(_jspParam);");
274: out.println(" " + name + "." + methodName + "(("
275: + paramType.getName()
276: + ") _editor.getValue());");
277: out.println("}");
278: foundProp = true;
279: }
280: }
281: } catch (Exception e) {
282: log.log(Level.FINER, e.toString(), e);
283:
284: throw error(L.l("{0} can't find class `{1}'",
285: "jsp:setProperty", name));
286: }
287:
288: if (!foundProp)
289: throw error(L.l("bean `{0}' has no property named `{1}'",
290: name, property));
291:
292: out.popDepth();
293: out.println("}");
294: }
295:
296: /**
297: * Returns true if there's a better method to set.
298: */
299: private boolean hasBetterMethod(Method[] methods, Method setMethod) {
300: Class[] setParam = setMethod.getParameterTypes();
301:
302: if (setParam[0].equals(String.class))
303: return false;
304:
305: for (int i = 0; i < methods.length; i++) {
306: Method method = methods[i];
307:
308: if (method == setMethod)
309: continue;
310:
311: if (!method.getName().equals(setMethod.getName()))
312: continue;
313:
314: Class[] param = method.getParameterTypes();
315:
316: if (param.length != 1)
317: continue;
318:
319: if (param[0].equals(String.class))
320: return true;
321: }
322:
323: return false;
324: }
325:
326: private String methodNameToPropertyName(BeanInfo info,
327: String methodName) {
328: PropertyDescriptor[] pds = info.getPropertyDescriptors();
329:
330: for (int i = 0; i < pds.length; i++) {
331: Method setter = pds[i].getWriteMethod();
332:
333: if (setter != null && setter.getName().equals(methodName))
334: return pds[i].getName();
335: }
336:
337: return BeanUtil.methodNameToPropertyName(methodName);
338: }
339: }
|