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.ejb.hessian;
030:
031: import com.caucho.java.AbstractGenerator;
032: import com.caucho.loader.DynamicClassLoader;
033: import com.caucho.util.CharBuffer;
034: import com.caucho.util.IntMap;
035: import com.caucho.vfs.Path;
036:
037: import java.io.IOException;
038: import java.lang.reflect.Method;
039: import java.util.ArrayList;
040:
041: /**
042: * Base class for generating code to marshal and unmarshal sml-rpc calls.
043: */
044: abstract class MarshalGenerator extends AbstractGenerator {
045: // Classes which can be safely passed by reference because they're
046: // immutable and part of the JDK
047: static IntMap immutableClasses;
048:
049: protected static Class readerClass;
050: protected static Class inputStreamClass;
051: protected static Class remoteClass;
052: protected static Class nodeClass;
053:
054: static {
055: readerClass = java.io.Reader.class;
056: inputStreamClass = java.io.InputStream.class;
057: remoteClass = java.rmi.Remote.class;
058: nodeClass = org.w3c.dom.Node.class;
059: }
060:
061: protected Class _cl;
062: String objClass;
063: String fullName;
064: String pkg;
065: String className;
066:
067: protected int unique;
068:
069: protected ArrayList marshallClasses;
070: protected ArrayList unmarshallClasses;
071:
072: protected ArrayList marshallArrays;
073: protected ArrayList unmarshallArrays;
074:
075: /**
076: * Initialize the generated classname.
077: *
078: * @param beanClass the bean which needs the stub/skeleton
079: *
080: * @return the path to the file to be generated
081: */
082: Path initClassNames(Class beanClass, String suffix)
083: throws Exception {
084: ClassLoader parentLoader = getParentLoader();
085:
086: if (parentLoader instanceof DynamicClassLoader) {
087: DynamicClassLoader dcl = (DynamicClassLoader) parentLoader;
088:
089: dcl.make();
090: }
091:
092: Path workPath = getClassDir();
093:
094: _cl = beanClass;
095:
096: fullName = _cl.getName() + suffix;
097:
098: objClass = _cl.getName();
099: int p = objClass.lastIndexOf('.');
100: if (p > 0)
101: objClass = objClass.substring(p + 1);
102:
103: p = fullName.lastIndexOf('.');
104: if (p > 0) {
105: pkg = fullName.substring(0, p);
106: className = fullName.substring(p + 1);
107: } else
108: className = fullName;
109:
110: Path path = workPath.lookup(fullName.replace('.', '/')
111: + ".java");
112: path.getParent().mkdirs();
113:
114: return path;
115: }
116:
117: /**
118: * Creates a unique mangled method name based on the method name and
119: * the method parameters.
120: *
121: * @param name the base method name
122: * @param method the method to mangle
123: * @param isFull if true, mangle the full classname
124: *
125: * @return a mangled string.
126: */
127: protected String mangleMethodName(String name, Method method,
128: boolean isFull) {
129: CharBuffer cb = CharBuffer.allocate();
130:
131: cb.append(name);
132:
133: Class[] params = method.getParameterTypes();
134: for (int i = 0; i < params.length; i++) {
135: cb.append('_');
136: mangleClass(cb, params[i], isFull);
137: }
138:
139: return cb.close();
140: }
141:
142: /**
143: * Creates a unique mangled method name based on the method name and
144: * the method parameters.
145: *
146: * @param name the base method name
147: * @param method the method to mangle
148: * @param isFull if true, mangle the full classname
149: *
150: * @return a mangled string.
151: */
152: protected String mangleMethodName(String name, Class[] param,
153: boolean isFull) {
154: CharBuffer cb = CharBuffer.allocate();
155:
156: cb.append(name);
157:
158: for (int i = 0; i < param.length; i++) {
159: cb.append('_');
160: mangleClass(cb, param[i], isFull);
161: }
162:
163: return cb.close();
164: }
165:
166: /**
167: * Mangles a classname.
168: */
169: private void mangleClass(CharBuffer cb, Class cl, boolean isFull) {
170: String name = cl.getName();
171:
172: if (name.equals("boolean"))
173: cb.append("boolean");
174: else if (name.equals("int") || name.equals("short")
175: || name.equals("byte"))
176: cb.append("int");
177: else if (name.equals("long"))
178: cb.append("long");
179: else if (name.equals("double") || name.equals("float"))
180: cb.append("double");
181: else if (name.equals("java.lang.String")
182: || name.equals("com.caucho.util.CharBuffer")
183: || name.equals("char") || name.equals("java.io.Reader"))
184: cb.append("string");
185: else if (name.equals("java.util.Date")
186: || name.equals("com.caucho.util.QDate"))
187: cb.append("date");
188: else if (inputStreamClass.isAssignableFrom(cl)
189: || name.equals("[B"))
190: cb.append("binary");
191: else if (cl.isArray()) {
192: cb.append("[");
193: mangleClass(cb, cl.getComponentType(), isFull);
194: } else if (name.equals("org.w3c.dom.Node")
195: || name.equals("org.w3c.dom.Element")
196: || name.equals("org.w3c.dom.Document"))
197: cb.append("xml");
198: else if (isFull)
199: cb.append(name);
200: else {
201: int p = name.lastIndexOf('.');
202: if (p > 0)
203: cb.append(name.substring(p + 1));
204: else
205: cb.append(name);
206: }
207: }
208:
209: /**
210: * Prints a method declaration with a given name.
211: *
212: * @param name the name to use for the generated method
213: * @param method the method to override
214: */
215: protected void printMethodDeclaration(String name, Method method)
216: throws IOException {
217: Class ret = method.getReturnType();
218: Class[] params = method.getParameterTypes();
219:
220: Class[] exns = method.getExceptionTypes();
221:
222: println();
223: print("public ");
224: printClass(ret);
225: print(" " + name + "(");
226: for (int i = 0; i < params.length; i++) {
227: if (i != 0)
228: print(", ");
229: printClass(params[i]);
230: print(" _arg" + i);
231: }
232: println(")");
233: if (exns.length > 0)
234: print(" throws ");
235: for (int i = 0; i < exns.length; i++) {
236: if (i != 0)
237: print(", ");
238: printClass(exns[i]);
239: }
240: if (exns.length > 0)
241: println();
242: }
243:
244: /**
245: * Unmarshal the reading of a single variable, knowing the result
246: * type.
247: *
248: * @param var the generated java variable which will receive the data.
249: * @param cl the class of the target variable.
250: */
251: protected void printUnmarshalType(Class cl) throws IOException {
252: String name = cl.getName();
253:
254: if (cl.equals(boolean.class)) {
255: println("in.readBoolean();");
256: } else if (cl.equals(int.class)) {
257: println("in.readInt();");
258: } else if (cl.equals(short.class) || cl.equals(char.class)
259: || cl.equals(byte.class)) {
260: println("(" + name + ") in.readInt();");
261: } else if (cl.equals(long.class)) {
262: println("in.readLong();");
263: } else if (cl.equals(double.class)) {
264: println("in.readDouble();");
265: } else if (cl.equals(float.class)) {
266: println("(" + name + ") in.readDouble();");
267: } else if (cl.equals(String.class))
268: println("in.readString();");
269: else if (cl.equals(java.util.Date.class)) {
270: println("new java.util.Date(in.readUTCDate());");
271: } else if (cl.equals(byte[].class)) {
272: println("in.readBytes();");
273: } else if (org.w3c.dom.Node.class.isAssignableFrom(cl)) {
274: println("in.readNode();");
275: } else if (cl.equals(java.lang.Object.class)) {
276: println("in.readObject();");
277: } else {
278: print("(");
279: printClass(cl);
280: print(") in.readObject(");
281: printClass(cl);
282: println(".class);");
283: }
284: }
285:
286: protected void printMarshalType(Class cl, String var)
287: throws IOException {
288: String name = cl.getName();
289:
290: if (cl.equals(void.class)) {
291: println("out.writeNull();");
292: } else if (cl.equals(boolean.class)) {
293: println("out.writeBoolean(" + var + ");");
294: } else if (cl.equals(int.class) || cl.equals(short.class)
295: || cl.equals(char.class) || cl.equals(byte.class)) {
296: println("out.writeInt(" + var + ");");
297: } else if (cl.equals(long.class)) {
298: println("out.writeLong(" + var + ");");
299: } else if (cl.equals(double.class) || cl.equals(float.class)) {
300: println("out.writeDouble(" + var + ");");
301: } else if (cl.equals(String.class)) {
302: println("out.writeString(" + var + ");");
303: } else if (cl.equals(java.util.Date.class)) {
304: println("out.writeUTCDate(" + var + " == null ? 0 : " + var
305: + ".getTime());");
306: } else if (org.w3c.dom.Node.class.isAssignableFrom(cl)) {
307: println("out.writeXml(" + var + ");");
308: } else if (cl.equals(byte[].class)) {
309: println("out.writeBytes(" + var + ");");
310: } else {
311: println("out.writeObject(" + var + ");");
312: }
313: }
314:
315: /**
316: * Returns true if the class needs serialization.
317: *
318: * @param cl the class to test.
319: *
320: * @return true if the class needs serialization
321: */
322: boolean needsSerialization(Class cl) {
323: if (cl.isPrimitive())
324: return false;
325: else
326: return immutableClasses.get(cl) < 0;
327: }
328:
329: public void printClass(Class cl) throws IOException {
330: if (!cl.isArray())
331: print(cl.getName());
332: else {
333: printClass(cl.getComponentType());
334: print("[]");
335: }
336: }
337:
338: protected void printNewArray(Class cl) throws IOException {
339: if (!cl.isArray()) {
340: print(cl.getName());
341: print("[length]");
342: } else {
343: printNewArray(cl.getComponentType());
344: print("[]");
345: }
346: }
347:
348: static {
349: immutableClasses = new IntMap();
350: immutableClasses.put(String.class, 1);
351: immutableClasses.put(Byte.class, 1);
352: immutableClasses.put(Character.class, 1);
353: immutableClasses.put(Short.class, 1);
354: immutableClasses.put(Integer.class, 1);
355: immutableClasses.put(Long.class, 1);
356: immutableClasses.put(Float.class, 1);
357: immutableClasses.put(Double.class, 1);
358: immutableClasses.put(Class.class, 1);
359: }
360: }
|