001: /*
002: * Copyright (c) 1998-2006 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.webbeans.bytecode;
031:
032: import java.io.*;
033: import java.util.*;
034: import java.lang.reflect.*;
035:
036: import com.caucho.bytecode.*;
037: import com.caucho.config.*;
038: import com.caucho.loader.*;
039: import com.caucho.webbeans.cfg.*;
040: import com.caucho.webbeans.component.*;
041: import com.caucho.vfs.*;
042:
043: /**
044: * interceptor generation
045: */
046: public class SerializationAdapter {
047: private final Class _cl;
048:
049: private Class _proxyClass;
050:
051: private SerializationAdapter(Class cl) {
052: _cl = cl;
053: }
054:
055: public static Class gen(Class cl) {
056: if (Modifier.isFinal(cl.getModifiers()))
057: return cl;
058: if (HandleAware.class.isAssignableFrom(cl))
059: return cl;
060:
061: SerializationAdapter gen = new SerializationAdapter(cl);
062:
063: Class proxyClass = gen.generateProxy();
064:
065: return proxyClass;
066: }
067:
068: public static void setHandle(Object obj, Object handle) {
069: try {
070: Class cl = obj.getClass();
071:
072: for (Field field : cl.getDeclaredFields()) {
073: if (field.getName().equals("__caucho_handle")) {
074: field.setAccessible(true);
075: field.set(obj, handle);
076: }
077: }
078: } catch (Exception e) {
079: throw ConfigException.create(e);
080: }
081: }
082:
083: private Class generateProxy() {
084: try {
085: JavaClassLoader jLoader = new JavaClassLoader(_cl
086: .getClassLoader());
087:
088: JavaClass jClass = new JavaClass(jLoader);
089: jClass.setAccessFlags(Modifier.PUBLIC);
090: ConstantPool cp = jClass.getConstantPool();
091:
092: jClass.setWrite(true);
093:
094: jClass.setMajor(49);
095: jClass.setMinor(0);
096:
097: String super ClassName = _cl.getName().replace('.', '/');
098: String this ClassName = super ClassName + "$BeanProxy";
099:
100: jClass.setSuperClass(super ClassName);
101: jClass.setThisClass(this ClassName);
102:
103: jClass.addInterface("java/io/Serializable");
104:
105: generateConstructors(jClass, super ClassName);
106:
107: generateWriteReplace(jClass);
108:
109: ByteArrayOutputStream bos = new ByteArrayOutputStream();
110: WriteStream out = Vfs.openWrite(bos);
111:
112: jClass.write(out);
113:
114: out.close();
115:
116: byte[] buffer = bos.toByteArray();
117:
118: if (false) {
119: out = Vfs.lookup("file:/tmp/caucho/qa/temp.class")
120: .openWrite();
121: out.write(buffer, 0, buffer.length);
122: out.close();
123: }
124:
125: String cleanName = this ClassName.replace('/', '.');
126: _proxyClass = new ProxyClassLoader().loadClass(cleanName,
127: buffer);
128: } catch (RuntimeException e) {
129: throw e;
130: } catch (Exception e) {
131: throw new RuntimeException(e);
132: }
133:
134: return _proxyClass;
135: }
136:
137: private void generateConstructors(JavaClass jClass,
138: String super ClassName) {
139: for (Constructor baseCtor : _cl.getDeclaredConstructors()) {
140: if (Modifier.isPrivate(baseCtor.getModifiers()))
141: continue;
142:
143: generateConstructor(jClass, super ClassName, baseCtor);
144: }
145: }
146:
147: public static void generateConstructor(JavaClass jClass,
148: String super ClassName, Constructor baseCtor) {
149: Class[] types = baseCtor.getParameterTypes();
150:
151: StringBuilder sb = new StringBuilder();
152: createDescriptor(sb, types);
153: sb.append("V");
154:
155: String descriptor = sb.toString();
156:
157: JavaMethod ctor = jClass.createMethod("<init>", descriptor);
158:
159: ctor.setAccessFlags(Modifier.PUBLIC);
160:
161: CodeWriterAttribute code = ctor.createCodeWriter();
162: code.setMaxLocals(5 + 2 * types.length);
163: code.setMaxStack(5 + 2 * types.length);
164:
165: code.pushObjectVar(0);
166:
167: marshal(code, types);
168:
169: code.invokespecial(super ClassName, "<init>", descriptor, 1, 0);
170: code.addReturn();
171: code.close();
172: }
173:
174: private void generateWriteReplace(JavaClass jClass) {
175: JavaField jField = jClass.createField("__caucho_handle",
176: "Ljava/lang/Object;");
177: jField.setAccessFlags(Modifier.PRIVATE);
178:
179: JavaMethod jMethod = jClass.createMethod("writeReplace",
180: "()Ljava/lang/Object;");
181:
182: jMethod.setAccessFlags(Modifier.PRIVATE);
183:
184: CodeWriterAttribute code = jMethod.createCodeWriter();
185: code.setMaxLocals(5);
186: code.setMaxStack(5);
187:
188: code.pushObjectVar(0);
189: code.getField(jClass.getThisClass(), "__caucho_handle",
190: "Ljava/lang/Object;");
191:
192: code.addObjectReturn();
193:
194: code.close();
195: }
196:
197: public static void marshal(CodeWriterAttribute code, Class[] param) {
198: int stack = 1;
199: int index = 1;
200:
201: for (int i = 0; i < param.length; i++) {
202: Class type = param[i];
203:
204: if (boolean.class.equals(type) || byte.class.equals(type)
205: || short.class.equals(type)
206: || int.class.equals(type)) {
207: code.pushIntVar(index);
208: index += 1;
209: stack += 1;
210: } else if (long.class.equals(type)) {
211: code.pushLongVar(index);
212: index += 2;
213: stack += 2;
214: } else if (float.class.equals(type)) {
215: code.pushFloatVar(index);
216: index += 1;
217: stack += 1;
218: } else if (double.class.equals(type)) {
219: code.pushDoubleVar(index);
220: index += 2;
221: stack += 2;
222: } else {
223: code.pushObjectVar(index);
224: index += 1;
225: stack += 1;
226: }
227: }
228: }
229:
230: private int parameterCount(Class[] parameters) {
231: int count = 0;
232:
233: for (Class param : parameters) {
234: if (long.class.equals(param) || double.class.equals(param))
235: count += 2;
236: else
237: count += 1;
238: }
239:
240: return count;
241: }
242:
243: public static void createDescriptor(StringBuilder sb, Class[] params) {
244: sb.append("(");
245:
246: for (Class param : params) {
247: sb.append(createDescriptor(param));
248: }
249:
250: sb.append(")");
251: }
252:
253: public static String createDescriptor(Class cl) {
254: if (cl.isArray())
255: return "[" + createDescriptor(cl.getComponentType());
256:
257: String primValue = _prim.get(cl);
258:
259: if (primValue != null)
260: return primValue;
261:
262: return "L" + cl.getName().replace('.', '/') + ";";
263: }
264:
265: private static HashMap<Class, String> _prim = new HashMap<Class, String>();
266: private static HashMap<Class, String> _boxClass = new HashMap<Class, String>();
267:
268: static {
269: _prim.put(boolean.class, "Z");
270: _prim.put(byte.class, "B");
271: _prim.put(char.class, "C");
272: _prim.put(short.class, "S");
273: _prim.put(int.class, "I");
274: _prim.put(long.class, "J");
275: _prim.put(float.class, "F");
276: _prim.put(double.class, "D");
277: _prim.put(void.class, "V");
278:
279: _boxClass.put(boolean.class, "java/lang/Boolean");
280: _boxClass.put(byte.class, "java/lang/Byte");
281: _boxClass.put(char.class, "java/lang/Character");
282: _boxClass.put(short.class, "java/lang/Short");
283: _boxClass.put(int.class, "java/lang/Integer");
284: _boxClass.put(long.class, "java/lang/Long");
285: _boxClass.put(float.class, "java/lang/Float");
286: _boxClass.put(double.class, "java/lang/Double");
287: }
288: }
|