diff options
Diffstat (limited to 'sandbox/jboynes/sdoproxy/src/main/java/org/apache/tuscany/sdo/impl/SDOGenerator.java')
-rw-r--r-- | sandbox/jboynes/sdoproxy/src/main/java/org/apache/tuscany/sdo/impl/SDOGenerator.java | 371 |
1 files changed, 371 insertions, 0 deletions
diff --git a/sandbox/jboynes/sdoproxy/src/main/java/org/apache/tuscany/sdo/impl/SDOGenerator.java b/sandbox/jboynes/sdoproxy/src/main/java/org/apache/tuscany/sdo/impl/SDOGenerator.java new file mode 100644 index 0000000000..e477665c06 --- /dev/null +++ b/sandbox/jboynes/sdoproxy/src/main/java/org/apache/tuscany/sdo/impl/SDOGenerator.java @@ -0,0 +1,371 @@ +/** + * + * Copyright 2005 BEA Systems Inc. + * Copyright 2005 International Business Machines Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.tuscany.sdo.impl; + +import java.util.ArrayList; +import java.util.List; +import java.lang.reflect.ParameterizedType; + +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.FieldVisitor; +import org.objectweb.asm.Label; +import org.objectweb.asm.MethodVisitor; +import static org.objectweb.asm.Opcodes.ACC_PRIVATE; +import static org.objectweb.asm.Opcodes.ACC_PUBLIC; +import static org.objectweb.asm.Opcodes.ACC_SUPER; +import static org.objectweb.asm.Opcodes.ARETURN; +import static org.objectweb.asm.Opcodes.ATHROW; +import static org.objectweb.asm.Opcodes.CHECKCAST; +import static org.objectweb.asm.Opcodes.DUP; +import static org.objectweb.asm.Opcodes.GETFIELD; +import static org.objectweb.asm.Opcodes.ILOAD; +import static org.objectweb.asm.Opcodes.INVOKESPECIAL; +import static org.objectweb.asm.Opcodes.INVOKESTATIC; +import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL; +import static org.objectweb.asm.Opcodes.IRETURN; +import static org.objectweb.asm.Opcodes.NEW; +import static org.objectweb.asm.Opcodes.PUTFIELD; +import static org.objectweb.asm.Opcodes.RETURN; +import static org.objectweb.asm.Opcodes.V1_5; +import org.objectweb.asm.Type; +import org.objectweb.asm.signature.SignatureWriter; +import org.objectweb.asm.signature.SignatureVisitor; +import org.osoa.sdo.Property; + +/** + * @version $Rev$ $Date$ + */ +public class SDOGenerator { + private static final String SDO_MARKER = "$$SDOImpl"; + private static final int ALOAD_0 = 42; + private static final int ALOAD_1 = 43; + private static final int ALOAD_2 = 44; +// private static final int ILOAD_1 = 27; + private static final Type[] NO_ARGS = {}; + + private final String name; + private final List<Property<?>> props; + private ClassWriter cw; + private String internalInterfaceName; + + public SDOGenerator(Class<?> interfaceClass) { + internalInterfaceName = getInternalName(interfaceClass.getName()); + name = internalInterfaceName + SDO_MARKER; + props = new ArrayList<Property<?>>(); + } + + public void addProperty(Property<?> property) { + props.add(property); + } + + public byte[] toByteArray() { + cw = new ClassWriter(false); + cw.visit(V1_5, ACC_PUBLIC + ACC_SUPER, name, null, "org/apache/tuscany/sdo/impl/AbstractDataObject", new String[]{internalInterfaceName}); + + for (Property<?> property : props) { + generateProperty(property); + } + + generateGetIndex(); + generateSetIndex(); + generateConstructor(); + + cw.visitEnd(); + return cw.toByteArray(); + } + + private void generateGetIndex() { + MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "get", "(I)Ljava/lang/Object;", null, null); + mv.visitCode(); + mv.visitVarInsn(ILOAD, 1); + Label[] labels = new Label[props.size()]; + for (int i=0; i < labels.length; i++) { + labels[i] = new Label(); + } + Label def = new Label(); + mv.visitTableSwitchInsn(0, labels.length-1, def, labels); + int i = 0; + for (Property<?> property : props) { + String propertyName = property.getName(); + java.lang.reflect.Type javaType = property.getType().getJavaType(); + + mv.visitLabel(labels[i++]); + mv.visitInsn(ALOAD_0); + + if (javaType instanceof Class<?>) { + Type type = Type.getType((Class<?>) javaType); + mv.visitFieldInsn(GETFIELD, name, propertyName, type.getDescriptor()); + autobox(mv, type); + } else { + throw new UnsupportedOperationException(); + } + + mv.visitInsn(ARETURN); + } + + mv.visitLabel(def); + mv.visitTypeInsn(NEW, "java/lang/IllegalArgumentException"); + mv.visitInsn(DUP); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/IllegalArgumentException", "<init>", "()V"); + mv.visitInsn(ATHROW); + mv.visitMaxs(2, 2); + mv.visitEnd(); + } + + private void generateSetIndex() { + MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "set", "(ILjava/lang/Object;)V", null, null); + mv.visitCode(); + mv.visitVarInsn(ILOAD, 1); + Label[] labels = new Label[props.size()]; + for (int i=0; i < labels.length; i++) { + labels[i] = new Label(); + } + Label def = new Label(); + mv.visitTableSwitchInsn(0, labels.length-1, def, labels); + int i = 0; + for (Property<?> property : props) { + String propertyName = property.getName(); + java.lang.reflect.Type javaType = property.getType().getJavaType(); + + mv.visitLabel(labels[i++]); + mv.visitInsn(ALOAD_0); + mv.visitInsn(ALOAD_2); + + if (javaType instanceof Class<?>) { + Class<?> propertyClass = (Class<?>) javaType; + Type propertyType = Type.getType(propertyClass); + autounbox(mv, propertyType); + mv.visitFieldInsn(PUTFIELD, name, propertyName, propertyType.getDescriptor()); + } else { + throw new UnsupportedOperationException(); + } + mv.visitInsn(RETURN); + } + + mv.visitLabel(def); + mv.visitTypeInsn(NEW, "java/lang/IllegalArgumentException"); + mv.visitInsn(DUP); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/IllegalArgumentException", "<init>", "()V"); + mv.visitInsn(ATHROW); + mv.visitMaxs(3, 3); + mv.visitEnd(); + } + + private void generateConstructor() { + int stack = 2; + MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "(Lorg/apache/tuscany/sdo/impl/TypeImpl;)V", null, null); + mv.visitCode(); + mv.visitInsn(ALOAD_0); + mv.visitInsn(ALOAD_1); + mv.visitMethodInsn(INVOKESPECIAL, "org/apache/tuscany/sdo/impl/AbstractDataObject", "<init>", "(Lorg/apache/tuscany/sdo/impl/TypeImpl;)V"); + for (Property<?> prop : props) { + if (!prop.isMany()) { + continue; + } + stack = 3; + mv.visitInsn(ALOAD_0); + mv.visitTypeInsn(NEW, "java/util/ArrayList"); + mv.visitInsn(DUP); + mv.visitMethodInsn(INVOKESPECIAL, "java/util/ArrayList", "<init>", "()V"); + mv.visitFieldInsn(PUTFIELD, name, prop.getName(), "Ljava/util/List;"); + + } + mv.visitInsn(RETURN); + mv.visitMaxs(stack, 2); + mv.visitEnd(); + } + + public void generateProperty(Property<?> property) { + generateField(property); + generateGetter(property); + generateSetter(property); + } + + private void generateField(Property<?> property) { + String propertyName = property.getName(); + java.lang.reflect.Type javaType = property.getJavaType(); + String descriptor; + String signature; + if (javaType instanceof Class<?>) { + descriptor = Type.getType((Class<?>) javaType).getDescriptor(); + signature = null; + } else if (javaType instanceof ParameterizedType) { + ParameterizedType type = (ParameterizedType) javaType; + Type rawType = Type.getType((Class<?>) type.getRawType()); + descriptor = rawType.getDescriptor(); + signature = getSignature(type, rawType); + } else { + throw new UnsupportedOperationException(); + } + FieldVisitor fv = cw.visitField(ACC_PRIVATE, propertyName, descriptor, signature, null); + fv.visitEnd(); + } + + private static String getSignature(ParameterizedType type, Type rawType) { + SignatureWriter sw = new SignatureWriter(); + sw.visitClassType(rawType.getInternalName()); + for (java.lang.reflect.Type typeArg : type.getActualTypeArguments()) { + if (typeArg instanceof Class<?>) { + SignatureVisitor sv = sw.visitTypeArgument(SignatureVisitor.INSTANCEOF); + sv.visitClassType(Type.getType((Class<?>) typeArg).getInternalName()); + sv.visitEnd(); + } + } + sw.visitEnd(); + return sw.toString(); + } + + private void generateGetter(Property<?> property) { + String propertyName = property.getName(); + java.lang.reflect.Type javaType = property.getJavaType(); + String methodName = (Boolean.TYPE.equals(javaType) ? "is" : "get") + Character.toUpperCase(propertyName.charAt(0)) + propertyName.substring(1); + + Type rawType; + String signature; + if (javaType instanceof Class<?>) { + rawType = Type.getType((Class<?>) javaType); + signature = null; + } else if (javaType instanceof ParameterizedType) { + ParameterizedType type = (ParameterizedType) javaType; + rawType = Type.getType((Class<?>) type.getRawType()); + signature = getSignature(type, rawType); + } else { + throw new UnsupportedOperationException(); + } + + String descriptor = rawType.getDescriptor(); + + MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, methodName, "()" + descriptor, signature, null); + mv.visitCode(); + mv.visitInsn(ALOAD_0); + mv.visitFieldInsn(GETFIELD, name, propertyName, descriptor); + mv.visitInsn(rawType.getOpcode(IRETURN)); + mv.visitMaxs(rawType.getSize(), 1); + mv.visitEnd(); + } + + private void generateSetter(Property<?> property) { + String propertyName = property.getName(); + java.lang.reflect.Type javaType = property.getJavaType(); + String methodName = "set" + Character.toUpperCase(propertyName.charAt(0)) + propertyName.substring(1); + + Type rawType; + String signature; + if (javaType instanceof Class<?>) { + rawType = Type.getType((Class<?>) javaType); + signature = null; + } else if (javaType instanceof ParameterizedType) { + ParameterizedType type = (ParameterizedType) javaType; + rawType = Type.getType((Class<?>) type.getRawType()); + signature = getSignature(type, rawType); + } else { + throw new UnsupportedOperationException(); + } + + String descriptor = rawType.getDescriptor(); + + MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, methodName, '(' + descriptor + ")V", signature, null); + mv.visitCode(); + mv.visitInsn(ALOAD_0); +// mv.visitInsn(rawType.getOpcode(ILOAD_1)); todo make this work + mv.visitVarInsn(rawType.getOpcode(ILOAD), 1); + mv.visitFieldInsn(PUTFIELD, name, propertyName, descriptor); + mv.visitInsn(RETURN); + mv.visitMaxs(1 + rawType.getSize(), 1 + rawType.getSize()); + mv.visitEnd(); + } + + private static void autobox(MethodVisitor mv, Type type) { + switch (type.getSort()) { + case Type.BOOLEAN: + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;"); + break; + case Type.CHAR: + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;"); + break; + case Type.BYTE: + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;"); + break; + case Type.SHORT: + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;"); + break; + case Type.INT: + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;"); + break; + case Type.LONG: + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;"); + break; + case Type.FLOAT: + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;"); + break; + case Type.DOUBLE: + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;"); + break; + } + } + + @SuppressWarnings({"OverlyLongMethod", "OverlyComplexMethod"}) + private static void autounbox(MethodVisitor mv, Type type) { + switch (type.getSort()) { + case Type.BOOLEAN: + mv.visitTypeInsn(CHECKCAST, "java/lang/Boolean"); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z"); + break; + case Type.CHAR: + mv.visitTypeInsn(CHECKCAST, "java/lang/Character"); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C"); + break; + case Type.BYTE: + mv.visitTypeInsn(CHECKCAST, "java/lang/Byte"); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Byte", "byteValue", "()B"); + break; + case Type.SHORT: + mv.visitTypeInsn(CHECKCAST, "java/lang/Short"); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Short", "shortValue", "()S"); + break; + case Type.INT: + mv.visitTypeInsn(CHECKCAST, "java/lang/Integer"); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I"); + break; + case Type.LONG: + mv.visitTypeInsn(CHECKCAST, "java/lang/Long"); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J"); + break; + case Type.FLOAT: + mv.visitTypeInsn(CHECKCAST, "java/lang/Float"); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Float", "floatValue", "()F"); + break; + case Type.DOUBLE: + mv.visitTypeInsn(CHECKCAST, "java/lang/Double"); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Double", "doubleValue", "()D"); + break; + case Type.ARRAY: + mv.visitTypeInsn(CHECKCAST, type.getDescriptor()); + break; + case Type.OBJECT: + mv.visitTypeInsn(CHECKCAST, type.getInternalName()); + break; + default: + throw new AssertionError(); + } + } + + private static String getInternalName(String name) { + return name.replace('.', '/'); + } +} |