Yet another improvement to BrwsrCtx.execute
authorJaroslav Tulach <jaroslav.tulach@netbeans.org>
Tue, 04 Mar 2014 21:57:50 +0100
changeset 576fef447226358
parent 573 08ef49505ba9
parent 575 3e6c5f24b12d
child 577 f23fdccd1827
child 579 f6f6c859c3f1
Yet another improvement to BrwsrCtx.execute
     1.1 --- a/boot-fx/src/main/java/org/netbeans/html/boot/fx/AbstractFXPresenter.java	Tue Mar 04 12:29:51 2014 +0100
     1.2 +++ b/boot-fx/src/main/java/org/netbeans/html/boot/fx/AbstractFXPresenter.java	Tue Mar 04 21:57:50 2014 +0100
     1.3 @@ -43,6 +43,8 @@
     1.4  package org.netbeans.html.boot.fx;
     1.5  
     1.6  import java.io.BufferedReader;
     1.7 +import java.io.Closeable;
     1.8 +import java.io.IOException;
     1.9  import java.io.Reader;
    1.10  import java.net.URL;
    1.11  import java.util.ArrayList;
    1.12 @@ -234,11 +236,35 @@
    1.13          }
    1.14      }
    1.15      
    1.16 -    @Override public void execute(Runnable r) {
    1.17 +    @Override public void execute(final Runnable r) {
    1.18          if (Platform.isFxApplicationThread()) {
    1.19 -            r.run();
    1.20 +            Closeable c = Fn.activate(this);
    1.21 +            try {
    1.22 +                r.run();
    1.23 +            } finally {
    1.24 +                try {
    1.25 +                    c.close();
    1.26 +                } catch (IOException ex) {
    1.27 +                    // ignore
    1.28 +                }
    1.29 +            }                
    1.30          } else {
    1.31 -            Platform.runLater(r);
    1.32 +            class Wrap implements Runnable {
    1.33 +                @Override
    1.34 +                public void run() {
    1.35 +                    Closeable c = Fn.activate(AbstractFXPresenter.this);
    1.36 +                    try {
    1.37 +                        r.run();
    1.38 +                    } finally {
    1.39 +                        try {
    1.40 +                            c.close();
    1.41 +                        } catch (IOException ex) {
    1.42 +                            // ignore
    1.43 +                        }
    1.44 +                    }                
    1.45 +                }
    1.46 +            }
    1.47 +            Platform.runLater(new Wrap());
    1.48          }
    1.49      }
    1.50  
     2.1 --- a/boot/src/main/java/net/java/html/boot/BrowserBuilder.java	Tue Mar 04 12:29:51 2014 +0100
     2.2 +++ b/boot/src/main/java/net/java/html/boot/BrowserBuilder.java	Tue Mar 04 21:57:50 2014 +0100
     2.3 @@ -51,11 +51,13 @@
     2.4  import java.util.Collection;
     2.5  import java.util.Enumeration;
     2.6  import java.util.ServiceLoader;
     2.7 +import java.util.concurrent.Executor;
     2.8  import java.util.logging.Level;
     2.9  import java.util.logging.Logger;
    2.10  import net.java.html.BrwsrCtx;
    2.11  import net.java.html.js.JavaScriptBody;
    2.12  import org.apidesign.html.boot.spi.Fn;
    2.13 +import org.apidesign.html.context.spi.Contexts;
    2.14  import org.netbeans.html.boot.impl.FindResources;
    2.15  import org.netbeans.html.boot.impl.FnContext;
    2.16  import org.netbeans.html.boot.impl.FnUtils;
    2.17 @@ -246,7 +248,15 @@
    2.18                          if (browserClass != null) {
    2.19                              browserClass[0] = newClazz;
    2.20                          }
    2.21 -                        BrwsrCtx c = BrwsrCtx.findDefault(newClazz);
    2.22 +                        Contexts.Builder cb = Contexts.newBuilder();
    2.23 +                        if (!Contexts.fillInByProviders(newClazz, cb)) {
    2.24 +                            LOG.log(Level.WARNING, "Using empty technology for {0}", newClazz);
    2.25 +                        }
    2.26 +                        if (currentP instanceof Executor) {
    2.27 +                            cb.register(Executor.class, (Executor)currentP, 1000);
    2.28 +                        }
    2.29 +                        cb.register(Fn.Presenter.class, currentP, 1000);
    2.30 +                        BrwsrCtx c = cb.build();
    2.31                          c.execute(this);
    2.32                          return;
    2.33                      }
     3.1 --- a/context/src/main/java/net/java/html/BrwsrCtx.java	Tue Mar 04 12:29:51 2014 +0100
     3.2 +++ b/context/src/main/java/net/java/html/BrwsrCtx.java	Tue Mar 04 21:57:50 2014 +0100
     3.3 @@ -42,7 +42,7 @@
     3.4   */
     3.5  package net.java.html;
     3.6  
     3.7 -import java.util.ServiceLoader;
     3.8 +import java.util.concurrent.Executor;
     3.9  import java.util.logging.Logger;
    3.10  import org.netbeans.html.context.impl.CtxAccssr;
    3.11  import org.netbeans.html.context.impl.CtxImpl;
    3.12 @@ -88,7 +88,8 @@
    3.13      
    3.14      /** Seeks for the default context that is associated with the requesting
    3.15       * class. If no suitable context is found, a warning message is
    3.16 -     * printed and {@link #EMPTY} context is returned.
    3.17 +     * printed and {@link #EMPTY} context is returned. One can enter 
    3.18 +     * a context by calling {@link #execute(java.lang.Runnable)}.
    3.19       * 
    3.20       * @param requestor the class that makes the request
    3.21       * @return appropriate context for the request
    3.22 @@ -100,38 +101,7 @@
    3.23          }
    3.24          
    3.25          org.apidesign.html.context.spi.Contexts.Builder cb = Contexts.newBuilder();
    3.26 -        boolean found = false;
    3.27 -        
    3.28 -        ClassLoader l;
    3.29 -        try {
    3.30 -            l = requestor.getClassLoader();
    3.31 -        } catch (SecurityException ex) {
    3.32 -            l = null;
    3.33 -        }
    3.34 -        
    3.35 -        for (org.apidesign.html.context.spi.Contexts.Provider cp : ServiceLoader.load(
    3.36 -            org.apidesign.html.context.spi.Contexts.Provider.class, l
    3.37 -        )) {
    3.38 -            cp.fillContext(cb, requestor);
    3.39 -            found = true;
    3.40 -        }
    3.41 -        try {
    3.42 -            for (org.apidesign.html.context.spi.Contexts.Provider cp : ServiceLoader.load(org.apidesign.html.context.spi.Contexts.Provider.class, org.apidesign.html.context.spi.Contexts.Provider.class.getClassLoader())) {
    3.43 -                cp.fillContext(cb, requestor);
    3.44 -                found = true;
    3.45 -            }
    3.46 -        } catch (SecurityException ex) {
    3.47 -            if (!found) {
    3.48 -                throw ex;
    3.49 -            }
    3.50 -            // if we have some data from regular provides, go on
    3.51 -        }
    3.52 -        if (!found) {
    3.53 -            for (org.apidesign.html.context.spi.Contexts.Provider cp : ServiceLoader.load(org.apidesign.html.context.spi.Contexts.Provider.class)) {
    3.54 -                cp.fillContext(cb, requestor);
    3.55 -                found = true;
    3.56 -            }
    3.57 -        }
    3.58 +        boolean found = Contexts.fillInByProviders(requestor, cb);
    3.59          if (!found) {
    3.60              LOG.warning("No browser context found. Returning empty technology!");
    3.61              return EMPTY;
    3.62 @@ -140,21 +110,37 @@
    3.63      }
    3.64  
    3.65      /** Runs provided code in the context of this {@link BrwsrCtx}.
    3.66 -     * While the <code>exec</code> is running, the {@link #findDefault(java.lang.Class)}
    3.67 -     * method returns <code>this</code>. The provided code is executed
    3.68 -     * synchronously on the same thread; 
    3.69 -     * the call returns when <code>exec.run()</code> is over.
    3.70 +     * If there is an {@link Executor} {@link Contexts#find(net.java.html.BrwsrCtx, java.lang.Class)  registered in the context}
    3.71 +     * it is used to perform the given code. While the code <code>exec</code>
    3.72 +     * is running the value of {@link #findDefault(java.lang.Class)} returns
    3.73 +     * <code>this</code>. If the executor supports a single thread execution
    3.74 +     * policy, it may execute the runnable later (in such case this method
    3.75 +     * returns immediately). If the call to this method is done on the right
    3.76 +     * thread, the runnable should be executed synchronously.
    3.77       * 
    3.78       * @param exec the code to execute
    3.79       * @since 0.7.6
    3.80       */
    3.81 -    public final void execute(Runnable exec) {
    3.82 -        BrwsrCtx prev = CURRENT.get();
    3.83 -        try {
    3.84 -            CURRENT.set(this);
    3.85 -            exec.run();
    3.86 -        } finally {
    3.87 -            CURRENT.set(prev);
    3.88 +    public final void execute(final Runnable exec) {
    3.89 +        class Wrap implements Runnable {
    3.90 +            @Override
    3.91 +            public void run() {
    3.92 +                BrwsrCtx prev = CURRENT.get();
    3.93 +                try {
    3.94 +                    CURRENT.set(BrwsrCtx.this);
    3.95 +                    exec.run();
    3.96 +                } finally {
    3.97 +                    CURRENT.set(prev);
    3.98 +                }
    3.99 +            }
   3.100 +        }
   3.101 +        Wrap w = new Wrap();
   3.102 +        Executor runIn = Contexts.find(this, Executor.class);
   3.103 +        if (runIn == null) {
   3.104 +            w.run();
   3.105 +        } else {
   3.106 +            runIn.execute(w);
   3.107          }
   3.108      }
   3.109  }
   3.110 +
     4.1 --- a/context/src/main/java/org/apidesign/html/context/spi/Contexts.java	Tue Mar 04 12:29:51 2014 +0100
     4.2 +++ b/context/src/main/java/org/apidesign/html/context/spi/Contexts.java	Tue Mar 04 21:57:50 2014 +0100
     4.3 @@ -42,6 +42,7 @@
     4.4   */
     4.5  package org.apidesign.html.context.spi;
     4.6  
     4.7 +import java.util.ServiceLoader;
     4.8  import net.java.html.BrwsrCtx;
     4.9  import org.netbeans.html.context.impl.CtxImpl;
    4.10  
    4.11 @@ -77,6 +78,47 @@
    4.12          return CtxImpl.find(context, technology);
    4.13      }
    4.14  
    4.15 +    /** Seeks {@link ServiceLoader} for all registered instances of
    4.16 +     * {@link Provider} and asks them to {@link Provider#fillContext(org.apidesign.html.context.spi.Contexts.Builder, java.lang.Class) fill
    4.17 +     * the builder}.
    4.18 +     * 
    4.19 +     * @param requestor the application class for which to find the context
    4.20 +     * @param cb the context builder to register technologies into
    4.21 +     * @return <code>true</code>, if some instances of the provider were
    4.22 +     *    found, <code>false</code> otherwise
    4.23 +     * @since 0.7.6
    4.24 +     */
    4.25 +    public static boolean fillInByProviders(Class<?> requestor, Contexts.Builder cb) {
    4.26 +        boolean found = false;
    4.27 +        ClassLoader l;
    4.28 +        try {
    4.29 +            l = requestor.getClassLoader();
    4.30 +        } catch (SecurityException ex) {
    4.31 +            l = null;
    4.32 +        }
    4.33 +        for (Provider cp : ServiceLoader.load(Provider.class, l)) {
    4.34 +            cp.fillContext(cb, requestor);
    4.35 +            found = true;
    4.36 +        }
    4.37 +        try {
    4.38 +            for (Provider cp : ServiceLoader.load(Provider.class, Provider.class.getClassLoader())) {
    4.39 +                cp.fillContext(cb, requestor);
    4.40 +                found = true;
    4.41 +            }
    4.42 +        } catch (SecurityException ex) {
    4.43 +            if (!found) {
    4.44 +                throw ex;
    4.45 +            }
    4.46 +        }
    4.47 +        if (!found) {
    4.48 +            for (Provider cp : ServiceLoader.load(Provider.class)) {
    4.49 +                cp.fillContext(cb, requestor);
    4.50 +                found = true;
    4.51 +            }
    4.52 +        }
    4.53 +        return found;
    4.54 +    }
    4.55 +
    4.56      /** Implementors of various HTML technologies should
    4.57       * register their implementation via {@link java.util.ServiceProvider} so
    4.58       * {@link java.util.ServiceProvider} can find them, when their JARs are included
     5.1 --- a/context/src/main/java/org/netbeans/html/context/impl/CtxImpl.java	Tue Mar 04 12:29:51 2014 +0100
     5.2 +++ b/context/src/main/java/org/netbeans/html/context/impl/CtxImpl.java	Tue Mar 04 21:57:50 2014 +0100
     5.3 @@ -46,6 +46,7 @@
     5.4  import java.util.Collections;
     5.5  import java.util.List;
     5.6  import net.java.html.BrwsrCtx;
     5.7 +import org.apidesign.html.context.spi.Contexts;
     5.8  
     5.9  /** Implementation detail. Holds list of technologies for particular
    5.10   * {@link BrwsrCtx}.
    5.11 @@ -75,8 +76,10 @@
    5.12  
    5.13      public BrwsrCtx build() {
    5.14          Collections.sort(techs);
    5.15 -        CtxImpl impl = new CtxImpl(Collections.unmodifiableList(techs));
    5.16 -        return CtxAccssr.getDefault().newContext(impl);
    5.17 +        final List<Bind<?>> arr = Collections.unmodifiableList(techs);
    5.18 +        CtxImpl impl = new CtxImpl(arr);
    5.19 +        BrwsrCtx ctx = CtxAccssr.getDefault().newContext(impl);
    5.20 +        return ctx;
    5.21      }
    5.22  
    5.23      public <Tech> void register(Class<Tech> type, Tech impl, int priority) {
     6.1 --- a/json/src/main/java/org/apidesign/html/json/spi/JSONCall.java	Tue Mar 04 12:29:51 2014 +0100
     6.2 +++ b/json/src/main/java/org/apidesign/html/json/spi/JSONCall.java	Tue Mar 04 21:57:50 2014 +0100
     6.3 @@ -45,6 +45,7 @@
     6.4  import java.io.IOException;
     6.5  import java.io.OutputStream;
     6.6  import net.java.html.BrwsrCtx;
     6.7 +import org.apidesign.html.context.spi.Contexts;
     6.8  import org.netbeans.html.json.impl.JSON;
     6.9  import org.netbeans.html.json.impl.RcvrJSON;
    6.10  
    6.11 @@ -123,7 +124,7 @@
    6.12      }
    6.13      
    6.14      private void dispatch(final RcvrJSON.MsgEvnt ev) {
    6.15 -        JSON.runInBrowser(ctx, new Runnable() {
    6.16 +        ctx.execute(new Runnable() {
    6.17              @Override
    6.18              public void run() {
    6.19                  ev.dispatch(whenDone);
     7.1 --- a/json/src/main/java/org/apidesign/html/json/spi/Proto.java	Tue Mar 04 12:29:51 2014 +0100
     7.2 +++ b/json/src/main/java/org/apidesign/html/json/spi/Proto.java	Tue Mar 04 21:57:50 2014 +0100
     7.3 @@ -154,7 +154,7 @@
     7.4       * @param run the action to execute
     7.5       */
     7.6      public void runInBrowser(Runnable run) {
     7.7 -        JSON.runInBrowser(context, run);
     7.8 +        context.execute(run);
     7.9      }
    7.10  
    7.11      /** Initializes the provided collection with a content of the <code>array</code>.
     8.1 --- a/json/src/main/java/org/apidesign/html/json/spi/Technology.java	Tue Mar 04 12:29:51 2014 +0100
     8.2 +++ b/json/src/main/java/org/apidesign/html/json/spi/Technology.java	Tue Mar 04 21:57:50 2014 +0100
     8.3 @@ -42,6 +42,7 @@
     8.4   */
     8.5  package org.apidesign.html.json.spi;
     8.6  
     8.7 +import net.java.html.BrwsrCtx;
     8.8  import net.java.html.json.Model;
     8.9  import net.java.html.json.Models;
    8.10  
    8.11 @@ -108,7 +109,9 @@
    8.12       * runSafe method.
    8.13       * 
    8.14       * @param r the runnable to execute
    8.15 +     * @deprecated Use {@link BrwsrCtx#execute(java.lang.Runnable)}
    8.16       */
    8.17 +    @Deprecated
    8.18      public void runSafe(Runnable r);
    8.19  
    8.20      /** For certain rendering technologies it may be more efficient to register
     9.1 --- a/json/src/main/java/org/netbeans/html/json/impl/JSON.java	Tue Mar 04 12:29:51 2014 +0100
     9.2 +++ b/json/src/main/java/org/netbeans/html/json/impl/JSON.java	Tue Mar 04 21:57:50 2014 +0100
     9.3 @@ -80,16 +80,6 @@
     9.4          return t == null ? EmptyTech.EMPTY : t;
     9.5      }
     9.6      
     9.7 -    public static void runInBrowser(final BrwsrCtx c, final Runnable runnable) {
     9.8 -        class Wrap implements Runnable {
     9.9 -            @Override
    9.10 -            public void run() {
    9.11 -                c.execute(runnable);
    9.12 -            }
    9.13 -        }
    9.14 -        findTechnology(c).runSafe(new Wrap());
    9.15 -    }
    9.16 -    
    9.17      public static void extract(BrwsrCtx c, Object value, String[] props, Object[] values) {
    9.18          Transfer t = findTransfer(c);
    9.19          t.extract(value, props, values);
    10.1 --- a/ko-osgi-test/src/main/java/org/netbeans/html/ko/osgi/test/KnockoutEquinoxTCKImpl.java	Tue Mar 04 12:29:51 2014 +0100
    10.2 +++ b/ko-osgi-test/src/main/java/org/netbeans/html/ko/osgi/test/KnockoutEquinoxTCKImpl.java	Tue Mar 04 21:57:50 2014 +0100
    10.3 @@ -53,6 +53,7 @@
    10.4  import java.net.URLConnection;
    10.5  import java.util.Map;
    10.6  import java.util.concurrent.Callable;
    10.7 +import java.util.concurrent.Executor;
    10.8  import java.util.concurrent.Executors;
    10.9  import net.java.html.BrwsrCtx;
   10.10  import net.java.html.boot.BrowserBuilder;
   10.11 @@ -143,7 +144,8 @@
   10.12              Object fx = cnstr.newInstance(browserContext);
   10.13              Contexts.Builder cb = Contexts.newBuilder().
   10.14                  register(Technology.class, (Technology)fx, 10).
   10.15 -                register(Transfer.class, (Transfer)fx, 10);
   10.16 +                register(Transfer.class, (Transfer)fx, 10).
   10.17 +                register(Executor.class, (Executor)browserContext, 10);
   10.18  //        if (fx.areWebSocketsSupported()) {
   10.19  //            cb.register(WSTransfer.class, fx, 10);
   10.20  //        }
    11.1 --- a/ko-ws-tyrus/src/test/java/org/netbeans/html/wstyrus/TyrusKnockoutTest.java	Tue Mar 04 12:29:51 2014 +0100
    11.2 +++ b/ko-ws-tyrus/src/test/java/org/netbeans/html/wstyrus/TyrusKnockoutTest.java	Tue Mar 04 21:57:50 2014 +0100
    11.3 @@ -54,6 +54,7 @@
    11.4  import java.util.ArrayList;
    11.5  import java.util.List;
    11.6  import java.util.Map;
    11.7 +import java.util.concurrent.Executor;
    11.8  import java.util.concurrent.Executors;
    11.9  import net.java.html.BrwsrCtx;
   11.10  import net.java.html.boot.BrowserBuilder;
   11.11 @@ -154,7 +155,10 @@
   11.12          Contexts.Builder cb = Contexts.newBuilder().
   11.13              register(Technology.class, ko.knockout(), 10).
   11.14              register(Transfer.class, tc, 10).
   11.15 -            register(WSTransfer.class, tc, 10);
   11.16 +            register(WSTransfer.class, tc, 10).
   11.17 +            register(Executor.class, (Executor)browserContext, 10).
   11.18 +            register(Fn.Presenter.class, (Fn.Presenter)browserContext, 10);
   11.19 +                
   11.20          return cb.build();
   11.21      }
   11.22  
    12.1 --- a/ko4j/src/main/java/org/netbeans/html/ko4j/FXContext.java	Tue Mar 04 12:29:51 2014 +0100
    12.2 +++ b/ko4j/src/main/java/org/netbeans/html/ko4j/FXContext.java	Tue Mar 04 21:57:50 2014 +0100
    12.3 @@ -49,7 +49,6 @@
    12.4  import java.io.InputStreamReader;
    12.5  import java.io.Reader;
    12.6  import java.net.URL;
    12.7 -import java.util.concurrent.Executor;
    12.8  import java.util.logging.Logger;
    12.9  import net.java.html.js.JavaScriptBody;
   12.10  import org.apidesign.html.boot.spi.Fn;
   12.11 @@ -71,43 +70,14 @@
   12.12  implements Technology.BatchInit<Object>, Technology.ValueMutated<Object>,
   12.13  Transfer, WSTransfer<LoadWS> {
   12.14      static final Logger LOG = Logger.getLogger(FXContext.class.getName());
   12.15 -    private static Boolean javaScriptEnabled;
   12.16 -    private final Fn.Presenter browserContext;
   12.17 +    private Object[] jsObjects;
   12.18 +    private int jsIndex;
   12.19  
   12.20      public FXContext(Fn.Presenter browserContext) {
   12.21 -        this.browserContext = browserContext;
   12.22      }
   12.23      
   12.24 -    @JavaScriptBody(args = {}, body = "if (window) return true; else return false;")
   12.25 -    private static boolean isJavaScriptEnabledJs() {
   12.26 -        return false;
   12.27 -    }
   12.28 -    
   12.29 -    static boolean isJavaScriptEnabled() {
   12.30 -        if (javaScriptEnabled != null) {
   12.31 -            return javaScriptEnabled;
   12.32 -        }
   12.33 -        if (!(javaScriptEnabled = isJavaScriptEnabledJs())) {
   12.34 -            Closeable c = Fn.activate(new TrueFn());
   12.35 -            try {
   12.36 -                javaScriptEnabled = isJavaScriptEnabledJs();
   12.37 -            } finally {
   12.38 -                try {
   12.39 -                    c.close();
   12.40 -                } catch (IOException ex) {
   12.41 -                    // cannot happen
   12.42 -                }
   12.43 -            }
   12.44 -        }
   12.45 -        return javaScriptEnabled;
   12.46 -    }
   12.47 -
   12.48 +    @JavaScriptBody(args = {}, body = "if (window.WebSocket) return true; else return false;")
   12.49      final boolean areWebSocketsSupported() {
   12.50 -        return isWebSocket();
   12.51 -    }
   12.52 -
   12.53 -    @JavaScriptBody(args = {}, body = "if (window.WebSocket) return true; else return false;")
   12.54 -    private static boolean isWebSocket() {
   12.55          return false;
   12.56      }
   12.57  
   12.58 @@ -125,13 +95,24 @@
   12.59          for (int i = 0; i < funcNames.length; i++) {
   12.60              funcNames[i] = funcArr[i].getFunctionName();
   12.61          }
   12.62 -        Object ret = Knockout.wrapModel(model, 
   12.63 +        Object ret = getJSObject();
   12.64 +        Knockout.wrapModel(ret, model, 
   12.65              propNames, propReadOnly, propValues, propArr,
   12.66              funcNames, funcArr
   12.67          );
   12.68          return ret;
   12.69      }
   12.70      
   12.71 +    private Object getJSObject() {
   12.72 +        int len = 64;
   12.73 +        if (jsObjects != null && jsIndex < (len = jsObjects.length)) {
   12.74 +            return jsObjects[jsIndex++];
   12.75 +        }
   12.76 +        jsObjects = Knockout.allocJS(len * 2);
   12.77 +        jsIndex = 1;
   12.78 +        return jsObjects[0];
   12.79 +    }
   12.80 +    
   12.81      @Override
   12.82      public Object wrapModel(Object model) {
   12.83          throw new UnsupportedOperationException();
   12.84 @@ -213,26 +194,8 @@
   12.85  
   12.86      @Override
   12.87      public void runSafe(final Runnable r) {
   12.88 -        class Wrap implements Runnable {
   12.89 -            @Override public void run() {
   12.90 -                Closeable c = Fn.activate(browserContext);
   12.91 -                try {
   12.92 -                    r.run();
   12.93 -                } finally {
   12.94 -                    try {
   12.95 -                        c.close();
   12.96 -                    } catch (IOException ex) {
   12.97 -                        // cannot be thrown
   12.98 -                    }
   12.99 -                }
  12.100 -            }
  12.101 -        }
  12.102 -        Wrap w = new Wrap();
  12.103 -        if (browserContext instanceof Executor) {
  12.104 -            ((Executor)browserContext).execute(w);
  12.105 -        } else {
  12.106 -            w.run();
  12.107 -        }
  12.108 +        LOG.warning("Technology.runSafe has been deprecated. Use BrwsrCtx.execute!");
  12.109 +        r.run();
  12.110      }
  12.111  
  12.112      @Override
    13.1 --- a/ko4j/src/main/java/org/netbeans/html/ko4j/KO4J.java	Tue Mar 04 12:29:51 2014 +0100
    13.2 +++ b/ko4j/src/main/java/org/netbeans/html/ko4j/KO4J.java	Tue Mar 04 21:57:50 2014 +0100
    13.3 @@ -116,12 +116,10 @@
    13.4       */
    13.5      @Override
    13.6      public void fillContext(Contexts.Builder context, Class<?> requestor) {
    13.7 -        if (FXContext.isJavaScriptEnabled()) {
    13.8 -            context.register(Technology.class, knockout(), 100);
    13.9 -            context.register(Transfer.class, transfer(), 100);
   13.10 -            if (c.areWebSocketsSupported()) {
   13.11 -                context.register(WSTransfer.class, websockets(), 100);
   13.12 -            }
   13.13 +        context.register(Technology.class, knockout(), 100);
   13.14 +        context.register(Transfer.class, transfer(), 100);
   13.15 +        if (c.areWebSocketsSupported()) {
   13.16 +            context.register(WSTransfer.class, websockets(), 100);
   13.17          }
   13.18      }
   13.19      
    14.1 --- a/ko4j/src/main/java/org/netbeans/html/ko4j/Knockout.java	Tue Mar 04 12:29:51 2014 +0100
    14.2 +++ b/ko4j/src/main/java/org/netbeans/html/ko4j/Knockout.java	Tue Mar 04 21:57:50 2014 +0100
    14.3 @@ -78,12 +78,18 @@
    14.4      @JavaScriptBody(args = { "bindings" }, body = "ko.applyBindings(bindings);\n")
    14.5      native static void applyBindings(Object bindings);
    14.6      
    14.7 +    @JavaScriptBody(args = { "cnt" }, body = 
    14.8 +        "var arr = new Array(cnt);\n" +
    14.9 +        "for (var i = 0; i < cnt; i++) arr[i] = new Object();\n" +
   14.10 +        "return arr;\n"
   14.11 +    )
   14.12 +    native static Object[] allocJS(int cnt);
   14.13 +    
   14.14      @JavaScriptBody(
   14.15          javacall = true,
   14.16 -        args = {"model", "propNames", "propReadOnly", "propValues", "propArr", "funcNames", "funcArr"},
   14.17 -        body
   14.18 -        = "var ret = {};\n"
   14.19 -        + "ret['ko-fx.model'] = model;\n"
   14.20 +        args = {"ret", "model", "propNames", "propReadOnly", "propValues", "propArr", "funcNames", "funcArr"},
   14.21 +        body =
   14.22 +          "ret['ko-fx.model'] = model;\n"
   14.23          + "function koComputed(name, readOnly, value, prop) {\n"
   14.24          + "  function realGetter() {\n"
   14.25          + "    try {\n"
   14.26 @@ -126,10 +132,9 @@
   14.27          + "for (var i = 0; i < funcNames.length; i++) {\n"
   14.28          + "  koExpose(funcNames[i], funcArr[i]);\n"
   14.29          + "}\n"
   14.30 -        + "return ret;\n"
   14.31          )
   14.32 -    static native Object wrapModel(
   14.33 -        Object model,
   14.34 +    static native void wrapModel(
   14.35 +        Object ret, Object model,
   14.36          String[] propNames, boolean[] propReadOnly, Object propValues, PropertyBinding[] propArr,
   14.37          String[] funcNames, FunctionBinding[] funcArr
   14.38      );
    15.1 --- a/ko4j/src/test/java/org/netbeans/html/ko4j/KnockoutFXTest.java	Tue Mar 04 12:29:51 2014 +0100
    15.2 +++ b/ko4j/src/test/java/org/netbeans/html/ko4j/KnockoutFXTest.java	Tue Mar 04 21:57:50 2014 +0100
    15.3 @@ -54,6 +54,7 @@
    15.4  import java.util.ArrayList;
    15.5  import java.util.List;
    15.6  import java.util.Map;
    15.7 +import java.util.concurrent.Executor;
    15.8  import java.util.concurrent.Executors;
    15.9  import net.java.html.BrwsrCtx;
   15.10  import net.java.html.boot.BrowserBuilder;
   15.11 @@ -160,7 +161,10 @@
   15.12          if (fx.areWebSocketsSupported()) {
   15.13              cb.register(WSTransfer.class, fx, 10);
   15.14          }
   15.15 -        return cb.build();
   15.16 +        cb.register(Executor.class, (Executor)browserContext, 10);
   15.17 +        cb.register(Fn.Presenter.class, browserContext, 10);
   15.18 +        BrwsrCtx ctx = cb.build();
   15.19 +        return ctx;
   15.20      }
   15.21  
   15.22      @Override