boot/src/main/java/org/apidesign/html/boot/impl/FnUtils.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Tue, 25 Jun 2013 21:09:48 +0200
branchclassloader
changeset 161 ea5ca9cc685d
parent 160 b5a06e2b3b92
child 163 2652760705d6
permissions -rw-r--r--
Can call method with two integer arguments from JavaScript
     1 /**
     2  * HTML via Java(tm) Language Bindings
     3  * Copyright (C) 2013 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
     4  *
     5  * This program is free software: you can redistribute it and/or modify
     6  * it under the terms of the GNU General Public License as published by
     7  * the Free Software Foundation, version 2 of the License.
     8  *
     9  * This program is distributed in the hope that it will be useful,
    10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12  * GNU General Public License for more details. apidesign.org
    13  * designates this particular file as subject to the
    14  * "Classpath" exception as provided by apidesign.org
    15  * in the License file that accompanied this code.
    16  *
    17  * You should have received a copy of the GNU General Public License
    18  * along with this program. Look for COPYING file in the top folder.
    19  * If not, see http://wiki.apidesign.org/wiki/GPLwithClassPathException
    20  */
    21 package org.apidesign.html.boot.impl;
    22 
    23 import java.lang.reflect.Method;
    24 import java.net.URL;
    25 import java.util.ArrayList;
    26 import java.util.Collections;
    27 import java.util.Enumeration;
    28 import java.util.List;
    29 import org.apidesign.html.boot.spi.Fn;
    30 import org.objectweb.asm.Type;
    31 
    32 /**
    33  *
    34  * @author Jaroslav Tulach <jtulach@netbeans.org>
    35  */
    36 public final class FnUtils {
    37     private FnUtils() {
    38     }
    39 
    40     public static Fn define(Class<?> caller, String code, String... names) {
    41         JsClassLoader cl = (JsClassLoader)caller.getClassLoader();
    42         return cl.defineFn(code, names);
    43     }
    44 
    45     public static ClassLoader newLoader(final FindResources f, final Fn.Presenter d, ClassLoader parent) {
    46         return new JsClassLoader(parent) {
    47             @Override
    48             protected URL findResource(String name) {
    49                 List<URL> l = res(name, true);
    50                 return l.isEmpty() ? null : l.get(0);
    51             }
    52             
    53             @Override
    54             protected Enumeration<URL> findResources(String name) {
    55                 return Collections.enumeration(res(name, false));
    56             }
    57             
    58             private List<URL> res(String name, boolean oneIsEnough) {
    59                 List<URL> l = new ArrayList<URL>();
    60                 f.findResources(name, l, oneIsEnough);
    61                 return l;
    62             }
    63             
    64             @Override
    65             protected Fn defineFn(String code, String... names) {
    66                 return d.defineFn(code, names);
    67             }
    68         };
    69     }
    70 
    71     static String callback(String body, ClassLoader loader) {
    72         try {
    73             return callbackImpl(body, loader);
    74         } catch (ClassNotFoundException ex) {
    75             throw new IllegalStateException("Can't parse " + body, ex);
    76         } catch (NoSuchMethodException ex) {
    77             throw new IllegalStateException("Can't parse " + body, ex);
    78         }
    79     }
    80     
    81     private static String callbackImpl(String body, ClassLoader loader)
    82     throws ClassNotFoundException, NoSuchMethodException {
    83         StringBuilder sb = new StringBuilder();
    84         int pos = 0;
    85         for (;;) {
    86             int next = body.indexOf(".@", pos);
    87             if (next == -1) {
    88                 sb.append(body.substring(pos));
    89                 return sb.toString();
    90             }
    91             sb.append(body.substring(pos, next));
    92             
    93             int sigBeg = body.indexOf('(', next);
    94             int sigEnd = body.indexOf(')', sigBeg);
    95             
    96             int colon4 = body.indexOf("::", next);
    97             
    98             if (sigBeg == -1 || sigEnd == -1 || colon4 == -1) {
    99                 throw new IllegalStateException("Malformed body " + body);
   100             }
   101             
   102             String fqn = body.substring(next + 2, colon4);
   103             String method = body.substring(colon4 + 2, sigBeg);
   104             String params = body.substring(sigBeg, sigEnd + 1);
   105             
   106             Class<?> clazz = Class.forName(fqn, false, loader);
   107             final Type[] argTps = Type.getArgumentTypes(params);
   108             Class<?>[] argCls = new Class<?>[argTps.length];
   109             for (int i = 0; i < argCls.length; i++) {
   110                 argCls[i] = toClass(argTps[i], loader);
   111             }
   112             Method m = clazz.getMethod(method, argCls);
   113             
   114             sb.append("['").append(m.getName()).append("(");
   115             String sep = "";
   116             for (Class<?> pt : m.getParameterTypes()) {
   117                 sb.append(sep).append(pt.getName());
   118                 sep = ",";
   119             }
   120             sb.append(")']");
   121             
   122             pos = sigEnd + 1;
   123         }
   124     }
   125 
   126     private static Class<?> toClass(final Type t, ClassLoader loader) throws ClassNotFoundException {
   127         if (t == Type.INT_TYPE) {
   128             return Integer.TYPE;
   129         } else if (t == Type.VOID_TYPE) {
   130             return Void.TYPE;
   131         } else if (t == Type.BOOLEAN_TYPE) {
   132             return Boolean.TYPE;
   133         } else if (t == Type.BYTE_TYPE) {
   134             return Byte.TYPE;
   135         } else if (t == Type.CHAR_TYPE) {
   136             return Character.TYPE;
   137         } else if (t == Type.SHORT_TYPE) {
   138             return Short.TYPE;
   139         } else if (t == Type.DOUBLE_TYPE) {
   140             return Double.TYPE;
   141         } else if (t == Type.FLOAT_TYPE) {
   142             return Float.TYPE;
   143         } else if (t == Type.LONG_TYPE) {
   144             return Long.TYPE;
   145         }
   146         return Class.forName(t.getClassName(), false, loader);
   147     }
   148     
   149 }