Supporting Fn.KeepAlive
authorJaroslav Tulach <jaroslav.tulach@apidesign.org>
Mon, 22 Dec 2014 20:57:23 +0100
changeset 175503e8d4077e55
parent 1754 ff4983098f3f
child 1756 6f67550dfa9e
Supporting Fn.KeepAlive
launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/fximpl/JVMBridge.java
     1.1 --- a/launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/fximpl/JVMBridge.java	Mon Dec 22 20:33:44 2014 +0100
     1.2 +++ b/launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/fximpl/JVMBridge.java	Mon Dec 22 20:57:23 2014 +0100
     1.3 @@ -19,12 +19,15 @@
     1.4  
     1.5  import java.io.BufferedReader;
     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.Arrays;
    1.11  import java.util.Collection;
    1.12  import java.util.List;
    1.13  import java.util.TooManyListenersException;
    1.14  import java.util.concurrent.Executor;
    1.15 +import java.util.logging.Level;
    1.16  import java.util.logging.Logger;
    1.17  import javafx.application.Platform;
    1.18  import javafx.beans.value.ChangeListener;
    1.19 @@ -78,8 +81,8 @@
    1.20          return Class.forName(name, true, cl);
    1.21      }
    1.22      
    1.23 -    private final class WebPresenter 
    1.24 -    implements FindResources, Fn.Presenter, Fn.ToJavaScript, Fn.FromJavaScript, Executor {
    1.25 +    private final class WebPresenter implements Fn.Presenter,
    1.26 +    FindResources, Fn.ToJavaScript, Fn.FromJavaScript, Executor, Fn.KeepAlive {
    1.27          @Override
    1.28          public void findResources(String name, Collection<? super URL> results, boolean oneIsEnough) {
    1.29              if (ldrs != null) for (ClassLoader l : ldrs) {
    1.30 @@ -92,14 +95,20 @@
    1.31  
    1.32          @Override
    1.33          public Fn defineFn(String code, String... names) {
    1.34 -            return defineJSFn(code, names);
    1.35 +            return defineJSFn(code, names, null);
    1.36          }
    1.37 -        private JSFn defineJSFn(String code, String... names) {
    1.38 +        
    1.39 +        @Override
    1.40 +        public Fn defineFn(String code, String[] names, boolean[] keepAlive) {
    1.41 +            return defineJSFn(code, names, keepAlive);
    1.42 +        }
    1.43 +        
    1.44 +        private JSFn defineJSFn(String code, String[] names, boolean[] keepAlive) {
    1.45              StringBuilder sb = new StringBuilder();
    1.46              sb.append("(function() {");
    1.47              sb.append("  return function(");
    1.48              String sep = "";
    1.49 -            for (String n : names) {
    1.50 +            if (names != null) for (String n : names) {
    1.51                  sb.append(sep).append(n);
    1.52                  sep = ",";
    1.53              }
    1.54 @@ -109,7 +118,7 @@
    1.55              sb.append("})()");
    1.56              
    1.57              JSObject x = (JSObject) engine.executeScript(sb.toString());
    1.58 -            return new JSFn(this, x);
    1.59 +            return new JSFn(this, x, keepAlive);
    1.60          }
    1.61  
    1.62          @Override
    1.63 @@ -133,6 +142,9 @@
    1.64  
    1.65          @Override
    1.66          public Object toJava(Object js) {
    1.67 +            if (js instanceof Weak) {
    1.68 +                js = ((Weak)js).get();
    1.69 +            }
    1.70              return checkArray(js);
    1.71          }
    1.72  
    1.73 @@ -172,7 +184,7 @@
    1.74                          + "  k.array= function() {"
    1.75                          + "    return Array.prototype.slice.call(arguments);"
    1.76                          + "  };"
    1.77 -                        + "  return k;"
    1.78 +                        + "  return k;", null, null
    1.79                      ).invokeImpl(null, false);
    1.80                  } catch (Exception ex) {
    1.81                      throw new IllegalStateException(ex);
    1.82 @@ -206,7 +218,7 @@
    1.83                          + "      return l;"
    1.84                          + "    }"
    1.85                          + "  };"
    1.86 -                        + "  return k;"
    1.87 +                        + "  return k;", null, null
    1.88                      ).invokeImpl(null, false);
    1.89                  } catch (Exception ex) {
    1.90                      throw new IllegalStateException(ex);
    1.91 @@ -214,15 +226,17 @@
    1.92              }
    1.93              return arraySize;
    1.94          }
    1.95 -        
    1.96 +
    1.97      }
    1.98      
    1.99      private static final class JSFn extends Fn {
   1.100          private final JSObject fn;
   1.101 +        private final boolean[] keepAlive;
   1.102  
   1.103 -        private JSFn(WebPresenter cl, JSObject fn) {
   1.104 +        private JSFn(WebPresenter cl, JSObject fn, boolean[] keepAlive) {
   1.105              super(cl);
   1.106              this.fn = fn;
   1.107 +            this.keepAlive = keepAlive;
   1.108          }
   1.109  
   1.110          @Override
   1.111 @@ -235,14 +249,25 @@
   1.112                  List<Object> all = new ArrayList<Object>(args.length + 1);
   1.113                  all.add(thiz == null ? fn : thiz);
   1.114                  for (int i = 0; i < args.length; i++) {
   1.115 -                    if (arrayChecks && args[i] instanceof Object[]) {
   1.116 -                        Object[] arr = (Object[]) args[i];
   1.117 -                        Object conv = ((WebPresenter) presenter()).convertArrays(arr);
   1.118 -                        args[i] = conv;
   1.119 +                    Object conv = args[i];
   1.120 +                    if (arrayChecks) {
   1.121 +                        if (args[i] instanceof Object[]) {
   1.122 +                            Object[] arr = (Object[]) args[i];
   1.123 +                            conv = ((WebPresenter) presenter()).convertArrays(arr);
   1.124 +                        }
   1.125 +                        if (conv != null && keepAlive != null
   1.126 +                            && !keepAlive[i] && !isJSReady(conv)
   1.127 +                            && !conv.getClass().getSimpleName().equals("$JsCallbacks$") // NOI18N
   1.128 +                            ) {
   1.129 +                            conv = new Weak(conv);
   1.130 +                        }
   1.131                      }
   1.132 -                    all.add(args[i]);
   1.133 +                    all.add(conv);
   1.134                  }
   1.135                  Object ret = fn.call("call", all.toArray()); // NOI18N
   1.136 +                if (ret instanceof Weak) {
   1.137 +                    ret = ((Weak) ret).get();
   1.138 +                }
   1.139                  if (ret == fn) {
   1.140                      return null;
   1.141                  }
   1.142 @@ -259,4 +284,30 @@
   1.143              }
   1.144          }
   1.145      }
   1.146 +
   1.147 +    private static boolean isJSReady(Object obj) {
   1.148 +        if (obj == null) {
   1.149 +            return true;
   1.150 +        }
   1.151 +        if (obj instanceof String) {
   1.152 +            return true;
   1.153 +        }
   1.154 +        if (obj instanceof Number) {
   1.155 +            return true;
   1.156 +        }
   1.157 +        if (obj instanceof JSObject) {
   1.158 +            return true;
   1.159 +        }
   1.160 +        if (obj instanceof Character) {
   1.161 +            return true;
   1.162 +        }
   1.163 +        return false;
   1.164 +    }
   1.165 +
   1.166 +    private static final class Weak extends WeakReference<Object> {
   1.167 +        public Weak(Object referent) {
   1.168 +            super(referent);
   1.169 +            assert !(referent instanceof Weak);
   1.170 +        }
   1.171 +    } // end of Weak
   1.172  }