]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.databoard/src/org/simantics/databoard/method/MethodInterfaceUtil.java
Improve Databoard's dynamically typed data capabilities.
[simantics/platform.git] / bundles / org.simantics.databoard / src / org / simantics / databoard / method / MethodInterfaceUtil.java
1 /*******************************************************************************\r
2  *  Copyright (c) 2010 Association for Decentralized Information Management in\r
3  *  Industry THTH ry.\r
4  *  All rights reserved. This program and the accompanying materials\r
5  *  are made available under the terms of the Eclipse Public License v1.0\r
6  *  which accompanies this distribution, and is available at\r
7  *  http://www.eclipse.org/legal/epl-v10.html\r
8  *\r
9  *  Contributors:\r
10  *      VTT Technical Research Centre of Finland - initial API and implementation\r
11  *******************************************************************************/\r
12 package org.simantics.databoard.method;
13
14 import static org.objectweb.asm.Opcodes.AALOAD;\r
15 import static org.objectweb.asm.Opcodes.AASTORE;\r
16 import static org.objectweb.asm.Opcodes.ACC_ABSTRACT;\r
17 import static org.objectweb.asm.Opcodes.ACC_FINAL;\r
18 import static org.objectweb.asm.Opcodes.ACC_INTERFACE;\r
19 import static org.objectweb.asm.Opcodes.ACC_PUBLIC;\r
20 import static org.objectweb.asm.Opcodes.ACC_STATIC;\r
21 import static org.objectweb.asm.Opcodes.ACC_SUPER;\r
22 import static org.objectweb.asm.Opcodes.ALOAD;\r
23 import static org.objectweb.asm.Opcodes.ANEWARRAY;\r
24 import static org.objectweb.asm.Opcodes.ARETURN;\r
25 import static org.objectweb.asm.Opcodes.ARRAYLENGTH;\r
26 import static org.objectweb.asm.Opcodes.ASTORE;\r
27 import static org.objectweb.asm.Opcodes.ATHROW;\r
28 import static org.objectweb.asm.Opcodes.CHECKCAST;\r
29 import static org.objectweb.asm.Opcodes.DLOAD;\r
30 import static org.objectweb.asm.Opcodes.DRETURN;\r
31 import static org.objectweb.asm.Opcodes.DUP;\r
32 import static org.objectweb.asm.Opcodes.FLOAD;\r
33 import static org.objectweb.asm.Opcodes.FRETURN;\r
34 import static org.objectweb.asm.Opcodes.GETFIELD;\r
35 import static org.objectweb.asm.Opcodes.GETSTATIC;\r
36 import static org.objectweb.asm.Opcodes.GOTO;\r
37 import static org.objectweb.asm.Opcodes.ICONST_0;\r
38 import static org.objectweb.asm.Opcodes.IFEQ;\r
39 import static org.objectweb.asm.Opcodes.IF_ICMPLT;\r
40 import static org.objectweb.asm.Opcodes.ILOAD;\r
41 import static org.objectweb.asm.Opcodes.INSTANCEOF;\r
42 import static org.objectweb.asm.Opcodes.INVOKEINTERFACE;\r
43 import static org.objectweb.asm.Opcodes.INVOKESPECIAL;\r
44 import static org.objectweb.asm.Opcodes.INVOKESTATIC;\r
45 import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL;\r
46 import static org.objectweb.asm.Opcodes.IRETURN;\r
47 import static org.objectweb.asm.Opcodes.ISTORE;\r
48 import static org.objectweb.asm.Opcodes.LLOAD;\r
49 import static org.objectweb.asm.Opcodes.LRETURN;\r
50 import static org.objectweb.asm.Opcodes.NEW;\r
51 import static org.objectweb.asm.Opcodes.POP;\r
52 import static org.objectweb.asm.Opcodes.PUTFIELD;\r
53 import static org.objectweb.asm.Opcodes.PUTSTATIC;\r
54 import static org.objectweb.asm.Opcodes.RETURN;\r
55 import static org.objectweb.asm.Opcodes.V1_6;\r
56 \r
57 import java.lang.reflect.Constructor;\r
58 import java.lang.reflect.InvocationTargetException;\r
59 import java.lang.reflect.Method;\r
60 import java.util.Arrays;\r
61 import java.util.Comparator;\r
62 import java.util.HashSet;\r
63 import java.util.Set;\r
64 \r
65 import org.objectweb.asm.ClassWriter;\r
66 import org.objectweb.asm.FieldVisitor;\r
67 import org.objectweb.asm.Label;\r
68 import org.objectweb.asm.MethodVisitor;\r
69 import org.objectweb.asm.Opcodes;\r
70 import org.objectweb.asm.Type;\r
71 import org.simantics.databoard.Bindings;\r
72 import org.simantics.databoard.Methods;\r
73 import org.simantics.databoard.adapter.AdaptException;\r
74 import org.simantics.databoard.adapter.Adapter;\r
75 import org.simantics.databoard.adapter.AdapterConstructionException;\r
76 import org.simantics.databoard.binding.error.BindingConstructionException;\r
77 import org.simantics.databoard.method.MethodInterface.AsyncResult;\r
78 import org.simantics.databoard.method.MethodInterface.ExecutionError;\r
79
80 public class MethodInterfaceUtil {
81
82         /**
83          * Bind an instance a to Method Interface 
84          * 
85          * @param <T>
86          * @param interfaze
87          * @param obj
88          * @return the method interface
89          * @throws BindingConstructionException
90          */
91         public static <T> MethodInterface bindInterface(Class<T> interfaze, final T obj) throws BindingConstructionException
92         {
93                 final Interface interfaceType = Methods.getInterfaceType(interfaze);
94                 MethodInterface mi = bindInterface(interfaceType, obj);\r
95                 /*\r
96                 System.out.println("Created methodinterface for "+interfaze.getName());\r
97                 for (MethodTypeDefinition k : mi.getInterface().methodDefinitions) {\r
98                         System.out.print(k);\r
99                         if (k.getType().requestType.getComponentCount()>0) {\r
100                                 System.out.print(System.identityHashCode( k.getType().requestType.getComponentType(0) ) );\r
101                         }\r
102                         System.out.println();                                   \r
103                 }\r
104                 */\r
105                 return mi;
106         }
107         
108         /**
109          * Bind interface type to an instance 
110          * 
111          * @param <T>
112          * @param interfaceType
113          * @param obj
114          * @return the method interface
115          * @throws BindingConstructionException
116          */
117         public static <T> MethodInterface bindInterface(final Interface interfaceType, final T obj) throws BindingConstructionException
118         {               
119                 // Find matching Java Method for each MethodTypeDefinition
120                 int len = interfaceType.getMethodDefinitions().length;
121                 final MethodTypeDefinition[] methodDefinitions = interfaceType.getMethodDefinitions();
122                 final MethodTypeBinding[] methodBindings = new MethodTypeBinding[ len ];
123                 final Method[] methods = new Method[ len ];
124                 Class<?> clazz = obj.getClass();
125                 Method[] classMethods = clazz.getMethods();
126                 for (int i=0; i<len; i++)
127                 {
128                         MethodTypeDefinition def = methodDefinitions[i];
129                         MethodType type = def.getType();
130                         String name = def.getName();
131                         
132                         // Find the MethodType from the class methods
133                         for (Method m : classMethods) {
134                                 // Verify name matchs
135                                 if ( !m.getName().equals(name) ) continue;
136                                 MethodTypeBinding classMethodTypeBinding = Methods.getMethodTypeBinding(m);
137                                 if ( !classMethodTypeBinding.getMethodType().equals( type) ) continue;
138                                 
139                                 m.setAccessible(true);
140                                 methodBindings[i] = classMethodTypeBinding; 
141                                 methods[i] = m;
142                                 break;
143                         }
144                         
145                         // We did not find suitable method in clazz
146                         if (methods[i]==null) {
147                                 throw new BindingConstructionException("Could not find method "+def+" in "+clazz.getSimpleName());
148                         }
149                 }
150                 
151                 // Read method definitions into an array
152                 
153                 MethodInterface mi = new MethodInterface() {
154                         @Override
155                         public org.simantics.databoard.method.MethodInterface.Method getMethod(
156                                         MethodTypeDefinition description)
157                                         throws org.simantics.databoard.method.MethodNotSupportedException {
158                                 int index = -1;
159                                 for (int i=0; i<methodDefinitions.length; i++) {
160                                         if (methodDefinitions[i].equals(description)) {
161                                                 index = i;
162                                                 break;
163                                         } 
164                                 }
165                                 if (index<0) throw new org.simantics.databoard.method.MethodNotSupportedException(description.getName());
166                                 final MethodTypeBinding binding = methodBindings[index];
167                                 final java.lang.reflect.Method method = methods[index];
168                                 
169                                 Method m = new Method() {
170                                         @Override
171                                         public MethodTypeBinding getMethodBinding() {
172                                                 return binding;
173                                         }
174
175                                         @Override
176                                         public AsyncResult invoke(Object request) {
177                                                 AsyncResultImpl result = new AsyncResultImpl(); 
178                                                 try {
179                                                         Object response = method.invoke(obj, (Object[]) request);
180                                                         if (response != null) result.setResponse(response);\r
181                                                         else result.setInvokeException(new org.simantics.databoard.method.InvokeException(new NullPointerException()));
182                                                 } catch(InvocationTargetException t) {\r
183                                                         Throwable e = t.getTargetException();\r
184                                                         if (e instanceof RuntimeException) {\r
185                                                                 result.setInvokeException(new org.simantics.databoard.method.InvokeException( (Exception) e));\r
186                                                         } else {
187                                                                 result.setExecutionError(e);\r
188                                                         }
189                                                 } catch(IllegalArgumentException e) {
190                                                         result.setInvokeException(new org.simantics.databoard.method.InvokeException(e));
191                                                 } catch (IllegalAccessException e) {
192                                                         result.setInvokeException(new org.simantics.databoard.method.InvokeException(e));
193                                                 }
194                                                 return result;
195                                         }
196                                         
197                                 };
198                                 return m;
199                         }
200                         @Override
201                         public org.simantics.databoard.method.MethodInterface.Method getMethod(
202                                         MethodTypeBinding binding) throws org.simantics.databoard.method.MethodNotSupportedException {
203                                 MethodTypeDefinition description = binding.getMethodDefinition();
204                                 int index = -1;                         
205                                 for (int i=0; i<methodDefinitions.length; i++) {
206                                         if (methodDefinitions[i].equals(description)) {
207                                                 index = i;
208                                                 break;
209                                         } 
210                                 }
211                                 if (index<0) throw new org.simantics.databoard.method.MethodNotSupportedException(description.getName());
212                                 final MethodTypeBinding producerBinding = methodBindings[index];
213                                 final MethodTypeBinding consumerBinding = binding;
214                                 try {
215                                         final Adapter requestAdapter = Bindings.getTypeAdapter(consumerBinding.getRequestBinding(), producerBinding.getRequestBinding());
216                                         final Adapter responseAdapter = Bindings.getTypeAdapter(producerBinding.getResponseBinding(), consumerBinding.getResponseBinding());
217                                         final Adapter errorAdapter = Bindings.getTypeAdapter(producerBinding.getErrorBinding(), consumerBinding.getErrorBinding());
218                                         final java.lang.reflect.Method method = methods[index];
219
220                                         Method m = new Method() {
221                                                 @Override
222                                                 public MethodTypeBinding getMethodBinding() {
223                                                         return consumerBinding;
224                                                 }
225
226                                                 @Override
227                                                 public AsyncResult invoke(Object request) {
228                                                         AsyncResultImpl result = new AsyncResultImpl();
229                                                         
230                                                         try {
231                                                                 request = requestAdapter.adapt(request);
232                                                                 Object response = method.invoke(obj, (Object[]) request);
233                                                                 response = responseAdapter.adapt(response);
234                                                                 result.setResponse(response);
235                                                         } catch (AdaptException e1) {
236                                                                 result.setInvokeException(new InvokeException(e1));
237                                                         } catch (InvocationTargetException t) {
238                                                                 Object error;
239                                                                 try {
240                                                                         error = errorAdapter.adapt(t.getCause());
241                                                                         result.setExecutionError(error);
242                                                                 } catch (AdaptException e) {
243                                                                         result.setInvokeException( new InvokeException(e) );
244                                                                 }
245                                                         } catch (IllegalArgumentException e) {
246                                                                 result.setInvokeException(new org.simantics.databoard.method.InvokeException(e));
247                                                         } catch (IllegalAccessException e) {
248                                                                 result.setInvokeException(new org.simantics.databoard.method.InvokeException(e));
249                                                         }
250                                                         return result;
251                                                 }
252
253                                         };                      
254                                 return m;
255                                 
256                                 } catch (AdapterConstructionException e1) {
257                                         throw new MethodNotSupportedException("Could not adapt method "+e1.getMessage(), e1);
258                                 }
259                                 
260                         }
261                         
262                         @Override
263                         public Interface getInterface() {
264                                 return interfaceType;
265                         }};
266                 
267                 return mi;
268         }
269         
270         @SuppressWarnings("unchecked")
271         public static <T> T createProxy(Class<T> interfaze, MethodInterface mi)
272         throws BindingConstructionException
273         {
274                 StubClassLoader cl = new StubClassLoader(interfaze.getClassLoader());
275                 Class<?> virhe;
276                 try {
277                         virhe = cl.loadClass(interfaze.getName()+"_Stub");
278                         Constructor<?> c = virhe.getConstructor(MethodInterface.class);
279                         return (T) c.newInstance(mi);
280                 } catch (ClassNotFoundException e) {
281                         System.err.println("Did you remember to include org.objectweb.asm ??");
282                         throw new BindingConstructionException(e);
283                 } catch (SecurityException e) {
284                         throw new BindingConstructionException(e);
285                 } catch (NoSuchMethodException e) {
286                         throw new BindingConstructionException(e);
287                 } catch (IllegalArgumentException e) {
288                         throw new BindingConstructionException(e);
289                 } catch (InstantiationException e) {
290                         throw new BindingConstructionException(e);
291                 } catch (IllegalAccessException e) {
292                         throw new BindingConstructionException(e);
293                 } catch (InvocationTargetException e) {
294                         throw new BindingConstructionException(e.getCause());
295                 }
296         }
297
298         public static Comparator<java.lang.reflect.Method> methodComparator = new Comparator<java.lang.reflect.Method>(){
299                 @Override public int compare(java.lang.reflect.Method o1,java.lang.reflect.Method o2){
300                 return o1.getName().compareTo(o2.getName());}};
301                 
302         public static MethodInterface adaptMethods(final MethodInterface mi, final MethodTypeDefinition[] rangeMethods)
303         {
304                 //final MethodTypeDefinition[] domainMethods = mi.getInterface().getMethodDefinitions();
305                 throw new IllegalArgumentException("To be implemented");
306                 /*
307                 return new MethodInterface() {
308                         @Override
309                         public org.simantics.databoard.method.MethodInterface.Method getMethod(
310                                         MethodDescription rangeDescription)
311                                         throws MethodNotSupportedException {
312                                 MethodDescription domainDescription = null;
313                                 for (int i=0; i<rangeMethods.length; i++) {
314                                         if (rangeMethods[i].equals(rangeDescription)) {
315                                                 domainDescription = domainMethods[i];
316                                         }
317                                 }
318                                 if (domainDescription==null)
319                                         throw new MethodNotSupportedException();
320                                 
321                                 return new org.simantics.databoard.method.MethodInterface.Method() {
322                                         @Override
323                                         public MethodBinding getMethodBinding() {
324                                                 return null;
325                                         }
326                                         @Override
327                                         public AsyncResult invoke(Object request) {
328                                                 return null;
329                                         }
330                                 };
331                         }
332                         @Override
333                         public org.simantics.databoard.method.MethodInterface.Method getMethod(
334                                         MethodBinding binding) throws MethodNotSupportedException {
335                                 return null;
336                         }
337                         @Override
338                         public MethodDescription[] getMethodDescriptions() {
339                                 return rangeMethods;
340                         }
341                 };
342                 */
343         }
344         
345         static class StubClassLoader extends ClassLoader {
346                 
347                 public StubClassLoader() {
348                         super(Thread.currentThread().getContextClassLoader());
349                 }
350
351                 public StubClassLoader(ClassLoader parent) {
352                         super(parent);
353                 }
354
355                 @Override
356                 protected Class<?> findClass(String name) throws ClassNotFoundException {
357                         if (name.endsWith("_Stub")) {
358                                 Class<?> interfaze = loadClass(name.substring(0, name.length()-5));
359                                 ClassWriter cw = new ClassWriter(0);
360                                 createImpl(name, interfaze, cw);
361                                 byte[] b = cw.toByteArray();\r
362                                 /*\r
363                                 new ClassReader(b).accept(\r
364                                                 new ASMifierClassVisitor(new PrintWriter(System.out)),\r
365                                                 0\r
366                                         );\r
367                                 */
368                                 Class<?> clazz = defineClass(name, b, 0, b.length);
369                                 return clazz;
370                         }
371                         return super.findClass(name);
372                 }
373
374                 static String toTypeDescriptor(Class<?> clazz) {
375                         if (clazz==void.class) return "V";
376                         if (clazz==boolean.class) return "Z";
377                         if (clazz==char.class) return "C";
378                         if (clazz==byte.class) return "B";
379                         if (clazz==short.class) return "S";
380                         if (clazz==int.class) return "I";
381                         if (clazz==float.class) return "F";
382                         if (clazz==long.class) return "J";
383                         if (clazz==double.class) return "D";
384                         if (clazz.isArray()) return clazz.getName().replaceAll("\\.", "/");             
385                         return "L"+clazz.getName().replaceAll("\\.", "/")+";";
386                 }
387                 
388                 void createImpl(String className, Class<?> interfaze, ClassWriter cw) {
389                         FieldVisitor fv;
390                         MethodVisitor mv;
391                         //AnnotationVisitor av0;
392                         
393                         java.lang.reflect.Method[] methods = interfaze.getMethods();
394                         Arrays.sort(methods, MethodInterfaceUtil.methodComparator);
395
396                         String classResourceName = className.replaceAll("\\.", "/");
397                         String classTypeDescriptor = "L"+classResourceName+";";
398                         String interfaceResourceName = classResourceName.substring(0, classResourceName.length()-5);
399                         String interfaceTypeDescriptor = "L"+interfaceResourceName+";";
400                         
401                         cw.visit(V1_6, ACC_SUPER | ACC_PUBLIC, classResourceName, null, "java/lang/Object", new String[] { interfaceResourceName });
402
403                         // Imports
404                         Set<Class<?>> imports = new HashSet<Class<?>>();
405                         imports.add(AsyncResult.class);
406                         imports.add(ExecutionError.class);
407                         imports.add(Method.class);
408                         imports.add(interfaze);
409                         
410                         for (java.lang.reflect.Method m : methods) {
411                                 for (Class<?> clazz : m.getExceptionTypes()) {
412                                         imports.add(clazz);
413                                 }
414                                 for (Class<?> clazz : m.getParameterTypes()) {
415                                         imports.add(clazz);                             
416                                 }
417                                 imports.add(m.getReturnType());                 
418                         }
419                         
420                         for (Class<?> clazz : imports) {
421                                 if (clazz.isPrimitive()) continue;
422                                 String name = clazz.getName();
423                                 if (name.startsWith("java.lang")) continue;
424                                 String resourceName = name.replaceAll("\\.", "/");
425                                 String outerName = resourceName.contains("$") ? resourceName.substring(0, resourceName.indexOf('$')) : null;
426                                 String className_ = clazz.isArray() ? clazz.getSimpleName().substring(0, clazz.getSimpleName().length()-2) : clazz.getSimpleName();
427                                 int access = ACC_PUBLIC + ACC_STATIC + (clazz.isInterface() ? ACC_INTERFACE + ACC_ABSTRACT : 0);
428 //                              System.out.printf("name=%s, outerName=%s, innerName=%s\n", resourceName, outerName, className_);
429                                 cw.visitInnerClass(resourceName, outerName, className_, access);                        
430                         }
431                         
432                         // Fields
433                         {
434                         fv = cw.visitField(ACC_FINAL + ACC_STATIC, "interfaze", "Ljava/lang/Class;", "Ljava/lang/Class<*>;", null);
435                         fv.visitEnd();
436                         }
437                         {
438                         fv = cw.visitField(ACC_FINAL + ACC_STATIC, "bindings", "[Lorg/simantics/databoard/method/MethodTypeBinding;", null, null);
439                         fv.visitEnd();
440                         }
441                         {
442                         fv = cw.visitField(0, "mi", "Lorg/simantics/databoard/method/MethodInterface;", null, null);
443                         fv.visitEnd();
444                         }
445                         {
446                         fv = cw.visitField(0, "methods", "[Lorg/simantics/databoard/method/MethodInterface$Method;", null, null);
447                         fv.visitEnd();
448                         }
449                         
450                         // Init class - static {}
451                         {
452                         mv = cw.visitMethod(ACC_STATIC, "<clinit>", "()V", null, null);
453                         mv.visitCode();
454                         Label l0 = new Label();
455                         mv.visitLabel(l0);
456                         mv.visitLdcInsn(Type.getType(interfaceTypeDescriptor));
457                         mv.visitFieldInsn(PUTSTATIC, classResourceName, "interfaze", "Ljava/lang/Class;");
458                         Label l1 = new Label();
459                         mv.visitLabel(l1);
460                         mv.visitFieldInsn(GETSTATIC, classResourceName, "interfaze", "Ljava/lang/Class;");
461                         mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getMethods", "()[Ljava/lang/reflect/Method;");
462                         mv.visitVarInsn(ASTORE, 0);
463                         Label l2 = new Label();
464                         mv.visitLabel(l2);
465                         mv.visitVarInsn(ALOAD, 0);
466                         mv.visitFieldInsn(GETSTATIC, "org/simantics/databoard/method/MethodInterfaceUtil", "methodComparator", "Ljava/util/Comparator;");
467                         mv.visitMethodInsn(INVOKESTATIC, "java/util/Arrays", "sort", "([Ljava/lang/Object;Ljava/util/Comparator;)V");
468                         Label l3 = new Label();
469                         mv.visitLabel(l3);
470                         mv.visitVarInsn(ALOAD, 0);
471                         mv.visitInsn(ARRAYLENGTH);
472                         mv.visitTypeInsn(ANEWARRAY, "org/simantics/databoard/method/MethodTypeBinding");
473                         mv.visitFieldInsn(PUTSTATIC, classResourceName, "bindings", "[Lorg/simantics/databoard/method/MethodTypeBinding;");
474                         Label l4 = new Label();
475                         mv.visitLabel(l4);
476                         mv.visitInsn(ICONST_0);
477                         mv.visitVarInsn(ISTORE, 1);
478                         Label l5 = new Label();
479                         mv.visitLabel(l5);
480                         Label l6 = new Label();
481                         mv.visitJumpInsn(GOTO, l6);
482                         Label l7 = new Label();
483                         mv.visitLabel(l7);
484                         mv.visitFrame(Opcodes.F_APPEND,2, new Object[] {"[Ljava/lang/reflect/Method;", Opcodes.INTEGER}, 0, null);
485                         mv.visitFieldInsn(GETSTATIC, classResourceName, "bindings", "[Lorg/simantics/databoard/method/MethodTypeBinding;");
486                         mv.visitVarInsn(ILOAD, 1);
487                         mv.visitVarInsn(ALOAD, 0);
488                         mv.visitVarInsn(ILOAD, 1);
489                         mv.visitInsn(AALOAD);
490                         mv.visitMethodInsn(INVOKESTATIC, "org/simantics/databoard/Methods", "getMethodTypeBinding", "(Ljava/lang/reflect/Method;)Lorg/simantics/databoard/method/MethodTypeBinding;");
491                         mv.visitInsn(AASTORE);
492                         Label l8 = new Label();
493                         mv.visitLabel(l8);
494                         mv.visitIincInsn(1, 1);
495                         mv.visitLabel(l6);
496                         mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
497                         mv.visitVarInsn(ILOAD, 1);
498                         mv.visitFieldInsn(GETSTATIC, classResourceName, "bindings", "[Lorg/simantics/databoard/method/MethodTypeBinding;");
499                         mv.visitInsn(ARRAYLENGTH);
500                         mv.visitJumpInsn(IF_ICMPLT, l7);
501                         Label l9 = new Label();
502                         mv.visitLabel(l9);
503                         mv.visitInsn(RETURN);
504                         Label l10 = new Label();
505                         mv.visitLabel(l10);
506                         mv.visitLocalVariable("methods", "[Ljava/lang/reflect/Method;", null, l2, l10, 0);
507                         mv.visitLocalVariable("i", "I", null, l5, l9, 1);
508                         mv.visitMaxs(4, 2);
509                         mv.visitEnd();
510                         }
511                         
512                         // Constructor
513                         {
514                         mv = cw.visitMethod(ACC_PUBLIC, "<init>", "(Lorg/simantics/databoard/method/MethodInterface;)V", null, new String[] { "org/simantics/databoard/method/MethodNotSupportedException" });
515                         mv.visitCode();
516                         Label l0 = new Label();
517                         mv.visitLabel(l0);
518                         mv.visitVarInsn(ALOAD, 0);
519                         mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
520                         Label l1 = new Label();
521                         mv.visitLabel(l1);
522                         mv.visitVarInsn(ALOAD, 0);
523                         mv.visitVarInsn(ALOAD, 1);
524                         mv.visitFieldInsn(PUTFIELD, classResourceName, "mi", "Lorg/simantics/databoard/method/MethodInterface;");
525                         Label l2 = new Label();
526                         mv.visitLabel(l2);
527                         mv.visitVarInsn(ALOAD, 0);
528                         mv.visitFieldInsn(GETSTATIC, classResourceName, "bindings", "[Lorg/simantics/databoard/method/MethodTypeBinding;");
529                         mv.visitInsn(ARRAYLENGTH);
530                         mv.visitTypeInsn(ANEWARRAY, "org/simantics/databoard/method/MethodInterface$Method");
531                         mv.visitFieldInsn(PUTFIELD, classResourceName, "methods", "[Lorg/simantics/databoard/method/MethodInterface$Method;");
532                         Label l3 = new Label();
533                         mv.visitLabel(l3);
534                         mv.visitInsn(ICONST_0);
535                         mv.visitVarInsn(ISTORE, 2);
536                         Label l4 = new Label();
537                         mv.visitLabel(l4);
538                         Label l5 = new Label();
539                         mv.visitJumpInsn(GOTO, l5);
540                         Label l6 = new Label();
541                         mv.visitLabel(l6);
542                         mv.visitFrame(Opcodes.F_FULL, 3, new Object[] {classResourceName, "org/simantics/databoard/method/MethodInterface", Opcodes.INTEGER}, 0, new Object[] {});
543                         mv.visitVarInsn(ALOAD, 0);
544                         mv.visitFieldInsn(GETFIELD, classResourceName, "methods", "[Lorg/simantics/databoard/method/MethodInterface$Method;");
545                         mv.visitVarInsn(ILOAD, 2);
546                         mv.visitVarInsn(ALOAD, 1);
547                         mv.visitFieldInsn(GETSTATIC, classResourceName, "bindings", "[Lorg/simantics/databoard/method/MethodTypeBinding;");
548                         mv.visitVarInsn(ILOAD, 2);
549                         mv.visitInsn(AALOAD);
550                         mv.visitMethodInsn(INVOKEINTERFACE, "org/simantics/databoard/method/MethodInterface", "getMethod", "(Lorg/simantics/databoard/method/MethodTypeBinding;)Lorg/simantics/databoard/method/MethodInterface$Method;");
551                         mv.visitInsn(AASTORE);
552                         Label l7 = new Label();
553                         mv.visitLabel(l7);
554                         mv.visitIincInsn(2, 1);
555                         mv.visitLabel(l5);
556                         mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
557                         mv.visitVarInsn(ILOAD, 2);
558                         mv.visitFieldInsn(GETSTATIC, classResourceName, "bindings", "[Lorg/simantics/databoard/method/MethodTypeBinding;");
559                         mv.visitInsn(ARRAYLENGTH);
560                         mv.visitJumpInsn(IF_ICMPLT, l6);
561                         Label l8 = new Label();
562                         mv.visitLabel(l8);
563                         mv.visitInsn(RETURN);
564                         Label l9 = new Label();
565                         mv.visitLabel(l9);
566                         mv.visitLocalVariable("this", classTypeDescriptor, null, l0, l9, 0);
567                         mv.visitLocalVariable("mi", "Lorg/simantics/databoard/method/MethodInterface;", null, l0, l9, 1);
568                         mv.visitLocalVariable("i", "I", null, l4, l8, 2);
569                         mv.visitMaxs(5, 3);
570                         mv.visitEnd();
571                         }
572                         
573                         // Method
574                         int methodNumber = 0;
575                         for (java.lang.reflect.Method m : methods)
576                         {
577                         String typeDescription = "";
578                         Class<?>[] params = m.getParameterTypes();
579                         for (int i=0; i<params.length; i++) {
580                                 typeDescription += toTypeDescriptor(params[i]);
581                         }
582                         typeDescription = "("+typeDescription+")"+toTypeDescriptor(m.getReturnType());
583 //                      System.out.println(typeDescription+" "+m.getName());
584                                 
585                         Class<?>[] exceptions = m.getExceptionTypes();
586                         String[] exceptionResourceNames = new String[exceptions.length];
587                         for (int i=0; i<exceptionResourceNames.length; i++) {
588                                 exceptionResourceNames[i] = exceptions[i].getName().replaceAll("\\.", "/");
589                         }
590                         
591                         // Registers
592                         // 0 - this
593                         // 1..argRegs args
594                         // argRegs+1 - method
595                         // argRegs+2 - args (the array)
596                         // argRegs+3 - AsyncResult
597                         // argRegs+4 - e
598                         // argRegs+5 - ExecutionError.cause
599                         // argRegs+6 - e
600                         
601                         int argRegs = 0;
602                         for (int i=0; i<params.length; i++) {
603                                 Class<?> clazz = params[i];
604                                 argRegs++;
605                                 if (clazz==long.class || clazz==double.class) argRegs++;
606                         }               
607                         
608                         mv = cw.visitMethod(ACC_PUBLIC, m.getName(), typeDescription, null, exceptionResourceNames);
609                         mv.visitCode();
610                         Label l0 = new Label();
611                         Label l1 = new Label();
612                         Label l2 = new Label();
613                         mv.visitTryCatchBlock(l0, l1, l2, "org/simantics/databoard/method/MethodInterface$ExecutionError");
614                         Label l3 = new Label();
615                         mv.visitTryCatchBlock(l0, l1, l3, "java/lang/InterruptedException");
616                         Label l4 = new Label();
617                         mv.visitLabel(l4);
618                         mv.visitVarInsn(ALOAD, 0);
619                         mv.visitFieldInsn(GETFIELD, classResourceName, "methods", "[Lorg/simantics/databoard/method/MethodInterface$Method;");
620                         // Method m and puts into register 
621                         mv.visitLdcInsn(Integer.valueOf(methodNumber));
622                         mv.visitInsn(AALOAD);
623                         mv.visitVarInsn(ASTORE, argRegs+1);
624                         Label l5 = new Label();
625                         mv.visitLabel(l5);
626                         mv.visitLdcInsn(Integer.valueOf(params.length));
627                         mv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
628                         
629                         int register = 1; // argument register  
630                         for (int i=0; i<params.length; i++) {
631                                 Class<?> clazz = params[i];
632                                 mv.visitInsn(DUP);
633                                 mv.visitLdcInsn(Integer.valueOf(i));
634                                 
635                                 if (clazz==byte.class) {
636                                         mv.visitVarInsn(ILOAD, register++);
637                                         mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;");                           
638                                 } else if (clazz==char.class) {
639                                         mv.visitVarInsn(ILOAD, register++);
640                                         mv.visitMethodInsn(INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;");                         
641                                 } else if (clazz==boolean.class) {
642                                         mv.visitVarInsn(ILOAD, register++);
643                                         mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;");                             
644                                 } else if (clazz==byte.class) {
645                                         mv.visitVarInsn(ILOAD, register++);
646                                         mv.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;");                         
647                                 } else if (clazz==int.class) {
648                                         mv.visitVarInsn(ILOAD, register++);
649                                         mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;");                             
650                                 } else if (clazz==long.class) {
651                                         mv.visitVarInsn(LLOAD, register); register += 2;
652                                         mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(F)Ljava/lang/Long;");                           
653                                 } else if (clazz==float.class) {
654                                         mv.visitVarInsn(FLOAD, register); register += 2;
655                                         mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;");                         
656                                 } else if (clazz==double.class) {
657                                         mv.visitVarInsn(DLOAD, register); register += 2;
658                                         mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;");
659                                 } else {                                
660                                         // Push argument to stack 
661                                         mv.visitVarInsn(ALOAD, register++); 
662                                 }                       
663                                 mv.visitInsn(AASTORE);
664                         }
665                         
666                         // Store args to argRegs+2
667                         mv.visitVarInsn(ASTORE, argRegs+2);
668                         Label l6 = new Label();
669                         mv.visitLabel(l6);
670                         mv.visitVarInsn(ALOAD, argRegs+1 /* m */);
671                         mv.visitVarInsn(ALOAD, argRegs+2 /*args*/);
672                         mv.visitMethodInsn(INVOKEINTERFACE, "org/simantics/databoard/method/MethodInterface$Method", "invoke", "(Ljava/lang/Object;)Lorg/simantics/databoard/method/MethodInterface$AsyncResult;");
673                         mv.visitVarInsn(ASTORE, argRegs+3);
674                         mv.visitLabel(l0);
675                         mv.visitVarInsn(ALOAD, argRegs+3);
676                         mv.visitMethodInsn(INVOKEINTERFACE, "org/simantics/databoard/method/MethodInterface$AsyncResult", "waitForResponse", "()Ljava/lang/Object;");
677                         // TODO Return typecase result
678                         Class<?> returnType = m.getReturnType();                
679                         
680                         if (returnType==void.class) {
681                                 mv.visitInsn(POP);\r
682                                 mv.visitLabel(l1);
683                                 mv.visitInsn(RETURN);
684                         } else if (returnType==int.class) {
685                                 mv.visitTypeInsn(CHECKCAST, "java/lang/Integer");
686                                 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I");
687                                 mv.visitLabel(l1);
688                                 mv.visitInsn(IRETURN);                  
689                         } else if (returnType==byte.class) {
690                                 mv.visitTypeInsn(CHECKCAST, "java/lang/Byte");
691                                 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Byte", "byteValue", "B()");
692                                 mv.visitLabel(l1);
693                                 mv.visitInsn(IRETURN);                  
694                         } else if (returnType==char.class) {
695                                 mv.visitTypeInsn(CHECKCAST, "java/lang/Character");
696                                 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C");
697                                 mv.visitLabel(l1);
698                                 mv.visitInsn(IRETURN);                  
699                         } else if (returnType==boolean.class) {
700                                 mv.visitTypeInsn(CHECKCAST, "java/lang/Boolean");
701                                 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z");
702                                 mv.visitLabel(l1);
703                                 mv.visitInsn(IRETURN);                  
704                         } else if (returnType==short.class) {
705                                 mv.visitTypeInsn(CHECKCAST, "java/lang/Short");
706                                 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Short", "shortValue", "()S");
707                                 mv.visitLabel(l1);
708                                 mv.visitInsn(IRETURN);                  
709                         } else if (returnType==long.class) {
710                                 mv.visitTypeInsn(CHECKCAST, "java/lang/Long");
711                                 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J");
712                                 mv.visitLabel(l1);
713                                 mv.visitInsn(LRETURN);                  
714                         } else if (returnType==double.class) {
715                                 mv.visitTypeInsn(CHECKCAST, "java/lang/Double");
716                                 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Double", "doubleValue", "()D");
717                                 mv.visitLabel(l1);
718                                 mv.visitInsn(DRETURN);                  
719                         } else if (returnType==float.class) {
720                                 mv.visitTypeInsn(CHECKCAST, "java/lang/Float");
721                                 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Float", "floatValue", "()F");
722                                 mv.visitLabel(l1);
723                                 mv.visitInsn(FRETURN);                  
724                         } else {
725                                 // Object
726                                 mv.visitTypeInsn(CHECKCAST, returnType.getName().replaceAll("\\.", "/"));
727                                 mv.visitLabel(l1);
728                                 mv.visitInsn(ARETURN);                  
729                         }
730                         
731                         
732                         // Handle exceptions
733                         mv.visitLabel(l2);
734                         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"});
735                         mv.visitVarInsn(ASTORE, argRegs+4);
736                         Label l7 = new Label();
737                         mv.visitLabel(l7);
738                         mv.visitVarInsn(ALOAD, argRegs+4);
739                         mv.visitMethodInsn(INVOKEVIRTUAL, "org/simantics/databoard/method/MethodInterface$ExecutionError", "getError", "()Ljava/lang/Object;");
740                         mv.visitVarInsn(ASTORE, argRegs+5); // argRegs+5 <- ExecutionError.cause
741                                         
742                         Class<?>[] exceptionClasses = m.getExceptionTypes();
743                         Label nextException[] = new Label[exceptionClasses.length];             
744                         for (int i=0; i<exceptionClasses.length; i++)
745                         {                       
746                                 Class<?> exceptionClass = exceptionClasses[i];
747                                 String exceptionClassResourceName = exceptionClass.getName().replaceAll("\\.", "/");
748                                 nextException[i] = new Label();
749                                 // If instanceof MyException
750                                 Label l8 = new Label();
751                                 mv.visitLabel(l8);
752                                 mv.visitVarInsn(ALOAD, argRegs+5); // Cause
753                                 mv.visitTypeInsn(INSTANCEOF, exceptionClassResourceName);
754                                 mv.visitJumpInsn(IFEQ, nextException[i]); // If not, go to ExecutionError
755                                 // If so, throw it
756                                 mv.visitVarInsn(ALOAD, argRegs+5); // e
757                                 mv.visitTypeInsn(CHECKCAST, exceptionClassResourceName);
758                                 mv.visitInsn(ATHROW);
759                                 mv.visitLabel(nextException[i]);
760                         }
761                         
762                         // ExecutionError
763                         mv.visitFrame(Opcodes.F_APPEND,2, new Object[] {"org/simantics/databoard/method/MethodInterface$ExecutionError", "java/lang/Object"}, 0, null);
764                         mv.visitTypeInsn(NEW, "java/lang/RuntimeException");
765                         mv.visitInsn(DUP);
766                         mv.visitVarInsn(ALOAD, argRegs+4);
767                         mv.visitMethodInsn(INVOKESPECIAL, "java/lang/RuntimeException", "<init>", "(Ljava/lang/Throwable;)V");
768                         mv.visitInsn(ATHROW);
769                         
770                         // InteruptedException
771                         mv.visitLabel(l3);
772                         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"});
773                         mv.visitVarInsn(ASTORE, argRegs+4);
774                         Label l10 = new Label();
775                         mv.visitLabel(l10);
776                         mv.visitTypeInsn(NEW, "java/lang/RuntimeException");
777                         mv.visitInsn(DUP);
778                         mv.visitVarInsn(ALOAD, argRegs+4);
779                         mv.visitMethodInsn(INVOKESPECIAL, "java/lang/RuntimeException", "<init>", "(Ljava/lang/Throwable;)V");
780                         mv.visitInsn(ATHROW);
781                         
782                         Label l11 = new Label();
783                         mv.visitLabel(l11);
784                         mv.visitLocalVariable("this", classTypeDescriptor, null, l4, l11, 0);
785 //                      mv.visitLocalVariable("arg1", "Ljava/lang/Integer;", null, l4, l11, 1);
786                         register = 1;
787                         for (int i=0; i<params.length; i++) {
788                                 Class<?> clazz = params[i];
789                                 mv.visitLocalVariable("arg"+(i+1), toTypeDescriptor(clazz), null, l4, l11, register);
790                                 register++;
791                                 if (clazz==long.class || clazz==double.class) argRegs++;
792                         }
793                         mv.visitLocalVariable("m", "Lorg/simantics/databoard/method/MethodInterface$Method;", null, l5, l11, argRegs+1);
794                         mv.visitLocalVariable("args", "[Ljava/lang/Object;", null, l6, l11, argRegs+2);
795                         mv.visitLocalVariable("result", "Lorg/simantics/databoard/method/MethodInterface$AsyncResult;", null, l0, l11, argRegs+3);
796                         mv.visitLocalVariable("e", "Lorg/simantics/databoard/method/MethodInterface$ExecutionError;", null, l7, l3, argRegs+4);
797                         mv.visitLocalVariable("cause", "Ljava/lang/Object;", null, l7, l3, argRegs+5);
798                         mv.visitLocalVariable("e", "Ljava/lang/InterruptedException;", null, l10, l11, argRegs+4);
799                         mv.visitMaxs(argRegs+3, argRegs+6);
800                         mv.visitEnd();
801                         methodNumber++;
802                         }
803
804                         cw.visitEnd();          
805                 }
806                 
807         }
808
809         
810         
811 }
812