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.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.util.*;
042: import com.caucho.vfs.*;
043:
044: /**
045: * Scope adapting
046: */
047: public class ScopeAdapter {
048: private static final L10N L = new L10N(ScopeAdapter.class);
049:
050: private final Class _cl;
051:
052: private Class _proxyClass;
053: private Constructor _proxyCtor;
054:
055: private ScopeAdapter(Class cl) {
056: _cl = cl;
057:
058: generateProxy(cl);
059: }
060:
061: public static ScopeAdapter create(Class cl) {
062: ScopeAdapter adapter = new ScopeAdapter(cl);
063:
064: return adapter;
065: }
066:
067: public Object wrap(ComponentImpl comp) {
068: try {
069: Object v = _proxyCtor.newInstance(comp);
070: return v;
071: } catch (Exception e) {
072: throw ConfigException.create(e);
073: }
074: }
075:
076: private void generateProxy(Class cl) {
077: try {
078: Constructor zeroCtor = null;
079:
080: for (Constructor ctorItem : cl.getConstructors()) {
081: if (ctorItem.getParameterTypes().length == 0) {
082: if (Modifier.isPublic(ctorItem.getModifiers())
083: || Modifier.isProtected(ctorItem
084: .getModifiers())) {
085: zeroCtor = ctorItem;
086: break;
087: }
088: }
089: }
090:
091: if (zeroCtor == null) {
092: throw new ConfigException(
093: L
094: .l(
095: "'{0}' does not have a zero-arg public or protected constructor. Scope adapter components need a zero-arg constructor, e.g. @RequestScoped stored in @ApplicationScoped.",
096: cl.getName()));
097: }
098:
099: JavaClassLoader jLoader = new JavaClassLoader(cl
100: .getClassLoader());
101:
102: JavaClass jClass = new JavaClass(jLoader);
103: jClass.setAccessFlags(Modifier.PUBLIC);
104: ConstantPool cp = jClass.getConstantPool();
105:
106: jClass.setWrite(true);
107:
108: jClass.setMajor(49);
109: jClass.setMinor(0);
110:
111: String super ClassName = cl.getName().replace('.', '/');
112: String this ClassName = super ClassName + "$ScopeProxy";
113:
114: jClass.setSuperClass(super ClassName);
115: jClass.setThisClass(this ClassName);
116:
117: JavaField jField = jClass.createField("_cxt",
118: "Lcom/caucho/webbeans/component/ComponentImpl;");
119: jField.setAccessFlags(Modifier.PRIVATE);
120:
121: JavaMethod ctor = jClass.createMethod("<init>",
122: "(Lcom/caucho/webbeans/component/ComponentImpl;)V");
123: ctor.setAccessFlags(Modifier.PUBLIC);
124:
125: CodeWriterAttribute code = ctor.createCodeWriter();
126: code.setMaxLocals(2);
127: code.setMaxStack(4);
128:
129: code.pushObjectVar(0);
130: code.invokespecial(super ClassName, "<init>", "()V", 1, 0);
131: code.pushObjectVar(0);
132: code.pushObjectVar(1);
133: code.putField(this ClassName, jField.getName(), jField
134: .getDescriptor());
135: code.addReturn();
136: code.close();
137:
138: for (Method method : _cl.getMethods()) {
139: if (Modifier.isStatic(method.getModifiers()))
140: continue;
141: if (Modifier.isFinal(method.getModifiers()))
142: continue;
143:
144: createProxyMethod(jClass, method);
145: }
146:
147: ByteArrayOutputStream bos = new ByteArrayOutputStream();
148: WriteStream out = Vfs.openWrite(bos);
149:
150: jClass.write(out);
151:
152: out.close();
153:
154: byte[] buffer = bos.toByteArray();
155:
156: /*
157: out = Vfs.lookup("file:/tmp/caucho/qa/temp.class").openWrite();
158: out.write(buffer, 0, buffer.length);
159: out.close();
160: */
161:
162: String cleanName = this ClassName.replace('/', '.');
163: _proxyClass = new ProxyClassLoader().loadClass(cleanName,
164: buffer);
165: _proxyCtor = _proxyClass.getConstructors()[0];
166: } catch (RuntimeException e) {
167: throw e;
168: } catch (Exception e) {
169: throw new RuntimeException(e);
170: }
171: }
172:
173: private void createProxyMethod(JavaClass jClass, Method method) {
174: String descriptor = createDescriptor(method);
175:
176: JavaMethod jMethod = jClass.createMethod(method.getName(),
177: descriptor);
178: jMethod.setAccessFlags(Modifier.PUBLIC);
179:
180: Class[] parameterTypes = method.getParameterTypes();
181:
182: CodeWriterAttribute code = jMethod.createCodeWriter();
183: code.setMaxLocals(1 + 2 * parameterTypes.length);
184: code.setMaxStack(2 + 2 * parameterTypes.length);
185:
186: code.pushObjectVar(0);
187: code.getField(jClass.getThisClass(), "_cxt",
188: "Lcom/caucho/webbeans/component/ComponentImpl;");
189:
190: code.invoke("com/caucho/webbeans/component/ComponentImpl",
191: "get", "()Ljava/lang/Object;", 1, 1);
192:
193: code.cast(method.getDeclaringClass().getName()
194: .replace('.', '/'));
195:
196: int stack = 1;
197: int index = 1;
198: for (Class type : parameterTypes) {
199: if (boolean.class.equals(type) || byte.class.equals(type)
200: || short.class.equals(type)
201: || int.class.equals(type)) {
202: code.pushIntVar(index);
203: index += 1;
204: stack += 1;
205: } else if (long.class.equals(type)) {
206: code.pushLongVar(index);
207: index += 2;
208: stack += 2;
209: } else if (float.class.equals(type)) {
210: code.pushFloatVar(index);
211: index += 1;
212: stack += 1;
213: } else if (double.class.equals(type)) {
214: code.pushDoubleVar(index);
215: index += 2;
216: stack += 2;
217: } else {
218: code.pushObjectVar(index);
219: index += 1;
220: stack += 1;
221: }
222: }
223:
224: code.invoke(method.getDeclaringClass().getName().replace('.',
225: '/'), method.getName(), createDescriptor(method),
226: stack, 1);
227:
228: Class retType = method.getReturnType();
229:
230: if (boolean.class.equals(retType) || byte.class.equals(retType)
231: || short.class.equals(retType)
232: || int.class.equals(retType)) {
233: code.addIntReturn();
234: } else if (long.class.equals(retType)) {
235: code.addLongReturn();
236: } else if (float.class.equals(retType)) {
237: code.addFloatReturn();
238: } else if (double.class.equals(retType)) {
239: code.addDoubleReturn();
240: } else if (void.class.equals(retType)) {
241: code.addReturn();
242: } else {
243: code.addObjectReturn();
244: }
245:
246: code.close();
247: }
248:
249: private String createDescriptor(Method method) {
250: StringBuilder sb = new StringBuilder();
251:
252: sb.append("(");
253:
254: for (Class param : method.getParameterTypes()) {
255: sb.append(createDescriptor(param));
256: }
257:
258: sb.append(")");
259: sb.append(createDescriptor(method.getReturnType()));
260:
261: return sb.toString();
262: }
263:
264: private String createDescriptor(Class cl) {
265: if (cl.isArray())
266: return "[" + createDescriptor(cl.getComponentType());
267:
268: String primValue = _prim.get(cl);
269:
270: if (primValue != null)
271: return primValue;
272:
273: return "L" + cl.getName().replace('.', '/') + ";";
274: }
275:
276: private static HashMap<Class, String> _prim = new HashMap<Class, String>();
277:
278: static {
279: _prim.put(boolean.class, "Z");
280: _prim.put(byte.class, "B");
281: _prim.put(char.class, "C");
282: _prim.put(short.class, "S");
283: _prim.put(int.class, "I");
284: _prim.put(long.class, "J");
285: _prim.put(float.class, "F");
286: _prim.put(double.class, "D");
287: _prim.put(void.class, "V");
288: }
289: }
|