]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.databoard/src/org/simantics/databoard/method/MethodInterfaceUtil.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.databoard / src / org / simantics / databoard / method / MethodInterfaceUtil.java
diff --git a/bundles/org.simantics.databoard/src/org/simantics/databoard/method/MethodInterfaceUtil.java b/bundles/org.simantics.databoard/src/org/simantics/databoard/method/MethodInterfaceUtil.java
new file mode 100644 (file)
index 0000000..1ea10b6
--- /dev/null
@@ -0,0 +1,812 @@
+/*******************************************************************************\r
+ *  Copyright (c) 2010 Association for Decentralized Information Management in\r
+ *  Industry THTH ry.\r
+ *  All rights reserved. This program and the accompanying materials\r
+ *  are made available under the terms of the Eclipse Public License v1.0\r
+ *  which accompanies this distribution, and is available at\r
+ *  http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ *  Contributors:\r
+ *      VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.databoard.method;
+
+import static org.objectweb.asm.Opcodes.AALOAD;\r
+import static org.objectweb.asm.Opcodes.AASTORE;\r
+import static org.objectweb.asm.Opcodes.ACC_ABSTRACT;\r
+import static org.objectweb.asm.Opcodes.ACC_FINAL;\r
+import static org.objectweb.asm.Opcodes.ACC_INTERFACE;\r
+import static org.objectweb.asm.Opcodes.ACC_PUBLIC;\r
+import static org.objectweb.asm.Opcodes.ACC_STATIC;\r
+import static org.objectweb.asm.Opcodes.ACC_SUPER;\r
+import static org.objectweb.asm.Opcodes.ALOAD;\r
+import static org.objectweb.asm.Opcodes.ANEWARRAY;\r
+import static org.objectweb.asm.Opcodes.ARETURN;\r
+import static org.objectweb.asm.Opcodes.ARRAYLENGTH;\r
+import static org.objectweb.asm.Opcodes.ASTORE;\r
+import static org.objectweb.asm.Opcodes.ATHROW;\r
+import static org.objectweb.asm.Opcodes.CHECKCAST;\r
+import static org.objectweb.asm.Opcodes.DLOAD;\r
+import static org.objectweb.asm.Opcodes.DRETURN;\r
+import static org.objectweb.asm.Opcodes.DUP;\r
+import static org.objectweb.asm.Opcodes.FLOAD;\r
+import static org.objectweb.asm.Opcodes.FRETURN;\r
+import static org.objectweb.asm.Opcodes.GETFIELD;\r
+import static org.objectweb.asm.Opcodes.GETSTATIC;\r
+import static org.objectweb.asm.Opcodes.GOTO;\r
+import static org.objectweb.asm.Opcodes.ICONST_0;\r
+import static org.objectweb.asm.Opcodes.IFEQ;\r
+import static org.objectweb.asm.Opcodes.IF_ICMPLT;\r
+import static org.objectweb.asm.Opcodes.ILOAD;\r
+import static org.objectweb.asm.Opcodes.INSTANCEOF;\r
+import static org.objectweb.asm.Opcodes.INVOKEINTERFACE;\r
+import static org.objectweb.asm.Opcodes.INVOKESPECIAL;\r
+import static org.objectweb.asm.Opcodes.INVOKESTATIC;\r
+import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL;\r
+import static org.objectweb.asm.Opcodes.IRETURN;\r
+import static org.objectweb.asm.Opcodes.ISTORE;\r
+import static org.objectweb.asm.Opcodes.LLOAD;\r
+import static org.objectweb.asm.Opcodes.LRETURN;\r
+import static org.objectweb.asm.Opcodes.NEW;\r
+import static org.objectweb.asm.Opcodes.POP;\r
+import static org.objectweb.asm.Opcodes.PUTFIELD;\r
+import static org.objectweb.asm.Opcodes.PUTSTATIC;\r
+import static org.objectweb.asm.Opcodes.RETURN;\r
+import static org.objectweb.asm.Opcodes.V1_6;\r
+\r
+import java.lang.reflect.Constructor;\r
+import java.lang.reflect.InvocationTargetException;\r
+import java.lang.reflect.Method;\r
+import java.util.Arrays;\r
+import java.util.Comparator;\r
+import java.util.HashSet;\r
+import java.util.Set;\r
+\r
+import org.objectweb.asm.ClassWriter;\r
+import org.objectweb.asm.FieldVisitor;\r
+import org.objectweb.asm.Label;\r
+import org.objectweb.asm.MethodVisitor;\r
+import org.objectweb.asm.Opcodes;\r
+import org.objectweb.asm.Type;\r
+import org.simantics.databoard.Bindings;\r
+import org.simantics.databoard.Methods;\r
+import org.simantics.databoard.adapter.AdaptException;\r
+import org.simantics.databoard.adapter.Adapter;\r
+import org.simantics.databoard.adapter.AdapterConstructionException;\r
+import org.simantics.databoard.binding.error.BindingConstructionException;\r
+import org.simantics.databoard.method.MethodInterface.AsyncResult;\r
+import org.simantics.databoard.method.MethodInterface.ExecutionError;\r
+
+public class MethodInterfaceUtil {
+
+       /**
+        * Bind an instance a to Method Interface 
+        * 
+        * @param <T>
+        * @param interfaze
+        * @param obj
+        * @return the method interface
+        * @throws BindingConstructionException
+        */
+       public static <T> MethodInterface bindInterface(Class<T> interfaze, final T obj) throws BindingConstructionException
+       {
+               final Interface interfaceType = Methods.getInterfaceType(interfaze);
+               MethodInterface mi = bindInterface(interfaceType, obj);\r
+               /*\r
+               System.out.println("Created methodinterface for "+interfaze.getName());\r
+               for (MethodTypeDefinition k : mi.getInterface().methodDefinitions) {\r
+                       System.out.print(k);\r
+                       if (k.getType().requestType.getComponentCount()>0) {\r
+                               System.out.print(System.identityHashCode( k.getType().requestType.getComponentType(0) ) );\r
+                       }\r
+                       System.out.println();                                   \r
+               }\r
+               */\r
+               return mi;
+       }
+       
+       /**
+        * Bind interface type to an instance 
+        * 
+        * @param <T>
+        * @param interfaceType
+        * @param obj
+        * @return the method interface
+        * @throws BindingConstructionException
+        */
+       public static <T> MethodInterface bindInterface(final Interface interfaceType, final T obj) throws BindingConstructionException
+       {               
+               // Find matching Java Method for each MethodTypeDefinition
+               int len = interfaceType.getMethodDefinitions().length;
+               final MethodTypeDefinition[] methodDefinitions = interfaceType.getMethodDefinitions();
+               final MethodTypeBinding[] methodBindings = new MethodTypeBinding[ len ];
+               final Method[] methods = new Method[ len ];
+               Class<?> clazz = obj.getClass();
+               Method[] classMethods = clazz.getMethods();
+               for (int i=0; i<len; i++)
+               {
+                       MethodTypeDefinition def = methodDefinitions[i];
+                       MethodType type = def.getType();
+                       String name = def.getName();
+                       
+                       // Find the MethodType from the class methods
+                       for (Method m : classMethods) {
+                               // Verify name matchs
+                               if ( !m.getName().equals(name) ) continue;
+                               MethodTypeBinding classMethodTypeBinding = Methods.getMethodTypeBinding(m);
+                               if ( !classMethodTypeBinding.getMethodType().equals( type) ) continue;
+                               
+                               m.setAccessible(true);
+                               methodBindings[i] = classMethodTypeBinding; 
+                               methods[i] = m;
+                               break;
+                       }
+                       
+                       // We did not find suitable method in clazz
+                       if (methods[i]==null) {
+                               throw new BindingConstructionException("Could not find method "+def+" in "+clazz.getSimpleName());
+                       }
+               }
+               
+               // Read method definitions into an array
+               
+               MethodInterface mi = new MethodInterface() {
+                       @Override
+                       public org.simantics.databoard.method.MethodInterface.Method getMethod(
+                                       MethodTypeDefinition description)
+                                       throws org.simantics.databoard.method.MethodNotSupportedException {
+                               int index = -1;
+                               for (int i=0; i<methodDefinitions.length; i++) {
+                                       if (methodDefinitions[i].equals(description)) {
+                                               index = i;
+                                               break;
+                                       } 
+                               }
+                               if (index<0) throw new org.simantics.databoard.method.MethodNotSupportedException(description.getName());
+                               final MethodTypeBinding binding = methodBindings[index];
+                               final java.lang.reflect.Method method = methods[index];
+                               
+                               Method m = new Method() {
+                                       @Override
+                                       public MethodTypeBinding getMethodBinding() {
+                                               return binding;
+                                       }
+
+                                       @Override
+                                       public AsyncResult invoke(Object request) {
+                                               AsyncResultImpl result = new AsyncResultImpl(); 
+                                               try {
+                                                       Object response = method.invoke(obj, (Object[]) request);
+                                                       if (response != null) result.setResponse(response);\r
+                                                       else result.setInvokeException(new org.simantics.databoard.method.InvokeException(new NullPointerException()));
+                                               } catch(InvocationTargetException t) {\r
+                                                       Throwable e = t.getTargetException();\r
+                                                       if (e instanceof RuntimeException) {\r
+                                                               result.setInvokeException(new org.simantics.databoard.method.InvokeException( (Exception) e));\r
+                                                       } else {
+                                                               result.setExecutionError(e);\r
+                                                       }
+                                               } catch(IllegalArgumentException e) {
+                                                       result.setInvokeException(new org.simantics.databoard.method.InvokeException(e));
+                                               } catch (IllegalAccessException e) {
+                                                       result.setInvokeException(new org.simantics.databoard.method.InvokeException(e));
+                                               }
+                                               return result;
+                                       }
+                                       
+                               };
+                               return m;
+                       }
+                       @Override
+                       public org.simantics.databoard.method.MethodInterface.Method getMethod(
+                                       MethodTypeBinding binding) throws org.simantics.databoard.method.MethodNotSupportedException {
+                               MethodTypeDefinition description = binding.getMethodDefinition();
+                               int index = -1;                         
+                               for (int i=0; i<methodDefinitions.length; i++) {
+                                       if (methodDefinitions[i].equals(description)) {
+                                               index = i;
+                                               break;
+                                       } 
+                               }
+                               if (index<0) throw new org.simantics.databoard.method.MethodNotSupportedException(description.getName());
+                               final MethodTypeBinding producerBinding = methodBindings[index];
+                               final MethodTypeBinding consumerBinding = binding;
+                               try {
+                                       final Adapter requestAdapter = Bindings.getTypeAdapter(consumerBinding.getRequestBinding(), producerBinding.getRequestBinding());
+                                       final Adapter responseAdapter = Bindings.getTypeAdapter(producerBinding.getResponseBinding(), consumerBinding.getResponseBinding());
+                                       final Adapter errorAdapter = Bindings.getTypeAdapter(producerBinding.getErrorBinding(), consumerBinding.getErrorBinding());
+                                       final java.lang.reflect.Method method = methods[index];
+
+                                       Method m = new Method() {
+                                               @Override
+                                               public MethodTypeBinding getMethodBinding() {
+                                                       return consumerBinding;
+                                               }
+
+                                               @Override
+                                               public AsyncResult invoke(Object request) {
+                                                       AsyncResultImpl result = new AsyncResultImpl();
+                                                       
+                                                       try {
+                                                               request = requestAdapter.adapt(request);
+                                                               Object response = method.invoke(obj, (Object[]) request);
+                                                               response = responseAdapter.adapt(response);
+                                                               result.setResponse(response);
+                                                       } catch (AdaptException e1) {
+                                                               result.setInvokeException(new InvokeException(e1));
+                                                       } catch (InvocationTargetException t) {
+                                                               Object error;
+                                                               try {
+                                                                       error = errorAdapter.adapt(t.getCause());
+                                                                       result.setExecutionError(error);
+                                                               } catch (AdaptException e) {
+                                                                       result.setInvokeException( new InvokeException(e) );
+                                                               }
+                                                       } catch (IllegalArgumentException e) {
+                                                               result.setInvokeException(new org.simantics.databoard.method.InvokeException(e));
+                                                       } catch (IllegalAccessException e) {
+                                                               result.setInvokeException(new org.simantics.databoard.method.InvokeException(e));
+                                                       }
+                                                       return result;
+                                               }
+
+                                       };                      
+                               return m;
+                               
+                               } catch (AdapterConstructionException e1) {
+                                       throw new MethodNotSupportedException("Could not adapt method "+e1.getMessage(), e1);
+                               }
+                               
+                       }
+                       
+                       @Override
+                       public Interface getInterface() {
+                               return interfaceType;
+                       }};
+               
+               return mi;
+       }
+       
+       @SuppressWarnings("unchecked")
+       public static <T> T createProxy(Class<T> interfaze, MethodInterface mi)
+       throws BindingConstructionException
+       {
+               StubClassLoader cl = new StubClassLoader(interfaze.getClassLoader());
+               Class<?> virhe;
+               try {
+                       virhe = cl.loadClass(interfaze.getName()+"_Stub");
+                       Constructor<?> c = virhe.getConstructor(MethodInterface.class);
+                       return (T) c.newInstance(mi);
+               } catch (ClassNotFoundException e) {
+                       System.err.println("Did you remember to include org.objectweb.asm ??");
+                       throw new BindingConstructionException(e);
+               } catch (SecurityException e) {
+                       throw new BindingConstructionException(e);
+               } catch (NoSuchMethodException e) {
+                       throw new BindingConstructionException(e);
+               } catch (IllegalArgumentException e) {
+                       throw new BindingConstructionException(e);
+               } catch (InstantiationException e) {
+                       throw new BindingConstructionException(e);
+               } catch (IllegalAccessException e) {
+                       throw new BindingConstructionException(e);
+               } catch (InvocationTargetException e) {
+                       throw new BindingConstructionException(e);
+               }
+       }
+
+       public static Comparator<java.lang.reflect.Method> methodComparator = new Comparator<java.lang.reflect.Method>(){
+               @Override public int compare(java.lang.reflect.Method o1,java.lang.reflect.Method o2){
+               return o1.getName().compareTo(o2.getName());}};
+               
+       public static MethodInterface adaptMethods(final MethodInterface mi, final MethodTypeDefinition[] rangeMethods)
+       {
+               //final MethodTypeDefinition[] domainMethods = mi.getInterface().getMethodDefinitions();
+               throw new IllegalArgumentException("To be implemented");
+               /*
+               return new MethodInterface() {
+                       @Override
+                       public org.simantics.databoard.method.MethodInterface.Method getMethod(
+                                       MethodDescription rangeDescription)
+                                       throws MethodNotSupportedException {
+                               MethodDescription domainDescription = null;
+                               for (int i=0; i<rangeMethods.length; i++) {
+                                       if (rangeMethods[i].equals(rangeDescription)) {
+                                               domainDescription = domainMethods[i];
+                                       }
+                               }
+                               if (domainDescription==null)
+                                       throw new MethodNotSupportedException();
+                               
+                               return new org.simantics.databoard.method.MethodInterface.Method() {
+                                       @Override
+                                       public MethodBinding getMethodBinding() {
+                                               return null;
+                                       }
+                                       @Override
+                                       public AsyncResult invoke(Object request) {
+                                               return null;
+                                       }
+                               };
+                       }
+                       @Override
+                       public org.simantics.databoard.method.MethodInterface.Method getMethod(
+                                       MethodBinding binding) throws MethodNotSupportedException {
+                               return null;
+                       }
+                       @Override
+                       public MethodDescription[] getMethodDescriptions() {
+                               return rangeMethods;
+                       }
+               };
+               */
+       }
+       
+       static class StubClassLoader extends ClassLoader {
+               
+               public StubClassLoader() {
+                       super(Thread.currentThread().getContextClassLoader());
+               }
+
+               public StubClassLoader(ClassLoader parent) {
+                       super(parent);
+               }
+
+               @Override
+               protected Class<?> findClass(String name) throws ClassNotFoundException {
+                       if (name.endsWith("_Stub")) {
+                               Class<?> interfaze = loadClass(name.substring(0, name.length()-5));
+                               ClassWriter cw = new ClassWriter(0);
+                               createImpl(name, interfaze, cw);
+                               byte[] b = cw.toByteArray();\r
+                               /*\r
+                               new ClassReader(b).accept(\r
+                                               new ASMifierClassVisitor(new PrintWriter(System.out)),\r
+                                               0\r
+                                       );\r
+                               */
+                               Class<?> clazz = defineClass(name, b, 0, b.length);
+                               return clazz;
+                       }
+                       return super.findClass(name);
+               }
+
+               static String toTypeDescriptor(Class<?> clazz) {
+                       if (clazz==void.class) return "V";
+                       if (clazz==boolean.class) return "Z";
+                       if (clazz==char.class) return "C";
+                       if (clazz==byte.class) return "B";
+                       if (clazz==short.class) return "S";
+                       if (clazz==int.class) return "I";
+                       if (clazz==float.class) return "F";
+                       if (clazz==long.class) return "J";
+                       if (clazz==double.class) return "D";
+                       if (clazz.isArray()) return clazz.getName().replaceAll("\\.", "/");             
+                       return "L"+clazz.getName().replaceAll("\\.", "/")+";";
+               }
+               
+               void createImpl(String className, Class<?> interfaze, ClassWriter cw) {
+                       FieldVisitor fv;
+                       MethodVisitor mv;
+                       //AnnotationVisitor av0;
+                       
+                       java.lang.reflect.Method[] methods = interfaze.getMethods();
+                       Arrays.sort(methods, MethodInterfaceUtil.methodComparator);
+
+                       String classResourceName = className.replaceAll("\\.", "/");
+                       String classTypeDescriptor = "L"+classResourceName+";";
+                       String interfaceResourceName = classResourceName.substring(0, classResourceName.length()-5);
+                       String interfaceTypeDescriptor = "L"+interfaceResourceName+";";
+                       
+                       cw.visit(V1_6, ACC_SUPER | ACC_PUBLIC, classResourceName, null, "java/lang/Object", new String[] { interfaceResourceName });
+
+                       // Imports
+                       Set<Class<?>> imports = new HashSet<Class<?>>();
+                       imports.add(AsyncResult.class);
+                       imports.add(ExecutionError.class);
+                       imports.add(Method.class);
+                       imports.add(interfaze);
+                       
+                       for (java.lang.reflect.Method m : methods) {
+                               for (Class<?> clazz : m.getExceptionTypes()) {
+                                       imports.add(clazz);
+                               }
+                               for (Class<?> clazz : m.getParameterTypes()) {
+                                       imports.add(clazz);                             
+                               }
+                               imports.add(m.getReturnType());                 
+                       }
+                       
+                       for (Class<?> clazz : imports) {
+                               if (clazz.isPrimitive()) continue;
+                               String name = clazz.getName();
+                               if (name.startsWith("java.lang")) continue;
+                               String resourceName = name.replaceAll("\\.", "/");
+                               String outerName = resourceName.contains("$") ? resourceName.substring(0, resourceName.indexOf('$')) : null;
+                               String className_ = clazz.isArray() ? clazz.getSimpleName().substring(0, clazz.getSimpleName().length()-2) : clazz.getSimpleName();
+                               int access = ACC_PUBLIC + ACC_STATIC + (clazz.isInterface() ? ACC_INTERFACE + ACC_ABSTRACT : 0);
+//                             System.out.printf("name=%s, outerName=%s, innerName=%s\n", resourceName, outerName, className_);
+                               cw.visitInnerClass(resourceName, outerName, className_, access);                        
+                       }
+                       
+                       // Fields
+                       {
+                       fv = cw.visitField(ACC_FINAL + ACC_STATIC, "interfaze", "Ljava/lang/Class;", "Ljava/lang/Class<*>;", null);
+                       fv.visitEnd();
+                       }
+                       {
+                       fv = cw.visitField(ACC_FINAL + ACC_STATIC, "bindings", "[Lorg/simantics/databoard/method/MethodTypeBinding;", null, null);
+                       fv.visitEnd();
+                       }
+                       {
+                       fv = cw.visitField(0, "mi", "Lorg/simantics/databoard/method/MethodInterface;", null, null);
+                       fv.visitEnd();
+                       }
+                       {
+                       fv = cw.visitField(0, "methods", "[Lorg/simantics/databoard/method/MethodInterface$Method;", null, null);
+                       fv.visitEnd();
+                       }
+                       
+                       // Init class - static {}
+                       {
+                       mv = cw.visitMethod(ACC_STATIC, "<clinit>", "()V", null, null);
+                       mv.visitCode();
+                       Label l0 = new Label();
+                       mv.visitLabel(l0);
+                       mv.visitLdcInsn(Type.getType(interfaceTypeDescriptor));
+                       mv.visitFieldInsn(PUTSTATIC, classResourceName, "interfaze", "Ljava/lang/Class;");
+                       Label l1 = new Label();
+                       mv.visitLabel(l1);
+                       mv.visitFieldInsn(GETSTATIC, classResourceName, "interfaze", "Ljava/lang/Class;");
+                       mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getMethods", "()[Ljava/lang/reflect/Method;");
+                       mv.visitVarInsn(ASTORE, 0);
+                       Label l2 = new Label();
+                       mv.visitLabel(l2);
+                       mv.visitVarInsn(ALOAD, 0);
+                       mv.visitFieldInsn(GETSTATIC, "org/simantics/databoard/method/MethodInterfaceUtil", "methodComparator", "Ljava/util/Comparator;");
+                       mv.visitMethodInsn(INVOKESTATIC, "java/util/Arrays", "sort", "([Ljava/lang/Object;Ljava/util/Comparator;)V");
+                       Label l3 = new Label();
+                       mv.visitLabel(l3);
+                       mv.visitVarInsn(ALOAD, 0);
+                       mv.visitInsn(ARRAYLENGTH);
+                       mv.visitTypeInsn(ANEWARRAY, "org/simantics/databoard/method/MethodTypeBinding");
+                       mv.visitFieldInsn(PUTSTATIC, classResourceName, "bindings", "[Lorg/simantics/databoard/method/MethodTypeBinding;");
+                       Label l4 = new Label();
+                       mv.visitLabel(l4);
+                       mv.visitInsn(ICONST_0);
+                       mv.visitVarInsn(ISTORE, 1);
+                       Label l5 = new Label();
+                       mv.visitLabel(l5);
+                       Label l6 = new Label();
+                       mv.visitJumpInsn(GOTO, l6);
+                       Label l7 = new Label();
+                       mv.visitLabel(l7);
+                       mv.visitFrame(Opcodes.F_APPEND,2, new Object[] {"[Ljava/lang/reflect/Method;", Opcodes.INTEGER}, 0, null);
+                       mv.visitFieldInsn(GETSTATIC, classResourceName, "bindings", "[Lorg/simantics/databoard/method/MethodTypeBinding;");
+                       mv.visitVarInsn(ILOAD, 1);
+                       mv.visitVarInsn(ALOAD, 0);
+                       mv.visitVarInsn(ILOAD, 1);
+                       mv.visitInsn(AALOAD);
+                       mv.visitMethodInsn(INVOKESTATIC, "org/simantics/databoard/Methods", "getMethodTypeBinding", "(Ljava/lang/reflect/Method;)Lorg/simantics/databoard/method/MethodTypeBinding;");
+                       mv.visitInsn(AASTORE);
+                       Label l8 = new Label();
+                       mv.visitLabel(l8);
+                       mv.visitIincInsn(1, 1);
+                       mv.visitLabel(l6);
+                       mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
+                       mv.visitVarInsn(ILOAD, 1);
+                       mv.visitFieldInsn(GETSTATIC, classResourceName, "bindings", "[Lorg/simantics/databoard/method/MethodTypeBinding;");
+                       mv.visitInsn(ARRAYLENGTH);
+                       mv.visitJumpInsn(IF_ICMPLT, l7);
+                       Label l9 = new Label();
+                       mv.visitLabel(l9);
+                       mv.visitInsn(RETURN);
+                       Label l10 = new Label();
+                       mv.visitLabel(l10);
+                       mv.visitLocalVariable("methods", "[Ljava/lang/reflect/Method;", null, l2, l10, 0);
+                       mv.visitLocalVariable("i", "I", null, l5, l9, 1);
+                       mv.visitMaxs(4, 2);
+                       mv.visitEnd();
+                       }
+                       
+                       // Constructor
+                       {
+                       mv = cw.visitMethod(ACC_PUBLIC, "<init>", "(Lorg/simantics/databoard/method/MethodInterface;)V", null, new String[] { "org/simantics/databoard/method/MethodNotSupportedException" });
+                       mv.visitCode();
+                       Label l0 = new Label();
+                       mv.visitLabel(l0);
+                       mv.visitVarInsn(ALOAD, 0);
+                       mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
+                       Label l1 = new Label();
+                       mv.visitLabel(l1);
+                       mv.visitVarInsn(ALOAD, 0);
+                       mv.visitVarInsn(ALOAD, 1);
+                       mv.visitFieldInsn(PUTFIELD, classResourceName, "mi", "Lorg/simantics/databoard/method/MethodInterface;");
+                       Label l2 = new Label();
+                       mv.visitLabel(l2);
+                       mv.visitVarInsn(ALOAD, 0);
+                       mv.visitFieldInsn(GETSTATIC, classResourceName, "bindings", "[Lorg/simantics/databoard/method/MethodTypeBinding;");
+                       mv.visitInsn(ARRAYLENGTH);
+                       mv.visitTypeInsn(ANEWARRAY, "org/simantics/databoard/method/MethodInterface$Method");
+                       mv.visitFieldInsn(PUTFIELD, classResourceName, "methods", "[Lorg/simantics/databoard/method/MethodInterface$Method;");
+                       Label l3 = new Label();
+                       mv.visitLabel(l3);
+                       mv.visitInsn(ICONST_0);
+                       mv.visitVarInsn(ISTORE, 2);
+                       Label l4 = new Label();
+                       mv.visitLabel(l4);
+                       Label l5 = new Label();
+                       mv.visitJumpInsn(GOTO, l5);
+                       Label l6 = new Label();
+                       mv.visitLabel(l6);
+                       mv.visitFrame(Opcodes.F_FULL, 3, new Object[] {classResourceName, "org/simantics/databoard/method/MethodInterface", Opcodes.INTEGER}, 0, new Object[] {});
+                       mv.visitVarInsn(ALOAD, 0);
+                       mv.visitFieldInsn(GETFIELD, classResourceName, "methods", "[Lorg/simantics/databoard/method/MethodInterface$Method;");
+                       mv.visitVarInsn(ILOAD, 2);
+                       mv.visitVarInsn(ALOAD, 1);
+                       mv.visitFieldInsn(GETSTATIC, classResourceName, "bindings", "[Lorg/simantics/databoard/method/MethodTypeBinding;");
+                       mv.visitVarInsn(ILOAD, 2);
+                       mv.visitInsn(AALOAD);
+                       mv.visitMethodInsn(INVOKEINTERFACE, "org/simantics/databoard/method/MethodInterface", "getMethod", "(Lorg/simantics/databoard/method/MethodTypeBinding;)Lorg/simantics/databoard/method/MethodInterface$Method;");
+                       mv.visitInsn(AASTORE);
+                       Label l7 = new Label();
+                       mv.visitLabel(l7);
+                       mv.visitIincInsn(2, 1);
+                       mv.visitLabel(l5);
+                       mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
+                       mv.visitVarInsn(ILOAD, 2);
+                       mv.visitFieldInsn(GETSTATIC, classResourceName, "bindings", "[Lorg/simantics/databoard/method/MethodTypeBinding;");
+                       mv.visitInsn(ARRAYLENGTH);
+                       mv.visitJumpInsn(IF_ICMPLT, l6);
+                       Label l8 = new Label();
+                       mv.visitLabel(l8);
+                       mv.visitInsn(RETURN);
+                       Label l9 = new Label();
+                       mv.visitLabel(l9);
+                       mv.visitLocalVariable("this", classTypeDescriptor, null, l0, l9, 0);
+                       mv.visitLocalVariable("mi", "Lorg/simantics/databoard/method/MethodInterface;", null, l0, l9, 1);
+                       mv.visitLocalVariable("i", "I", null, l4, l8, 2);
+                       mv.visitMaxs(5, 3);
+                       mv.visitEnd();
+                       }
+                       
+                       // Method
+                       int methodNumber = 0;
+                       for (java.lang.reflect.Method m : methods)
+                       {
+                       String typeDescription = "";
+                       Class<?>[] params = m.getParameterTypes();
+                       for (int i=0; i<params.length; i++) {
+                               typeDescription += toTypeDescriptor(params[i]);
+                       }
+                       typeDescription = "("+typeDescription+")"+toTypeDescriptor(m.getReturnType());
+//                     System.out.println(typeDescription+" "+m.getName());
+                               
+                       Class<?>[] exceptions = m.getExceptionTypes();
+                       String[] exceptionResourceNames = new String[exceptions.length];
+                       for (int i=0; i<exceptionResourceNames.length; i++) {
+                               exceptionResourceNames[i] = exceptions[i].getName().replaceAll("\\.", "/");
+                       }
+                       
+                       // Registers
+                       // 0 - this
+                       // 1..argRegs args
+                       // argRegs+1 - method
+                       // argRegs+2 - args (the array)
+                       // argRegs+3 - AsyncResult
+                       // argRegs+4 - e
+                       // argRegs+5 - ExecutionError.cause
+                       // argRegs+6 - e
+                       
+                       int argRegs = 0;
+                       for (int i=0; i<params.length; i++) {
+                               Class<?> clazz = params[i];
+                               argRegs++;
+                               if (clazz==long.class || clazz==double.class) argRegs++;
+                       }               
+                       
+                       mv = cw.visitMethod(ACC_PUBLIC, m.getName(), typeDescription, null, exceptionResourceNames);
+                       mv.visitCode();
+                       Label l0 = new Label();
+                       Label l1 = new Label();
+                       Label l2 = new Label();
+                       mv.visitTryCatchBlock(l0, l1, l2, "org/simantics/databoard/method/MethodInterface$ExecutionError");
+                       Label l3 = new Label();
+                       mv.visitTryCatchBlock(l0, l1, l3, "java/lang/InterruptedException");
+                       Label l4 = new Label();
+                       mv.visitLabel(l4);
+                       mv.visitVarInsn(ALOAD, 0);
+                       mv.visitFieldInsn(GETFIELD, classResourceName, "methods", "[Lorg/simantics/databoard/method/MethodInterface$Method;");
+                       // Method m and puts into register 
+                       mv.visitLdcInsn(Integer.valueOf(methodNumber));
+                       mv.visitInsn(AALOAD);
+                       mv.visitVarInsn(ASTORE, argRegs+1);
+                       Label l5 = new Label();
+                       mv.visitLabel(l5);
+                       mv.visitLdcInsn(Integer.valueOf(params.length));
+                       mv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
+                       
+                       int register = 1; // argument register  
+                       for (int i=0; i<params.length; i++) {
+                               Class<?> clazz = params[i];
+                               mv.visitInsn(DUP);
+                               mv.visitLdcInsn(Integer.valueOf(i));
+                               
+                               if (clazz==byte.class) {
+                                       mv.visitVarInsn(ILOAD, register++);
+                                       mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;");                           
+                               } else if (clazz==char.class) {
+                                       mv.visitVarInsn(ILOAD, register++);
+                                       mv.visitMethodInsn(INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;");                         
+                               } else if (clazz==boolean.class) {
+                                       mv.visitVarInsn(ILOAD, register++);
+                                       mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;");                             
+                               } else if (clazz==byte.class) {
+                                       mv.visitVarInsn(ILOAD, register++);
+                                       mv.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;");                         
+                               } else if (clazz==int.class) {
+                                       mv.visitVarInsn(ILOAD, register++);
+                                       mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;");                             
+                               } else if (clazz==long.class) {
+                                       mv.visitVarInsn(LLOAD, register); register += 2;
+                                       mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(F)Ljava/lang/Long;");                           
+                               } else if (clazz==float.class) {
+                                       mv.visitVarInsn(FLOAD, register); register += 2;
+                                       mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;");                         
+                               } else if (clazz==double.class) {
+                                       mv.visitVarInsn(DLOAD, register); register += 2;
+                                       mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;");
+                               } else {                                
+                                       // Push argument to stack 
+                                       mv.visitVarInsn(ALOAD, register++); 
+                               }                       
+                               mv.visitInsn(AASTORE);
+                       }
+                       
+                       // Store args to argRegs+2
+                       mv.visitVarInsn(ASTORE, argRegs+2);
+                       Label l6 = new Label();
+                       mv.visitLabel(l6);
+                       mv.visitVarInsn(ALOAD, argRegs+1 /* m */);
+                       mv.visitVarInsn(ALOAD, argRegs+2 /*args*/);
+                       mv.visitMethodInsn(INVOKEINTERFACE, "org/simantics/databoard/method/MethodInterface$Method", "invoke", "(Ljava/lang/Object;)Lorg/simantics/databoard/method/MethodInterface$AsyncResult;");
+                       mv.visitVarInsn(ASTORE, argRegs+3);
+                       mv.visitLabel(l0);
+                       mv.visitVarInsn(ALOAD, argRegs+3);
+                       mv.visitMethodInsn(INVOKEINTERFACE, "org/simantics/databoard/method/MethodInterface$AsyncResult", "waitForResponse", "()Ljava/lang/Object;");
+                       // TODO Return typecase result
+                       Class<?> returnType = m.getReturnType();                
+                       
+                       if (returnType==void.class) {
+                               mv.visitInsn(POP);\r
+                               mv.visitLabel(l1);
+                               mv.visitInsn(RETURN);
+                       } else if (returnType==int.class) {
+                               mv.visitTypeInsn(CHECKCAST, "java/lang/Integer");
+                               mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I");
+                               mv.visitLabel(l1);
+                               mv.visitInsn(IRETURN);                  
+                       } else if (returnType==byte.class) {
+                               mv.visitTypeInsn(CHECKCAST, "java/lang/Byte");
+                               mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Byte", "byteValue", "B()");
+                               mv.visitLabel(l1);
+                               mv.visitInsn(IRETURN);                  
+                       } else if (returnType==char.class) {
+                               mv.visitTypeInsn(CHECKCAST, "java/lang/Character");
+                               mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C");
+                               mv.visitLabel(l1);
+                               mv.visitInsn(IRETURN);                  
+                       } else if (returnType==boolean.class) {
+                               mv.visitTypeInsn(CHECKCAST, "java/lang/Boolean");
+                               mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z");
+                               mv.visitLabel(l1);
+                               mv.visitInsn(IRETURN);                  
+                       } else if (returnType==short.class) {
+                               mv.visitTypeInsn(CHECKCAST, "java/lang/Short");
+                               mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Short", "shortValue", "()S");
+                               mv.visitLabel(l1);
+                               mv.visitInsn(IRETURN);                  
+                       } else if (returnType==long.class) {
+                               mv.visitTypeInsn(CHECKCAST, "java/lang/Long");
+                               mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J");
+                               mv.visitLabel(l1);
+                               mv.visitInsn(LRETURN);                  
+                       } else if (returnType==double.class) {
+                               mv.visitTypeInsn(CHECKCAST, "java/lang/Double");
+                               mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Double", "doubleValue", "()D");
+                               mv.visitLabel(l1);
+                               mv.visitInsn(DRETURN);                  
+                       } else if (returnType==float.class) {
+                               mv.visitTypeInsn(CHECKCAST, "java/lang/Float");
+                               mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Float", "floatValue", "()F");
+                               mv.visitLabel(l1);
+                               mv.visitInsn(FRETURN);                  
+                       } else {
+                               // Object
+                               mv.visitTypeInsn(CHECKCAST, returnType.getName().replaceAll("\\.", "/"));
+                               mv.visitLabel(l1);
+                               mv.visitInsn(ARETURN);                  
+                       }
+                       
+                       
+                       // Handle exceptions
+                       mv.visitLabel(l2);
+                       mv.visitFrame(Opcodes.F_FULL, 5, new Object[] {classResourceName, "java/lang/Integer", "org/simantics/databoard/method/MethodInterface$Method", "[Ljava/lang/Object;", "org/simantics/databoard/method/MethodInterface$AsyncResult"}, 1, new Object[] {"org/simantics/databoard/method/MethodInterface$ExecutionError"});
+                       mv.visitVarInsn(ASTORE, argRegs+4);
+                       Label l7 = new Label();
+                       mv.visitLabel(l7);
+                       mv.visitVarInsn(ALOAD, argRegs+4);
+                       mv.visitMethodInsn(INVOKEVIRTUAL, "org/simantics/databoard/method/MethodInterface$ExecutionError", "getError", "()Ljava/lang/Object;");
+                       mv.visitVarInsn(ASTORE, argRegs+5); // argRegs+5 <- ExecutionError.cause
+                                       
+                       Class<?>[] exceptionClasses = m.getExceptionTypes();
+                       Label nextException[] = new Label[exceptionClasses.length];             
+                       for (int i=0; i<exceptionClasses.length; i++)
+                       {                       
+                               Class<?> exceptionClass = exceptionClasses[i];
+                               String exceptionClassResourceName = exceptionClass.getName().replaceAll("\\.", "/");
+                               nextException[i] = new Label();
+                               // If instanceof MyException
+                               Label l8 = new Label();
+                               mv.visitLabel(l8);
+                               mv.visitVarInsn(ALOAD, argRegs+5); // Cause
+                               mv.visitTypeInsn(INSTANCEOF, exceptionClassResourceName);
+                               mv.visitJumpInsn(IFEQ, nextException[i]); // If not, go to ExecutionError
+                               // If so, throw it
+                               mv.visitVarInsn(ALOAD, argRegs+5); // e
+                               mv.visitTypeInsn(CHECKCAST, exceptionClassResourceName);
+                               mv.visitInsn(ATHROW);
+                               mv.visitLabel(nextException[i]);
+                       }
+                       
+                       // ExecutionError
+                       mv.visitFrame(Opcodes.F_APPEND,2, new Object[] {"org/simantics/databoard/method/MethodInterface$ExecutionError", "java/lang/Object"}, 0, null);
+                       mv.visitTypeInsn(NEW, "java/lang/RuntimeException");
+                       mv.visitInsn(DUP);
+                       mv.visitVarInsn(ALOAD, argRegs+4);
+                       mv.visitMethodInsn(INVOKESPECIAL, "java/lang/RuntimeException", "<init>", "(Ljava/lang/Throwable;)V");
+                       mv.visitInsn(ATHROW);
+                       
+                       // InteruptedException
+                       mv.visitLabel(l3);
+                       mv.visitFrame(Opcodes.F_FULL, 5, new Object[] {classResourceName, "java/lang/Integer", "org/simantics/databoard/method/MethodInterface$Method", "[Ljava/lang/Object;", "org/simantics/databoard/method/MethodInterface$AsyncResult"}, 1, new Object[] {"java/lang/InterruptedException"});
+                       mv.visitVarInsn(ASTORE, argRegs+4);
+                       Label l10 = new Label();
+                       mv.visitLabel(l10);
+                       mv.visitTypeInsn(NEW, "java/lang/RuntimeException");
+                       mv.visitInsn(DUP);
+                       mv.visitVarInsn(ALOAD, argRegs+4);
+                       mv.visitMethodInsn(INVOKESPECIAL, "java/lang/RuntimeException", "<init>", "(Ljava/lang/Throwable;)V");
+                       mv.visitInsn(ATHROW);
+                       
+                       Label l11 = new Label();
+                       mv.visitLabel(l11);
+                       mv.visitLocalVariable("this", classTypeDescriptor, null, l4, l11, 0);
+//                     mv.visitLocalVariable("arg1", "Ljava/lang/Integer;", null, l4, l11, 1);
+                       register = 1;
+                       for (int i=0; i<params.length; i++) {
+                               Class<?> clazz = params[i];
+                               mv.visitLocalVariable("arg"+(i+1), toTypeDescriptor(clazz), null, l4, l11, register);
+                               register++;
+                               if (clazz==long.class || clazz==double.class) argRegs++;
+                       }
+                       mv.visitLocalVariable("m", "Lorg/simantics/databoard/method/MethodInterface$Method;", null, l5, l11, argRegs+1);
+                       mv.visitLocalVariable("args", "[Ljava/lang/Object;", null, l6, l11, argRegs+2);
+                       mv.visitLocalVariable("result", "Lorg/simantics/databoard/method/MethodInterface$AsyncResult;", null, l0, l11, argRegs+3);
+                       mv.visitLocalVariable("e", "Lorg/simantics/databoard/method/MethodInterface$ExecutionError;", null, l7, l3, argRegs+4);
+                       mv.visitLocalVariable("cause", "Ljava/lang/Object;", null, l7, l3, argRegs+5);
+                       mv.visitLocalVariable("e", "Ljava/lang/InterruptedException;", null, l10, l11, argRegs+4);
+                       mv.visitMaxs(argRegs+3, argRegs+6);
+                       mv.visitEnd();
+                       methodNumber++;
+                       }
+
+                       cw.visitEnd();          
+               }
+               
+       }
+
+       
+       
+}
+