boot/src/main/java/org/apidesign/html/boot/impl/FnUtils.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Wed, 26 Jun 2013 08:43:32 +0200
branchclassloader
changeset 163 2652760705d6
parent 161 ea5ca9cc685d
child 171 54ac82353158
permissions -rw-r--r--
Loading of external JavaScript files simplified
     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.io.InputStream;
    24 import java.io.InputStreamReader;
    25 import java.io.Reader;
    26 import java.lang.reflect.Method;
    27 import java.net.URL;
    28 import java.util.ArrayList;
    29 import java.util.Collections;
    30 import java.util.Enumeration;
    31 import java.util.List;
    32 import org.apidesign.html.boot.spi.Fn;
    33 import org.objectweb.asm.Type;
    34 
    35 /**
    36  *
    37  * @author Jaroslav Tulach <jtulach@netbeans.org>
    38  */
    39 public final class FnUtils {
    40     private FnUtils() {
    41     }
    42 
    43     public static Fn define(Class<?> caller, String code, String... names) {
    44         JsClassLoader cl = (JsClassLoader)caller.getClassLoader();
    45         return cl.defineFn(code, names);
    46     }
    47 
    48     public static ClassLoader newLoader(final FindResources f, final Fn.Presenter d, ClassLoader parent) {
    49         return new JsClassLoader(parent) {
    50             @Override
    51             protected URL findResource(String name) {
    52                 List<URL> l = res(name, true);
    53                 return l.isEmpty() ? null : l.get(0);
    54             }
    55             
    56             @Override
    57             protected Enumeration<URL> findResources(String name) {
    58                 return Collections.enumeration(res(name, false));
    59             }
    60             
    61             private List<URL> res(String name, boolean oneIsEnough) {
    62                 List<URL> l = new ArrayList<URL>();
    63                 f.findResources(name, l, oneIsEnough);
    64                 return l;
    65             }
    66             
    67             @Override
    68             protected Fn defineFn(String code, String... names) {
    69                 return d.defineFn(code, names);
    70             }
    71 
    72             @Override
    73             protected void loadScript(Reader code) throws Exception {
    74                 d.loadScript(code);
    75             }
    76         };
    77     }
    78 
    79     static String callback(String body, ClassLoader loader) {
    80         try {
    81             return callbackImpl(body, loader);
    82         } catch (ClassNotFoundException ex) {
    83             throw new IllegalStateException("Can't parse " + body, ex);
    84         } catch (NoSuchMethodException ex) {
    85             throw new IllegalStateException("Can't parse " + body, ex);
    86         }
    87     }
    88     
    89     private static String callbackImpl(String body, ClassLoader loader)
    90     throws ClassNotFoundException, NoSuchMethodException {
    91         StringBuilder sb = new StringBuilder();
    92         int pos = 0;
    93         for (;;) {
    94             int next = body.indexOf(".@", pos);
    95             if (next == -1) {
    96                 sb.append(body.substring(pos));
    97                 return sb.toString();
    98             }
    99             sb.append(body.substring(pos, next));
   100             
   101             int sigBeg = body.indexOf('(', next);
   102             int sigEnd = body.indexOf(')', sigBeg);
   103             
   104             int colon4 = body.indexOf("::", next);
   105             
   106             if (sigBeg == -1 || sigEnd == -1 || colon4 == -1) {
   107                 throw new IllegalStateException("Malformed body " + body);
   108             }
   109             
   110             String fqn = body.substring(next + 2, colon4);
   111             String method = body.substring(colon4 + 2, sigBeg);
   112             String params = body.substring(sigBeg, sigEnd + 1);
   113             
   114             Class<?> clazz = Class.forName(fqn, false, loader);
   115             final Type[] argTps = Type.getArgumentTypes(params);
   116             Class<?>[] argCls = new Class<?>[argTps.length];
   117             for (int i = 0; i < argCls.length; i++) {
   118                 argCls[i] = toClass(argTps[i], loader);
   119             }
   120             Method m = clazz.getMethod(method, argCls);
   121             
   122             sb.append("['").append(m.getName()).append("(");
   123             String sep = "";
   124             for (Class<?> pt : m.getParameterTypes()) {
   125                 sb.append(sep).append(pt.getName());
   126                 sep = ",";
   127             }
   128             sb.append(")']");
   129             
   130             pos = sigEnd + 1;
   131         }
   132     }
   133 
   134     private static Class<?> toClass(final Type t, ClassLoader loader) throws ClassNotFoundException {
   135         if (t == Type.INT_TYPE) {
   136             return Integer.TYPE;
   137         } else if (t == Type.VOID_TYPE) {
   138             return Void.TYPE;
   139         } else if (t == Type.BOOLEAN_TYPE) {
   140             return Boolean.TYPE;
   141         } else if (t == Type.BYTE_TYPE) {
   142             return Byte.TYPE;
   143         } else if (t == Type.CHAR_TYPE) {
   144             return Character.TYPE;
   145         } else if (t == Type.SHORT_TYPE) {
   146             return Short.TYPE;
   147         } else if (t == Type.DOUBLE_TYPE) {
   148             return Double.TYPE;
   149         } else if (t == Type.FLOAT_TYPE) {
   150             return Float.TYPE;
   151         } else if (t == Type.LONG_TYPE) {
   152             return Long.TYPE;
   153         }
   154         return Class.forName(t.getClassName(), false, loader);
   155     }
   156 
   157     static void loadScript(JsClassLoader jcl, String resource) {
   158         final InputStream script = jcl.getResourceAsStream(resource);
   159         if (script == null) {
   160             throw new NullPointerException("Can't find " + resource);
   161         }
   162         try {
   163             Reader isr = null;
   164             try {
   165                 isr = new InputStreamReader(script, "UTF-8");
   166                 jcl.loadScript(isr);
   167             } finally {
   168                 if (isr != null) {
   169                     isr.close();
   170                 }
   171             }
   172         } catch (Exception ex) {
   173             throw new IllegalStateException("Can't execute " + resource, ex);
   174         } 
   175     }
   176 }