summaryrefslogtreecommitdiffstats
path: root/sandbox/jboynes/sdoproxy/src/main/java/org/apache/tuscany/sdo/impl/SDOGenerator.java
diff options
context:
space:
mode:
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.java371
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('.', '/');
+ }
+}