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.vfs.WriteStream;
033: import com.caucho.xml.QName;
034:
035: import java.io.IOException;
036: import java.lang.reflect.Constructor;
037: import java.lang.reflect.Modifier;
038:
039: /**
040: * Represents a Java scriptlet.
041: */
042: public class JspUseBean extends JspContainerNode {
043: private static final QName ID = new QName("id");
044: private static final QName TYPE = new QName("type");
045: private static final QName CLASS = new QName("class");
046: private static final QName BEAN_NAME = new QName("beanName");
047: private static final QName SCOPE = new QName("scope");
048:
049: private String _id;
050: private String _typeName;
051: private String _className;
052: private String _beanName;
053: private String _scope;
054:
055: /**
056: * Adds an attribute.
057: */
058: public void addAttribute(QName name, String value)
059: throws JspParseException {
060: if (ID.equals(name))
061: _id = value;
062: else if (TYPE.equals(name))
063: _typeName = value;
064: else if (CLASS.equals(name))
065: _className = value;
066: else if (BEAN_NAME.equals(name))
067: _beanName = value;
068: else if (SCOPE.equals(name))
069: _scope = value;
070: else
071: throw error(L.l(
072: "'{0}' is an invalid attribute in <jsp:useBean>",
073: name.getName()));
074: }
075:
076: /**
077: * Adds text to the scriptlet.
078: */
079: public JspNode addText(String text) throws JspParseException {
080: JspNode node = new StaticText(_gen, text, this );
081:
082: addChild(node);
083:
084: return node;
085: }
086:
087: /**
088: * Generates the XML text representation for the tag validation.
089: *
090: * @param os write stream to the generated XML.
091: */
092: public void printXml(WriteStream os) throws IOException {
093: os.print("<jsp:userBean");
094:
095: if (_id != null)
096: os.print(" id=\"" + _id + "\"");
097: if (_typeName != null)
098: os.print(" type=\"" + _typeName + "\"");
099: if (_className != null)
100: os.print(" class=\"" + _className + "\"");
101: if (_beanName != null)
102: os.print(" beanName=\"" + _beanName + "\"");
103: if (_scope != null)
104: os.print(" scope=\"" + _scope + "\"");
105: os.print("/>");
106: }
107:
108: /**
109: * Generates the code for the scriptlet
110: *
111: * @param out the output writer for the generated java.
112: */
113: public void generate(JspJavaWriter out) throws Exception {
114: if (_id == null)
115: throw error(L
116: .l("<jsp:useBean> expects an 'id' attribute. id specifies the variable name for the bean."));
117:
118: if (_typeName == null)
119: _typeName = _className;
120:
121: if (_typeName == null)
122: throw error(L
123: .l("<jsp:useBean> expects a 'type' or 'class' attribute. The 'type' specifies the Java type of the bean."));
124:
125: // Save the bean's type
126: _gen.addBeanClass(_id, _typeName);
127:
128: String context = null;
129: if (_scope == null || _scope.equals("page"))
130: context = "pageContext";
131: else if (_scope.equals("request")) {
132: context = "pageContext.getRequest()";
133: } else if (_scope.equals("session")) {
134: context = "pageContext.getSession()";
135: } else if (_scope.equals("application")) {
136: context = "pageContext.getApplication()";
137: } else
138: throw error(L
139: .l(
140: "Unknown scope '{0}' in <jsp:useBean>. Scope must be 'page', 'request', 'session', or 'application'.",
141: _scope));
142:
143: // declare the bean
144: out.println(_typeName + " " + _id + ";");
145:
146: // application and session beans need synchronization
147: if ("application".equals(_scope) || "session".equals(_scope)) {
148: out.println("synchronized (" + context + ") {");
149: out.pushDepth();
150: }
151:
152: // try to get the bean from the context
153: out.print(_id + " = (" + _typeName + ") " + context);
154: out.println(".getAttribute(\"" + _id + "\");");
155:
156: // If the bean is new, then instantiate it
157: out.println("if (" + _id + " == null) {");
158: out.pushDepth();
159:
160: boolean canInstantiate = false;
161:
162: // instantiate a class
163: if (_className != null) {
164: String msg = canInstantiateBean(_className);
165: if (msg == null) {
166: out.println(_id + " = new " + _className + "();");
167: canInstantiate = true;
168: } else
169: out
170: .println("throw new java.lang.InstantiationException(\""
171: + msg + "\");");
172: } else if (_beanName == null)
173: out
174: .println("throw new java.lang.InstantiationException(\"jsp:useBean needs 'bean' or 'class'\");");
175: // instantiate beans with a request time attribute
176: else if (hasRuntimeAttribute(_beanName)) {
177: String beanName = getRuntimeAttribute(_beanName);
178: out
179: .println(_id
180: + " = ("
181: + _typeName
182: + ") java.beans.Beans.instantiate(getClass().getClassLoader(), "
183: + beanName + ");");
184: canInstantiate = true;
185: }
186: // instantiate a beans
187: else {
188: out
189: .println(_id
190: + " = ("
191: + _typeName
192: + ") java.beans.Beans.instantiate(getClass().getClassLoader(), \""
193: + _beanName + "\");");
194: canInstantiate = true;
195: }
196:
197: // Save it in the context
198: if (!canInstantiate) {
199: } else
200: out.println(context + ".setAttribute(\"" + _id + "\", "
201: + _id + ");");
202:
203: // Initialize the new bean
204: if (canInstantiate)
205: generateChildren(out);
206:
207: out.popDepth();
208: out.println("}");
209:
210: // Close the synchronization if necessary
211: if ("application".equals(_scope) || "session".equals(_scope)) {
212: out.popDepth();
213: out.println("}");
214: }
215: }
216:
217: /**
218: * Tests if the bean can be instantiated.
219: */
220: private String canInstantiateBean(String className)
221: throws Exception {
222: try {
223: Class cl = _gen.getBeanClass(className);
224: int modifiers = cl.getModifiers();
225: if (Modifier.isInterface(modifiers))
226: return L.l("'{0}' is an interface", className);
227: if (Modifier.isAbstract(modifiers))
228: return L.l("'{0}' is abstract", className);
229: if (!Modifier.isPublic(modifiers))
230: return L.l("'{0}' must be public", className);
231:
232: Constructor[] constructors = cl.getConstructors();
233: for (int i = 0; i < constructors.length; i++) {
234:
235: Class[] param = constructors[i].getParameterTypes();
236: if (param.length == 0)
237: return null;
238: }
239: } catch (Exception e) {
240: throw error(e.getMessage());
241: }
242:
243: return L.l("'{0}' has no public zero-arg constructor",
244: className);
245: }
246: }
|