001: /**
002: *
003: * Licensed to the Apache Software Foundation (ASF) under one or more
004: * contributor license agreements. See the NOTICE file distributed with
005: * this work for additional information regarding copyright ownership.
006: * The ASF licenses this file to You under the Apache License, Version 2.0
007: * (the "License"); you may not use this file except in compliance with
008: * the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing, software
013: * distributed under the License is distributed on an "AS IS" BASIS,
014: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015: * See the License for the specific language governing permissions and
016: * limitations under the License.
017: */package org.apache.openejb.core.cmp.cmp2;
018:
019: import org.objectweb.asm.ClassWriter;
020: import org.objectweb.asm.FieldVisitor;
021: import org.objectweb.asm.Label;
022: import org.objectweb.asm.MethodVisitor;
023: import org.objectweb.asm.Opcodes;
024: import org.objectweb.asm.Type;
025:
026: import java.lang.reflect.Method;
027: import java.lang.reflect.Field;
028: import java.lang.reflect.Modifier;
029: import java.util.LinkedHashMap;
030: import java.util.Map;
031: import java.util.List;
032: import java.util.ArrayList;
033: import java.util.HashMap;
034: import java.util.Collection;
035:
036: public class Cmp2Generator implements Opcodes {
037: private static final String UNKNOWN_PK_NAME = "OpenEJB_pk";
038: private static final Type UNKNOWN_PK_TYPE = Type
039: .getType(Long.class);
040: private static final Method EJB_SELECT_EXECUTE;
041: static {
042: try {
043: EJB_SELECT_EXECUTE = EjbSelect.class.getMethod("execute",
044: Object.class, String.class, String.class,
045: Object[].class);
046: } catch (NoSuchMethodException e) {
047: throw new RuntimeException(e);
048: }
049: }
050:
051: private final String implClassName;
052: private final String beanClassName;
053: private final ClassWriter cw;
054: private final Map<String, CmpField> cmpFields = new LinkedHashMap<String, CmpField>();
055: private final Collection<CmrField> cmrFields = new ArrayList<CmrField>();
056: private final CmpField pkField;
057: private final Class primKeyClass;
058: private final List<Method> selectMethods = new ArrayList<Method>();
059:
060: public Cmp2Generator(String cmpImplClass, Class beanClass,
061: String pkField, Class<?> primKeyClass, String[] cmpFields) {
062: if (pkField == null && primKeyClass == null)
063: throw new NullPointerException(
064: "Both pkField and primKeyClass are null");
065: beanClassName = Type.getInternalName(beanClass);
066: implClassName = cmpImplClass.replace('.', '/');
067: this .primKeyClass = primKeyClass;
068:
069: for (String cmpFieldName : cmpFields) {
070: String getterName = getterName(cmpFieldName);
071: try {
072: Method getter = beanClass.getMethod(getterName);
073: Type type = Type.getType(getter.getReturnType());
074: CmpField cmpField = new CmpField(cmpFieldName, type);
075: this .cmpFields.put(cmpFieldName, cmpField);
076: } catch (NoSuchMethodException e) {
077: throw new IllegalArgumentException("No such property "
078: + cmpFieldName + " defined on bean class "
079: + beanClassName, e);
080: }
081: }
082:
083: if (pkField != null) {
084: this .pkField = this .cmpFields.get(pkField);
085: if (this .pkField == null) {
086: throw new IllegalArgumentException("No such property "
087: + pkField + " defined on bean class "
088: + beanClassName);
089: }
090: } else {
091: this .pkField = null;
092: }
093:
094: for (Method method : beanClass.getMethods()) {
095: if (Modifier.isAbstract(method.getModifiers())
096: && method.getName().startsWith("ejbSelect")) {
097: addSelectMethod(method);
098: }
099: }
100:
101: cw = new ClassWriter(true);
102: }
103:
104: public void addCmrField(CmrField cmrField) {
105: if (cmpFields.get(cmrField.getName()) != null) {
106: cmpFields.remove(cmrField.getName());
107: }
108: cmrFields.add(cmrField);
109: }
110:
111: public void addSelectMethod(Method selectMethod) {
112: selectMethods.add(selectMethod);
113: }
114:
115: public byte[] generate() {
116: cw
117: .visit(
118: V1_5,
119: ACC_PUBLIC + ACC_SUPER,
120: implClassName,
121: null,
122: beanClassName,
123: new String[] { "org/apache/openejb/core/cmp/cmp2/Cmp2Entity" });
124:
125: // public static Object deploymentInfo;
126: {
127: FieldVisitor fv = cw.visitField(ACC_PUBLIC + ACC_STATIC,
128: "deploymentInfo", "Ljava/lang/Object;", null, null);
129: fv.visitEnd();
130: }
131:
132: // private transient boolean deleted;
133: {
134: FieldVisitor fv = cw.visitField(
135: ACC_PRIVATE + ACC_TRANSIENT, "deleted", "Z", null,
136: null);
137: fv.visitEnd();
138: }
139:
140: if (Object.class.equals(primKeyClass)) {
141: FieldVisitor fv = cw.visitField(ACC_PRIVATE,
142: UNKNOWN_PK_NAME, UNKNOWN_PK_TYPE.getDescriptor(),
143: null, null);
144: fv.visitEnd();
145: }
146:
147: // private ${cmpField.type} ${cmpField.name};
148: for (CmpField cmpField : cmpFields.values()) {
149: createField(cmpField);
150: }
151:
152: for (CmrField cmrField : cmrFields) {
153: createCmrFields(cmrField);
154: }
155:
156: createConstructor();
157:
158: for (CmpField cmpField : cmpFields.values()) {
159: // public ${cmpField.type} get${cmpField.name}() {
160: // return this.${cmpField.name};
161: // }
162: createGetter(cmpField);
163:
164: // public void setId(${cmpField.type} ${cmpField.name}) {
165: // this.${cmpField.name} = ${cmpField.name};
166: // }
167: createSetter(cmpField);
168: }
169:
170: for (CmrField cmrField : cmrFields) {
171: createCmrGetter(cmrField);
172: createCmrSetter(cmrField);
173: }
174:
175: createSimplePrimaryKeyGetter();
176:
177: createOpenEJB_isDeleted();
178:
179: createOpenEJB_deleted();
180:
181: createOpenEJB_addCmr();
182:
183: createOpenEJB_removeCmr();
184:
185: for (Method selectMethod : selectMethods) {
186: createSelectMethod(selectMethod);
187: }
188:
189: cw.visitEnd();
190:
191: return cw.toByteArray();
192: }
193:
194: private void createConstructor() {
195: MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V",
196: null, null);
197: mv.visitCode();
198: mv.visitVarInsn(ALOAD, 0);
199: mv.visitMethodInsn(INVOKESPECIAL, beanClassName, "<init>",
200: "()V");
201:
202: for (CmrField cmrField : cmrFields) {
203: initCmrFields(mv, cmrField);
204: }
205:
206: mv.visitInsn(RETURN);
207: mv.visitMaxs(0, 0);
208: mv.visitEnd();
209: }
210:
211: private void createOpenEJB_isDeleted() {
212: MethodVisitor mv = cw.visitMethod(ACC_PUBLIC,
213: "OpenEJB_isDeleted", "()Z", null, null);
214: mv.visitCode();
215: mv.visitVarInsn(ALOAD, 0);
216: mv.visitFieldInsn(GETFIELD, implClassName, "deleted", "Z");
217: mv.visitInsn(IRETURN);
218: mv.visitMaxs(0, 0);
219: mv.visitEnd();
220: }
221:
222: private void createOpenEJB_deleted() {
223: MethodVisitor mv = cw.visitMethod(ACC_PUBLIC,
224: "OpenEJB_deleted", "()V", null, null);
225: mv.visitCode();
226:
227: // if (deleted) return;
228: mv.visitVarInsn(ALOAD, 0);
229: mv.visitFieldInsn(GETFIELD, implClassName, "deleted", "Z");
230: Label notDeleted = new Label();
231: mv.visitJumpInsn(IFEQ, notDeleted);
232: mv.visitInsn(RETURN);
233: mv.visitLabel(notDeleted);
234:
235: // deleted = true;
236: mv.visitVarInsn(ALOAD, 0);
237: mv.visitInsn(ICONST_1);
238: mv.visitFieldInsn(PUTFIELD, implClassName, "deleted", "Z");
239:
240: for (CmrField cmrField : cmrFields) {
241: // ${cmrField.accessor}.delete(${cmrField.name});
242: createOpenEJB_deleted(mv, cmrField);
243: }
244:
245: // return;
246: mv.visitInsn(RETURN);
247: mv.visitMaxs(0, 0);
248: mv.visitEnd();
249: }
250:
251: private void createOpenEJB_addCmr() {
252: MethodVisitor mv = cw
253: .visitMethod(
254: ACC_PUBLIC,
255: "OpenEJB_addCmr",
256: "(Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;",
257: null, null);
258: mv.visitCode();
259:
260: // if (deleted) return null;
261: mv.visitVarInsn(ALOAD, 0);
262: mv.visitFieldInsn(GETFIELD, implClassName, "deleted", "Z");
263: Label notDeleted = new Label();
264: mv.visitJumpInsn(IFEQ, notDeleted);
265: mv.visitInsn(ACONST_NULL);
266: mv.visitInsn(ARETURN);
267: mv.visitLabel(notDeleted);
268:
269: for (CmrField cmrField : cmrFields) {
270: // if ("${cmrField.name}".equals(name)) {
271: // ${cmrField.name}.add((${cmrField.type})value);
272: // return null;
273: // }
274: //
275: // OR
276: //
277: // if ("${cmrField.name}".equals(name)) {
278: // Object oldValue = ${cmrField.name};
279: // ${cmrField.name} = (${cmrField.type}) bean;
280: // return oldValue;
281: // }
282: createOpenEJB_addCmr(mv, cmrField);
283: }
284:
285: // throw new IllegalArgumentException("Unknown cmr field " + name + " on entity bean of type " + getClass().getName());
286: mv.visitTypeInsn(NEW, "java/lang/IllegalArgumentException");
287: mv.visitInsn(DUP);
288: mv.visitTypeInsn(NEW, "java/lang/StringBuilder");
289: mv.visitInsn(DUP);
290: mv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuilder",
291: "<init>", "()V");
292: mv.visitLdcInsn("Unknown cmr field ");
293: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder",
294: "append",
295: "(Ljava/lang/String;)Ljava/lang/StringBuilder;");
296: mv.visitVarInsn(ALOAD, 1);
297: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder",
298: "append",
299: "(Ljava/lang/String;)Ljava/lang/StringBuilder;");
300: mv.visitLdcInsn(" on entity bean of type ");
301: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder",
302: "append",
303: "(Ljava/lang/String;)Ljava/lang/StringBuilder;");
304: mv.visitVarInsn(ALOAD, 0);
305: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object",
306: "getClass", "()Ljava/lang/Class;");
307: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getName",
308: "()Ljava/lang/String;");
309: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder",
310: "append",
311: "(Ljava/lang/String;)Ljava/lang/StringBuilder;");
312: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder",
313: "toString", "()Ljava/lang/String;");
314: mv.visitMethodInsn(INVOKESPECIAL,
315: "java/lang/IllegalArgumentException", "<init>",
316: "(Ljava/lang/String;)V");
317: mv.visitInsn(ATHROW);
318:
319: mv.visitMaxs(0, 0);
320: mv.visitEnd();
321: }
322:
323: private void createOpenEJB_removeCmr() {
324: MethodVisitor mv = cw.visitMethod(ACC_PUBLIC,
325: "OpenEJB_removeCmr",
326: "(Ljava/lang/String;Ljava/lang/Object;)V", null, null);
327: mv.visitCode();
328:
329: // if (deleted) return;
330: mv.visitVarInsn(ALOAD, 0);
331: mv.visitFieldInsn(GETFIELD, implClassName, "deleted", "Z");
332: Label notDeleted = new Label();
333: mv.visitJumpInsn(IFEQ, notDeleted);
334: mv.visitInsn(RETURN);
335: mv.visitLabel(notDeleted);
336:
337: for (CmrField cmrField : cmrFields) {
338: // if ("${cmrField.name}".equals(name)) {
339: // ${cmrField.name}.remove(value);
340: // return;
341: // }
342: //
343: // OR
344: //
345: // if ("${cmrField.name}".equals(name)) {
346: // ${cmrField.name} = null;
347: // return;
348: // }
349: createOpenEJB_removeCmr(mv, cmrField);
350: }
351:
352: // throw new IllegalArgumentException("Unknown cmr field " + name + " on entity bean of type " + getClass().getName());
353: mv.visitTypeInsn(NEW, "java/lang/IllegalArgumentException");
354: mv.visitInsn(DUP);
355: mv.visitTypeInsn(NEW, "java/lang/StringBuilder");
356: mv.visitInsn(DUP);
357: mv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuilder",
358: "<init>", "()V");
359: mv.visitLdcInsn("Unknown cmr field ");
360: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder",
361: "append",
362: "(Ljava/lang/String;)Ljava/lang/StringBuilder;");
363: mv.visitVarInsn(ALOAD, 1);
364: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder",
365: "append",
366: "(Ljava/lang/String;)Ljava/lang/StringBuilder;");
367: mv.visitLdcInsn(" on entity bean of type ");
368: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder",
369: "append",
370: "(Ljava/lang/String;)Ljava/lang/StringBuilder;");
371: mv.visitVarInsn(ALOAD, 0);
372: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object",
373: "getClass", "()Ljava/lang/Class;");
374: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getName",
375: "()Ljava/lang/String;");
376: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder",
377: "append",
378: "(Ljava/lang/String;)Ljava/lang/StringBuilder;");
379: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder",
380: "toString", "()Ljava/lang/String;");
381: mv.visitMethodInsn(INVOKESPECIAL,
382: "java/lang/IllegalArgumentException", "<init>",
383: "(Ljava/lang/String;)V");
384: mv.visitInsn(ATHROW);
385:
386: mv.visitMaxs(0, 0);
387: mv.visitEnd();
388: }
389:
390: private void createField(CmpField cmpField) {
391: FieldVisitor fv = cw.visitField(ACC_PRIVATE,
392: cmpField.getName(), cmpField.getDescriptor(), null,
393: null);
394: fv.visitEnd();
395: }
396:
397: private void createGetter(CmpField cmpField) {
398: String methodName = getterName(cmpField.getName());
399: MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, methodName, "()"
400: + cmpField.getDescriptor(), null, null);
401: mv.visitCode();
402: mv.visitVarInsn(ALOAD, 0);
403: mv.visitFieldInsn(GETFIELD, implClassName, cmpField.getName(),
404: cmpField.getDescriptor());
405: mv.visitInsn(cmpField.getType().getOpcode(IRETURN));
406: mv.visitMaxs(0, 0);
407: mv.visitEnd();
408: }
409:
410: private static String getterName(String propertyName) {
411: return "get" + propertyName.substring(0, 1).toUpperCase()
412: + propertyName.substring(1);
413: }
414:
415: private void createSetter(CmpField cmpField) {
416: String methodName = setterName(cmpField.getName());
417: MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, methodName, "("
418: + cmpField.getDescriptor() + ")V", null, null);
419: mv.visitCode();
420: mv.visitVarInsn(ALOAD, 0);
421: mv.visitVarInsn(cmpField.getType().getOpcode(ILOAD), 1);
422: mv.visitFieldInsn(PUTFIELD, implClassName, cmpField.getName(),
423: cmpField.getDescriptor());
424: mv.visitInsn(RETURN);
425: mv.visitMaxs(0, 0);
426: mv.visitEnd();
427: }
428:
429: private String setterName(String propertyName) {
430: return "set" + propertyName.substring(0, 1).toUpperCase()
431: + propertyName.substring(1);
432: }
433:
434: private void createSimplePrimaryKeyGetter() {
435: MethodVisitor mv = cw.visitMethod(ACC_PUBLIC,
436: "OpenEJB_getPrimaryKey", "()Ljava/lang/Object;", null,
437: null);
438: mv.visitCode();
439: if (pkField != null) {
440: // push the pk field
441: mv.visitVarInsn(ALOAD, 0);
442: mv.visitFieldInsn(GETFIELD, implClassName, pkField
443: .getName(), pkField.getDescriptor());
444:
445: // return the pk field (from the stack)
446: mv.visitInsn(pkField.getType().getOpcode(IRETURN));
447: } else if (Object.class.equals(primKeyClass)) {
448: // push the pk field
449: mv.visitVarInsn(ALOAD, 0);
450: mv.visitFieldInsn(GETFIELD, implClassName, UNKNOWN_PK_NAME,
451: UNKNOWN_PK_TYPE.getDescriptor());
452:
453: // return the pk field (from the stack)
454: mv.visitInsn(UNKNOWN_PK_TYPE.getOpcode(IRETURN));
455: } else {
456: String pkImplName = primKeyClass.getName()
457: .replace('.', '/');
458:
459: // new Pk();
460: mv.visitTypeInsn(NEW, pkImplName);
461: mv.visitInsn(DUP);
462: mv.visitMethodInsn(INVOKESPECIAL, pkImplName, "<init>",
463: "()V");
464: mv.visitVarInsn(ASTORE, 1);
465: mv.visitVarInsn(ALOAD, 1);
466:
467: // copy each field from the ejb to the pk class
468: for (Field field : primKeyClass.getFields()) {
469: CmpField cmpField = cmpFields.get(field.getName());
470:
471: // only process the cmp fields
472: if (cmpField == null) {
473: continue;
474: }
475:
476: // verify types match... this should have been caught by the verifier, but
477: // check again since generated code is so hard to debug
478: if (!cmpField.getType().getClassName().equals(
479: field.getType().getName())) {
480: throw new IllegalArgumentException("Primary key "
481: + cmpField.getName() + " is type "
482: + cmpField.getType().getClassName()
483: + " but CMP field is type "
484: + field.getType().getName());
485: }
486:
487: // push the value from the cmp bean
488: mv.visitVarInsn(ALOAD, 0);
489: mv.visitFieldInsn(GETFIELD, implClassName, cmpField
490: .getName(), cmpField.getDescriptor());
491: // set matching field in the pk class to the value on the stack
492: mv.visitFieldInsn(PUTFIELD, pkImplName, cmpField
493: .getName(), cmpField.getDescriptor());
494: mv.visitVarInsn(ALOAD, 1);
495: }
496:
497: // return the Pk();
498: mv.visitInsn(ARETURN);
499: }
500:
501: mv.visitMaxs(0, 0);
502: mv.visitEnd();
503: }
504:
505: private void createCmrFields(CmrField cmrField) {
506: FieldVisitor fv = cw.visitField(ACC_PRIVATE,
507: cmrField.getName(), cmrField.getDescriptor(), cmrField
508: .getGenericSignature(), null);
509: fv.visitEnd();
510:
511: fv = cw.visitField(ACC_PRIVATE + ACC_TRANSIENT, cmrField
512: .getName()
513: + "Cmr", cmrField.getAccessorDescriptor(), cmrField
514: .getAccessorGenericSignature(), null);
515: fv.visitEnd();
516: }
517:
518: private void initCmrFields(MethodVisitor mv, CmrField cmrField) {
519: // this.${cmrField.name} = new ${cmrField.initialValueType}();
520: Type initialValueType = cmrField.getInitialValueType();
521: if (initialValueType != null) {
522: mv.visitVarInsn(ALOAD, 0);
523: mv.visitTypeInsn(NEW, initialValueType.getInternalName());
524: mv.visitInsn(DUP);
525: mv.visitMethodInsn(INVOKESPECIAL, initialValueType
526: .getInternalName(), "<init>", "()V");
527: mv.visitFieldInsn(PUTFIELD, implClassName, cmrField
528: .getName(), cmrField.getDescriptor());
529: }
530:
531: // this.${cmrField.name}Cmr = new ${cmrField.accessorType}<${cmrField.type}, ${cmrField.proxyType}>(this,
532: // ${cmrField.name},
533: // ${cmrField.type},
534: // ${cmrField.relatedName});
535: mv.visitVarInsn(ALOAD, 0);
536: mv.visitTypeInsn(NEW, cmrField.getAccessorInternalName());
537: mv.visitInsn(DUP);
538:
539: // arg0: EntityBean source = this
540: mv.visitVarInsn(ALOAD, 0);
541:
542: // arg1: String sourceProperty - "b"
543: mv.visitLdcInsn(cmrField.getName());
544:
545: // arg2: Class<Bean> relatedType = BBean_BBean
546: mv.visitLdcInsn(cmrField.getType());
547:
548: // arg3: String relatedProperty
549: if (cmrField.getRelatedName() != null) {
550: mv.visitLdcInsn(cmrField.getRelatedName());
551: } else {
552: mv.visitInsn(ACONST_NULL);
553: }
554:
555: // invoke
556: mv
557: .visitMethodInsn(
558: INVOKESPECIAL,
559: cmrField.getAccessorInternalName(),
560: "<init>",
561: "(Ljavax/ejb/EntityBean;Ljava/lang/String;Ljava/lang/Class;Ljava/lang/String;)V");
562:
563: // bCmr = result
564: mv.visitFieldInsn(PUTFIELD, implClassName, cmrField.getName()
565: + "Cmr", cmrField.getAccessorDescriptor());
566: }
567:
568: private void createCmrGetter(CmrField cmrField) {
569: if (cmrField.isSynthetic())
570: return;
571:
572: String methodName = getterName(cmrField.getName());
573: MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, methodName, "()"
574: + cmrField.getProxyDescriptor(), null, null);
575: mv.visitCode();
576: mv.visitVarInsn(ALOAD, 0);
577: mv.visitFieldInsn(GETFIELD, implClassName, cmrField.getName()
578: + "Cmr", cmrField.getAccessorDescriptor());
579: mv.visitVarInsn(ALOAD, 0);
580: mv.visitFieldInsn(GETFIELD, implClassName, cmrField.getName(),
581: cmrField.getDescriptor());
582: mv.visitMethodInsn(INVOKEVIRTUAL, cmrField
583: .getAccessorInternalName(), "get", cmrField
584: .getCmrStyle().getGetterDescriptor());
585: if (cmrField.getCmrStyle() == CmrStyle.SINGLE) {
586: mv.visitTypeInsn(CHECKCAST, cmrField.getProxyType()
587: .getInternalName());
588: }
589: mv.visitInsn(ARETURN);
590: mv.visitMaxs(0, 0);
591: mv.visitEnd();
592: }
593:
594: private void createCmrSetter(CmrField cmrField) {
595: if (cmrField.isSynthetic())
596: return;
597:
598: String methodName = setterName(cmrField.getName());
599: MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, methodName, "("
600: + cmrField.getProxyDescriptor() + ")V", null, null);
601: mv.visitCode();
602: if (cmrField.getCmrStyle() != CmrStyle.SINGLE) {
603: mv.visitVarInsn(ALOAD, 0);
604: mv.visitFieldInsn(GETFIELD, implClassName, cmrField
605: .getName()
606: + "Cmr", cmrField.getAccessorDescriptor());
607: mv.visitVarInsn(ALOAD, 0);
608: mv.visitFieldInsn(GETFIELD, implClassName, cmrField
609: .getName(), cmrField.getDescriptor());
610: mv.visitVarInsn(ALOAD, 1);
611: mv.visitMethodInsn(INVOKEVIRTUAL, cmrField
612: .getAccessorInternalName(), "set", cmrField
613: .getCmrStyle().getSetterDescriptor());
614: mv.visitInsn(RETURN);
615: } else {
616: mv.visitVarInsn(ALOAD, 0);
617: mv.visitVarInsn(ALOAD, 0);
618: mv.visitFieldInsn(GETFIELD, implClassName, cmrField
619: .getName()
620: + "Cmr", cmrField.getAccessorDescriptor());
621: mv.visitVarInsn(ALOAD, 0);
622: mv.visitFieldInsn(GETFIELD, implClassName, cmrField
623: .getName(), cmrField.getDescriptor());
624: mv.visitVarInsn(ALOAD, 1);
625: mv.visitMethodInsn(INVOKEVIRTUAL, cmrField
626: .getAccessorInternalName(), "set", cmrField
627: .getCmrStyle().getSetterDescriptor());
628: mv.visitTypeInsn(CHECKCAST, cmrField.getType()
629: .getInternalName());
630: mv.visitFieldInsn(PUTFIELD, implClassName, cmrField
631: .getName(), cmrField.getDescriptor());
632: mv.visitInsn(RETURN);
633: }
634: mv.visitMaxs(0, 0);
635: mv.visitEnd();
636: }
637:
638: private void createOpenEJB_deleted(MethodVisitor mv,
639: CmrField cmrField) {
640: mv.visitVarInsn(ALOAD, 0);
641: mv.visitFieldInsn(GETFIELD, implClassName, cmrField.getName()
642: + "Cmr", cmrField.getAccessorDescriptor());
643: mv.visitVarInsn(ALOAD, 0);
644: mv.visitFieldInsn(GETFIELD, implClassName, cmrField.getName(),
645: cmrField.getDescriptor());
646: mv.visitMethodInsn(INVOKEVIRTUAL, cmrField
647: .getAccessorInternalName(), "deleted", cmrField
648: .getCmrStyle().getDeletedDescriptor());
649: }
650:
651: private void createOpenEJB_addCmr(MethodVisitor mv,
652: CmrField cmrField) {
653: // if (${cmrField.name}.equals(arg1))
654: mv.visitLdcInsn(cmrField.getName());
655: mv.visitVarInsn(ALOAD, 1);
656: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "equals",
657: "(Ljava/lang/Object;)Z");
658: // if not equal jump to end
659: Label end = new Label();
660: mv.visitJumpInsn(IFEQ, end);
661:
662: if (cmrField.getCmrStyle() != CmrStyle.SINGLE) {
663: mv.visitVarInsn(ALOAD, 0);
664: mv.visitFieldInsn(GETFIELD, implClassName, cmrField
665: .getName(), cmrField.getDescriptor());
666: mv.visitVarInsn(ASTORE, 3);
667: mv.visitVarInsn(ALOAD, 3);
668: Label fieldNotNull = new Label();
669: mv.visitJumpInsn(IFNONNULL, fieldNotNull);
670: mv.visitTypeInsn(NEW, cmrField.getInitialValueType()
671: .getInternalName());
672: mv.visitInsn(DUP);
673: mv.visitMethodInsn(INVOKESPECIAL, cmrField
674: .getInitialValueType().getInternalName(), "<init>",
675: "()V");
676: mv.visitVarInsn(ASTORE, 3);
677: mv.visitLabel(fieldNotNull);
678:
679: // ${cmrField.name}.add(arg2)
680: mv.visitVarInsn(ALOAD, 3);
681: mv.visitVarInsn(ALOAD, 2);
682: mv.visitMethodInsn(INVOKEINTERFACE, cmrField.getCmrStyle()
683: .getCollectionType().getInternalName(), "add",
684: "(Ljava/lang/Object;)Z");
685: mv.visitInsn(POP);
686: mv.visitVarInsn(ALOAD, 0);
687: mv.visitVarInsn(ALOAD, 3);
688: mv.visitFieldInsn(PUTFIELD, implClassName, cmrField
689: .getName(), cmrField.getDescriptor());
690:
691: // return null;
692: mv.visitInsn(ACONST_NULL);
693: mv.visitInsn(ARETURN);
694: } else {
695: // push: this.${cmrField.name};
696: mv.visitVarInsn(ALOAD, 0);
697: mv.visitFieldInsn(GETFIELD, implClassName, cmrField
698: .getName(), cmrField.getDescriptor());
699:
700: // this.${cmrField.name} = (${cmrField.type}) bean;
701: mv.visitVarInsn(ALOAD, 0);
702: mv.visitVarInsn(ALOAD, 2);
703: mv.visitTypeInsn(CHECKCAST, cmrField.getType()
704: .getInternalName());
705: mv.visitFieldInsn(PUTFIELD, implClassName, cmrField
706: .getName(), cmrField.getDescriptor());
707:
708: // return pushed value above
709: mv.visitInsn(ARETURN);
710: }
711:
712: // end of if statement
713: mv.visitLabel(end);
714: }
715:
716: // private void createPrintln(MethodVisitor mv, String message) {
717: // mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
718: // mv.visitLdcInsn(message);
719: // mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V");
720: // }
721:
722: // private void createPrintField(MethodVisitor mv, String fieldName, String descriptor) {
723: // mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
724: // mv.visitLdcInsn(fieldName + "=");
725: // mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "print", "(Ljava/lang/String;)V");
726: //
727: // mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
728: // mv.visitVarInsn(ALOAD, 0);
729: // mv.visitFieldInsn(GETFIELD, implClassName, fieldName, descriptor);
730: // mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/Object;)V");
731: // }
732:
733: private void createOpenEJB_removeCmr(MethodVisitor mv,
734: CmrField cmrField) {
735: // if (${cmrField.name}.equals(arg1))
736: mv.visitLdcInsn(cmrField.getName());
737: mv.visitVarInsn(ALOAD, 1);
738: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "equals",
739: "(Ljava/lang/Object;)Z");
740: // if not equal jump to end
741: Label end = new Label();
742: mv.visitJumpInsn(IFEQ, end);
743:
744: if (cmrField.getCmrStyle() != CmrStyle.SINGLE) {
745: // ${cmrField.name}.remove(arg2)
746: mv.visitVarInsn(ALOAD, 0);
747: mv.visitFieldInsn(GETFIELD, implClassName, cmrField
748: .getName(), cmrField.getDescriptor());
749: mv.visitVarInsn(ALOAD, 2);
750: mv.visitMethodInsn(INVOKEINTERFACE, cmrField.getCmrStyle()
751: .getCollectionType().getInternalName(), "remove",
752: "(Ljava/lang/Object;)Z");
753: mv.visitInsn(POP);
754:
755: // return;
756: mv.visitInsn(RETURN);
757: } else {
758: // this.${cmrField.name} = null;
759: mv.visitVarInsn(ALOAD, 0);
760: mv.visitInsn(ACONST_NULL);
761: mv.visitFieldInsn(PUTFIELD, implClassName, cmrField
762: .getName(), cmrField.getDescriptor());
763:
764: // return;
765: mv.visitInsn(RETURN);
766: }
767:
768: // end of if statement
769: mv.visitLabel(end);
770: }
771:
772: private void createSelectMethod(Method selectMethod) {
773: MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, selectMethod
774: .getName(), Type.getMethodDescriptor(selectMethod),
775: null, getExceptionTypes(selectMethod));
776: mv.visitCode();
777:
778: // push deploymentInfo
779: mv.visitFieldInsn(GETSTATIC, implClassName, "deploymentInfo",
780: "Ljava/lang/Object;");
781:
782: // push method signature
783: mv.visitLdcInsn(getSelectMethodSignature(selectMethod));
784:
785: // push return type
786: mv.visitLdcInsn(selectMethod.getReturnType().getName());
787:
788: // new Object[]
789: mv
790: .visitIntInsn(BIPUSH,
791: selectMethod.getParameterTypes().length);
792: mv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
793:
794: // object[i] = arg${i}
795: int i = 0;
796: for (Class<?> parameterType : selectMethod.getParameterTypes()) {
797: // push arguement i on stack
798: mv.visitInsn(DUP);
799: bipush(mv, i);
800: mv.visitVarInsn(Type.getType(parameterType)
801: .getOpcode(ILOAD), i + 1);
802:
803: // convert argument on stack to an Object
804: Convert.toObjectFrom(mv, parameterType);
805:
806: // store it into the array
807: mv.visitInsn(AASTORE);
808:
809: if (long.class.equals(parameterType)
810: || double.class.equals(parameterType)) {
811: // longs and doubles are double wide
812: i = i + 2;
813: } else {
814: i++;
815: }
816: }
817:
818: // EjbSelect.execute(deploymentInfo, signature, args[]);
819: mv.visitMethodInsn(INVOKESTATIC,
820: Type.getInternalName(EJB_SELECT_EXECUTE
821: .getDeclaringClass()), EJB_SELECT_EXECUTE
822: .getName(), Type
823: .getMethodDescriptor(EJB_SELECT_EXECUTE));
824:
825: if (!Void.TYPE.equals(selectMethod.getReturnType())) {
826: // convert return type
827: Convert.fromObjectTo(mv, selectMethod.getReturnType());
828:
829: // return value;
830: mv.visitInsn(Type.getReturnType(selectMethod).getOpcode(
831: IRETURN));
832: } else {
833: // return;
834: mv.visitInsn(RETURN);
835: }
836:
837: // close method
838: mv.visitMaxs(0, 0);
839: mv.visitEnd();
840: }
841:
842: private String getSelectMethodSignature(Method selectMethod) {
843: StringBuilder signature = new StringBuilder();
844: signature.append(selectMethod.getName());
845: if (selectMethod.getParameterTypes().length > 0) {
846: signature.append('(');
847: boolean first = true;
848: for (Class<?> parameterType : selectMethod
849: .getParameterTypes()) {
850: if (!first)
851: signature.append(',');
852: signature.append(parameterType.getCanonicalName());
853: first = false;
854: }
855: signature.append(')');
856: }
857: return signature.toString();
858: }
859:
860: private static String[] getExceptionTypes(Method method) {
861: List<String> types = new ArrayList<String>(method
862: .getExceptionTypes().length);
863: for (Class<?> exceptionType : method.getExceptionTypes()) {
864: types.add(Type.getInternalName(exceptionType));
865: }
866: return types.toArray(new String[types.size()]);
867: }
868:
869: private static void bipush(MethodVisitor mv, int i) {
870: switch (i) {
871: case -1:
872: mv.visitInsn(ICONST_M1);
873: break;
874: case 0:
875: mv.visitInsn(ICONST_0);
876: break;
877: case 1:
878: mv.visitInsn(ICONST_1);
879: break;
880: case 2:
881: mv.visitInsn(ICONST_2);
882: break;
883: case 3:
884: mv.visitInsn(ICONST_3);
885: break;
886: case 4:
887: mv.visitInsn(ICONST_4);
888: break;
889: case 5:
890: mv.visitInsn(ICONST_5);
891: break;
892: default:
893: mv.visitIntInsn(BIPUSH, i);
894: }
895:
896: }
897:
898: private static class Convert {
899: public static void toObjectFrom(MethodVisitor mv, Class from) {
900: if (from.isPrimitive()) {
901: Convert conversion = getConversion(from);
902: if (conversion == null)
903: throw new NullPointerException(
904: "conversion is null " + from.getName()
905: + " " + from.isPrimitive());
906: conversion.primitiveToObject(mv);
907: }
908: }
909:
910: public static void fromObjectTo(MethodVisitor mv, Class to) {
911: if (to.equals(Object.class)) {
912: // direct assignment will work
913: } else if (!to.isPrimitive()) {
914: mv.visitTypeInsn(CHECKCAST, Type.getInternalName(to));
915: } else {
916: Convert conversion = getConversion(to);
917: if (conversion == null)
918: throw new NullPointerException(
919: "unsupported conversion for EJB select return type "
920: + to.getName());
921: conversion.objectToPrimitive(mv);
922: }
923: }
924:
925: private static Map<Class, Convert> conversionsByPrimitive = new HashMap<Class, Convert>();
926:
927: public static Convert getConversion(Class primitive) {
928: if (!primitive.isPrimitive()) {
929: throw new IllegalArgumentException(primitive.getName()
930: + " is not a primitive class");
931: }
932: return conversionsByPrimitive.get(primitive);
933: }
934:
935: public static final Convert BOOLEAN = new Convert(
936: boolean.class, Boolean.class, "booleanValue");
937: public static final Convert CHAR = new Convert(char.class,
938: Character.class, "charValue");
939: public static final Convert BYTE = new Convert(byte.class,
940: Byte.class, "byteValue");
941: public static final Convert SHORT = new Convert(short.class,
942: Short.class, "shortValue");
943: public static final Convert INT = new Convert(int.class,
944: Integer.class, "intValue");
945: public static final Convert LONG = new Convert(long.class,
946: Long.class, "longValue");
947: public static final Convert FLOAT = new Convert(float.class,
948: Float.class, "floatValue");
949: public static final Convert DOUBLE = new Convert(double.class,
950: Double.class, "doubleValue");
951:
952: private Type objectType;
953: private final Method toPrimitive;
954: private final Method toObject;
955:
956: private Convert(Class primitiveClass, Class objectClass,
957: String toPrimitiveMethodName) {
958: objectType = Type.getType(objectClass);
959:
960: try {
961: toObject = objectClass.getMethod("valueOf",
962: primitiveClass);
963: toPrimitive = objectClass
964: .getMethod(toPrimitiveMethodName);
965: } catch (NoSuchMethodException e) {
966: throw new RuntimeException(e);
967: }
968:
969: conversionsByPrimitive.put(primitiveClass, this );
970: }
971:
972: public void primitiveToObject(MethodVisitor mv) {
973: mv.visitMethodInsn(INVOKESTATIC, objectType
974: .getInternalName(), toObject.getName(), Type
975: .getMethodDescriptor(toObject));
976: }
977:
978: public void objectToPrimitive(MethodVisitor mv) {
979: mv.visitTypeInsn(CHECKCAST, objectType.getInternalName());
980: mv.visitMethodInsn(INVOKEVIRTUAL, objectType
981: .getInternalName(), toPrimitive.getName(), Type
982: .getMethodDescriptor(toPrimitive));
983: }
984:
985: }
986: }
|