boot-script/src/main/java/net/java/html/boot/script/ScriptPresenter.java
branchweakfx
changeset 915 15af7ebf1d0e
parent 838 bdc3d696dd4a
child 1040 6429e051b1de
     1.1 --- a/boot-script/src/main/java/net/java/html/boot/script/ScriptPresenter.java	Tue Aug 26 18:13:30 2014 +0200
     1.2 +++ b/boot-script/src/main/java/net/java/html/boot/script/ScriptPresenter.java	Thu Dec 18 03:25:54 2014 +0100
     1.3 @@ -45,6 +45,7 @@
     1.4  import java.io.Closeable;
     1.5  import java.io.IOException;
     1.6  import java.io.Reader;
     1.7 +import java.lang.ref.WeakReference;
     1.8  import java.net.URL;
     1.9  import java.util.ArrayList;
    1.10  import java.util.List;
    1.11 @@ -70,8 +71,8 @@
    1.12   *
    1.13   * @author Jaroslav Tulach
    1.14   */
    1.15 -final class ScriptPresenter 
    1.16 -implements Presenter, Fn.FromJavaScript, Fn.ToJavaScript, Executor {
    1.17 +final class ScriptPresenter implements Fn.KeepAlive,
    1.18 +Presenter, Fn.FromJavaScript, Fn.ToJavaScript, Executor {
    1.19      private static final Logger LOG = Logger.getLogger(ScriptPresenter.class.getName());
    1.20      private final ScriptEngine eng;
    1.21      private final Executor exc;
    1.22 @@ -90,9 +91,14 @@
    1.23  
    1.24      @Override
    1.25      public Fn defineFn(String code, String... names) {
    1.26 -        return defineImpl(code, names);
    1.27 +        return defineImpl(code, names, null);
    1.28      }
    1.29 -    private FnImpl defineImpl(String code, String... names) {
    1.30 +
    1.31 +    @Override
    1.32 +    public Fn defineFn(String code, String[] names, boolean[] keepAlive) {
    1.33 +        return defineImpl(code, names, keepAlive);
    1.34 +    }    
    1.35 +    private FnImpl defineImpl(String code, String[] names, boolean[] keepAlive) {
    1.36          StringBuilder sb = new StringBuilder();
    1.37          sb.append("(function() {");
    1.38          sb.append("  return function(");
    1.39 @@ -112,7 +118,7 @@
    1.40          } catch (ScriptException ex) {
    1.41              throw new IllegalStateException(ex);
    1.42          }
    1.43 -        return new FnImpl(this, fn);
    1.44 +        return new FnImpl(this, fn, keepAlive);
    1.45      }
    1.46  
    1.47      @Override
    1.48 @@ -150,7 +156,7 @@
    1.49      private FnImpl wrapArrFn() {
    1.50          if (wrapArrImpl == null) {
    1.51              try {
    1.52 -                wrapArrImpl = defineImpl("return Array.prototype.slice.call(arguments);");
    1.53 +                wrapArrImpl = defineImpl("return Array.prototype.slice.call(arguments);", null, null);
    1.54              } catch (Exception ex) {
    1.55                  throw new IllegalStateException(ex);
    1.56              }
    1.57 @@ -181,7 +187,7 @@
    1.58                      + "  var l = arr.length;\n"
    1.59                      + "  for (var i = 0; i < l; i++) to[i] = arr[i];\n"
    1.60                      + "  return l;\n"
    1.61 -                    + "}", "arr", "to"
    1.62 +                    + "}", new String[] { "arr", "to" }, null
    1.63                  );
    1.64              } catch (Exception ex) {
    1.65                  throw new IllegalStateException(ex);
    1.66 @@ -192,6 +198,9 @@
    1.67  
    1.68      @Override
    1.69      public Object toJava(Object jsArray) {
    1.70 +        if (jsArray instanceof Weak) {
    1.71 +            jsArray = ((Weak)jsArray).get();
    1.72 +        }
    1.73          try {
    1.74              return checkArray(jsArray);
    1.75          } catch (Exception ex) {
    1.76 @@ -239,10 +248,12 @@
    1.77      private class FnImpl extends Fn {
    1.78  
    1.79          private final Object fn;
    1.80 +        private final boolean[] keepAlive;
    1.81  
    1.82 -        public FnImpl(Presenter presenter, Object fn) {
    1.83 +        public FnImpl(Presenter presenter, Object fn, boolean[] keepAlive) {
    1.84              super(presenter);
    1.85              this.fn = fn;
    1.86 +            this.keepAlive = keepAlive;
    1.87          }
    1.88  
    1.89          @Override
    1.90 @@ -254,19 +265,28 @@
    1.91                  List<Object> all = new ArrayList<>(args.length + 1);
    1.92                  all.add(thiz == null ? fn : thiz);
    1.93                  for (int i = 0; i < args.length; i++) {
    1.94 +                    Object conv = args[i];
    1.95                      if (arrayChecks) {
    1.96                          if (args[i] instanceof Object[]) {
    1.97                              Object[] arr = (Object[]) args[i];
    1.98 -                            Object conv = ((ScriptPresenter)presenter()).convertArrays(arr);
    1.99 -                            args[i] = conv;
   1.100 +                            conv = ((ScriptPresenter) presenter()).convertArrays(arr);
   1.101                          }
   1.102 -                        if (args[i] instanceof Character) {
   1.103 -                            args[i] = (int)((Character)args[i]);
   1.104 +                        if (conv != null && keepAlive != null
   1.105 +                            && !keepAlive[i] && !isJSReady(conv)
   1.106 +                            && !conv.getClass().getSimpleName().equals("$JsCallbacks$") // NOI18N
   1.107 +                            ) {
   1.108 +                            conv = new Weak(conv);
   1.109 +                        }
   1.110 +                        if (conv instanceof Character) {
   1.111 +                            conv = (int)(Character)conv;
   1.112                          }
   1.113                      }
   1.114 -                    all.add(args[i]);
   1.115 +                    all.add(conv);
   1.116                  }
   1.117                  Object ret = ((Invocable)eng).invokeMethod(fn, "call", all.toArray()); // NOI18N
   1.118 +                if (ret instanceof Weak) {
   1.119 +                    ret = ((Weak)ret).get();
   1.120 +                }
   1.121                  if (ret == fn) {
   1.122                      return null;
   1.123                  }
   1.124 @@ -277,4 +297,31 @@
   1.125              }
   1.126      }
   1.127      
   1.128 +    private static boolean isJSReady(Object obj) {
   1.129 +        if (obj == null) {
   1.130 +            return true;
   1.131 +        }
   1.132 +        if (obj instanceof String) {
   1.133 +            return true;
   1.134 +        }
   1.135 +        if (obj instanceof Number) {
   1.136 +            return true;
   1.137 +        }
   1.138 +        final String cn = obj.getClass().getName();
   1.139 +        if (cn.startsWith("jdk.nashorn") || ( // NOI18N
   1.140 +            cn.contains(".mozilla.") && cn.contains(".Native") // NOI18N
   1.141 +        )) {
   1.142 +            return true;
   1.143 +        }
   1.144 +        if (obj instanceof Character) {
   1.145 +            return true;
   1.146 +        }
   1.147 +        return false;
   1.148 +    }    
   1.149 +    
   1.150 +    private static final class Weak extends WeakReference<Object> {
   1.151 +        public Weak(Object referent) {
   1.152 +            super(referent);
   1.153 +        }
   1.154 +    }
   1.155  }