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