#248918: Introducing technology identifiers
authorJaroslav Tulach <jtulach@netbeans.org>
Thu, 04 Dec 2014 09:21:55 +0100
changeset 88688d62267a0b5
parent 885 6e20d36f1a13
child 887 0e2dc14e3a1e
#248918: Introducing technology identifiers
boot-fx/src/main/java/net/java/html/boot/fx/FXBrowsers.java
boot/src/main/java/net/java/html/boot/BrowserBuilder.java
context/src/main/java/net/java/html/BrwsrCtx.java
context/src/main/java/org/netbeans/html/context/impl/CtxImpl.java
context/src/main/java/org/netbeans/html/context/spi/Contexts.java
context/src/test/java/net/java/html/BrwsrCtxTest.java
json/src/main/java/org/netbeans/html/json/spi/Technology.java
json/src/main/java/org/netbeans/html/json/spi/Transfer.java
json/src/main/java/org/netbeans/html/json/spi/WSTransfer.java
ko-felix-test/src/main/java/org/netbeans/html/ko/felix/test/KnockoutFelixTCKImpl.java
ko-osgi-test/src/main/java/org/netbeans/html/ko/osgi/test/KnockoutEquinoxTCKImpl.java
ko-ws-tyrus/src/main/java/org/netbeans/html/wstyrus/TyrusContext.java
ko4j/src/main/java/org/netbeans/html/ko4j/FXContext.java
ko4j/src/main/java/org/netbeans/html/ko4j/KO4J.java
ko4j/src/main/java/org/netbeans/html/ko4j/KOSockets.java
ko4j/src/main/java/org/netbeans/html/ko4j/KOTech.java
ko4j/src/main/java/org/netbeans/html/ko4j/KOTransfer.java
ko4j/src/main/java/org/netbeans/html/ko4j/Knockout.java
ko4j/src/test/java/org/netbeans/html/ko4j/KnockoutFXTest.java
src/main/javadoc/overview.html
     1.1 --- a/boot-fx/src/main/java/net/java/html/boot/fx/FXBrowsers.java	Wed Dec 03 11:41:24 2014 +0100
     1.2 +++ b/boot-fx/src/main/java/net/java/html/boot/fx/FXBrowsers.java	Thu Dec 04 09:21:55 2014 +0100
     1.3 @@ -52,6 +52,8 @@
     1.4  import net.java.html.boot.BrowserBuilder;
     1.5  import net.java.html.js.JavaScriptBody;
     1.6  import org.netbeans.html.boot.fx.AbstractFXPresenter;
     1.7 +import org.netbeans.html.context.spi.Contexts;
     1.8 +import org.netbeans.html.context.spi.Contexts.Id;
     1.9  
    1.10  /** Utility methods to use {@link WebView} and {@link JavaScriptBody} code
    1.11   * in existing <em>JavaFX</em> applications.
    1.12 @@ -82,6 +84,16 @@
    1.13       * <p>
    1.14       * This method sets {@link WebView#getUserData()} and {@link #runInBrowser(javafx.scene.web.WebView, java.lang.Runnable)}
    1.15       * relies on the value. Please don't alter it.
    1.16 +     * <p>
    1.17 +     * Since introduction of {@link Id technology identifiers} the 
    1.18 +     * provided <code>args</code> strings are also passed to the 
    1.19 +     * {@link BrwsrCtx context} when it is being 
    1.20 +     * {@link Contexts#newBuilder(java.lang.Object...) created}
    1.21 +     * and can influence the selection
    1.22 +     * of available technologies 
    1.23 +     * (like {@link org.netbeans.html.json.spi.Technology},
    1.24 +     * {@link org.netbeans.html.json.spi.Transfer} or
    1.25 +     * {@link org.netbeans.html.json.spi.WSTransfer}).
    1.26       * 
    1.27       * @param webView the instance of Web View to tweak
    1.28       * @param url the URL of the HTML page to load into the view
    1.29 @@ -94,7 +106,10 @@
    1.30          Class<?> onPageLoad, String methodName,
    1.31          String... args
    1.32      ) {
    1.33 -        BrowserBuilder.newBrowser(new Load(webView)).
    1.34 +        Object[] context = new Object[args.length + 1];
    1.35 +        System.arraycopy(args, 0, context, 1, args.length);
    1.36 +        context[0] = new Load(webView);
    1.37 +        BrowserBuilder.newBrowser(context).
    1.38              loadPage(url.toExternalForm()).
    1.39              loadClass(onPageLoad).
    1.40              invoke(methodName, args).
     2.1 --- a/boot/src/main/java/net/java/html/boot/BrowserBuilder.java	Wed Dec 03 11:41:24 2014 +0100
     2.2 +++ b/boot/src/main/java/net/java/html/boot/BrowserBuilder.java	Thu Dec 04 09:21:55 2014 +0100
     2.3 @@ -65,6 +65,7 @@
     2.4  import org.netbeans.html.boot.spi.Fn;
     2.5  import org.netbeans.html.boot.spi.Fn.Presenter;
     2.6  import org.netbeans.html.context.spi.Contexts;
     2.7 +import org.netbeans.html.context.spi.Contexts.Id;
     2.8  import org.netbeans.html.boot.impl.FindResources;
     2.9  import org.netbeans.html.boot.impl.FnContext;
    2.10  import org.netbeans.html.boot.impl.FnUtils;
    2.11 @@ -121,6 +122,15 @@
    2.12      /** Entry method to obtain a new browser builder. Follow by calling 
    2.13       * its instance methods like {@link #loadClass(java.lang.Class)} and
    2.14       * {@link #loadPage(java.lang.String)}.
    2.15 +     * Since introduction of {@link Id technology identifiers} the 
    2.16 +     * provided <code>context</code> objects are also passed to the 
    2.17 +     * {@link BrwsrCtx context} when it is being 
    2.18 +     * {@link Contexts#newBuilder(java.lang.Object...) created}
    2.19 +     * and can influence the selection
    2.20 +     * of available technologies 
    2.21 +     * (like {@link org.netbeans.html.json.spi.Technology},
    2.22 +     * {@link org.netbeans.html.json.spi.Transfer} or
    2.23 +     * {@link org.netbeans.html.json.spi.WSTransfer}) by name.
    2.24       * 
    2.25       * @param context any instances that should be available to the builder -
    2.26       *   implementation dependant
    2.27 @@ -301,7 +311,7 @@
    2.28                      if (browserClass != null) {
    2.29                          browserClass[0] = newClazz;
    2.30                      }
    2.31 -                    Contexts.Builder cb = Contexts.newBuilder();
    2.32 +                    Contexts.Builder cb = Contexts.newBuilder(context);
    2.33                      if (!Contexts.fillInByProviders(newClazz, cb)) {
    2.34                          LOG.log(Level.WARNING, "Using empty technology for {0}", newClazz);
    2.35                      }
     3.1 --- a/context/src/main/java/net/java/html/BrwsrCtx.java	Wed Dec 03 11:41:24 2014 +0100
     3.2 +++ b/context/src/main/java/net/java/html/BrwsrCtx.java	Thu Dec 04 09:21:55 2014 +0100
     3.3 @@ -47,6 +47,7 @@
     3.4  import org.netbeans.html.context.impl.CtxAccssr;
     3.5  import org.netbeans.html.context.impl.CtxImpl;
     3.6  import org.netbeans.html.context.spi.Contexts;
     3.7 +import org.netbeans.html.context.spi.Contexts.Id;
     3.8  
     3.9  /** Represents context where the <code>net.java.html.json.Model</code>
    3.10   * and other objects
    3.11 @@ -54,7 +55,12 @@
    3.12   * The context is also associated with the actual HTML technology
    3.13   * in the HTML page - there is likely to be different context for 
    3.14   * <a href="http://knockoutjs.com">knockout.js</a> and different one
    3.15 - * for <a href="http://angularjs.org">angular</a>.
    3.16 + * for <a href="http://angularjs.org">angular</a>. Since version 1.1
    3.17 + * the content of contexts can be selected by registering
    3.18 + * implementations under specific
    3.19 + * {@link Id technology identifiers} and requesting them during 
    3.20 + * {@link Contexts#newBuilder(java.lang.Object...) construction} of the
    3.21 + * context.
    3.22   *
    3.23   * @author Jaroslav Tulach
    3.24   */
     4.1 --- a/context/src/main/java/org/netbeans/html/context/impl/CtxImpl.java	Wed Dec 03 11:41:24 2014 +0100
     4.2 +++ b/context/src/main/java/org/netbeans/html/context/impl/CtxImpl.java	Thu Dec 04 09:21:55 2014 +0100
     4.3 @@ -44,8 +44,10 @@
     4.4  
     4.5  import java.util.ArrayList;
     4.6  import java.util.Collections;
     4.7 +import java.util.Comparator;
     4.8  import java.util.List;
     4.9  import net.java.html.BrwsrCtx;
    4.10 +import org.netbeans.html.context.spi.Contexts;
    4.11  
    4.12  /** Implementation detail. Holds list of technologies for particular
    4.13   * {@link BrwsrCtx}.
    4.14 @@ -54,13 +56,15 @@
    4.15   */
    4.16  public final class CtxImpl {
    4.17      private final List<Bind<?>> techs;
    4.18 +    private final Object[] context;
    4.19      
    4.20 -    public CtxImpl() {
    4.21 -        techs = new ArrayList<Bind<?>>();
    4.22 +    public CtxImpl(Object[] context) {
    4.23 +        this(context, new ArrayList<Bind<?>>());
    4.24      }
    4.25      
    4.26 -    private CtxImpl(List<Bind<?>> techs) {
    4.27 +    private CtxImpl(Object[] context, List<Bind<?>> techs) {
    4.28          this.techs = techs;
    4.29 +        this.context = context;
    4.30      }
    4.31      
    4.32      public static <Tech> Tech find(BrwsrCtx context, Class<Tech> technology) {
    4.33 @@ -74,9 +78,9 @@
    4.34      }
    4.35  
    4.36      public BrwsrCtx build() {
    4.37 -        Collections.sort(techs);
    4.38 +        Collections.sort(techs, new BindCompare());
    4.39          final List<Bind<?>> arr = Collections.unmodifiableList(techs);
    4.40 -        CtxImpl impl = new CtxImpl(arr);
    4.41 +        CtxImpl impl = new CtxImpl(context, arr);
    4.42          BrwsrCtx ctx = CtxAccssr.getDefault().newContext(impl);
    4.43          return ctx;
    4.44      }
    4.45 @@ -85,7 +89,7 @@
    4.46          techs.add(new Bind<Tech>(type, impl, priority));
    4.47      }
    4.48      
    4.49 -    private static final class Bind<Tech> implements Comparable<Bind<?>> {
    4.50 +    private static final class Bind<Tech> {
    4.51          private final Class<Tech> clazz;
    4.52          private final Tech impl;
    4.53          private final int priority;
    4.54 @@ -97,16 +101,39 @@
    4.55          }
    4.56  
    4.57          @Override
    4.58 -        public int compareTo(Bind<?> o) {
    4.59 -            if (priority != o.priority) {
    4.60 -                return priority - o.priority;
    4.61 -            }
    4.62 -            return clazz.getName().compareTo(o.clazz.getName());
    4.63 -        }
    4.64 -
    4.65 -        @Override
    4.66          public String toString() {
    4.67              return "Bind{" + "clazz=" + clazz + "@" + clazz.getClassLoader() + ", impl=" + impl + ", priority=" + priority + '}';
    4.68          }
    4.69      }
    4.70 +    
    4.71 +    private final class BindCompare implements Comparator<Bind<?>> {
    4.72 +        boolean isPrefered(Bind<?> b) {
    4.73 +            final Class<?> implClazz = b.impl.getClass();
    4.74 +            Contexts.Id id = implClazz.getAnnotation(Contexts.Id.class);
    4.75 +            if (id == null) {
    4.76 +                return false;
    4.77 +            }
    4.78 +            for (String v : id.value()) {
    4.79 +                for (Object c : context) {
    4.80 +                    if (v.equals(c)) {
    4.81 +                        return true;
    4.82 +                    }
    4.83 +                }
    4.84 +            }
    4.85 +            return false;
    4.86 +        }
    4.87 +        
    4.88 +        @Override
    4.89 +        public int compare(Bind<?> o1, Bind<?> o2) {
    4.90 +            boolean p1 = isPrefered(o1);
    4.91 +            boolean p2 = isPrefered(o2);
    4.92 +            if (p1 != p2) {
    4.93 +                return p1 ? -1 : 1;
    4.94 +            }
    4.95 +            if (o1.priority != o2.priority) {
    4.96 +                return o1.priority - o2.priority;
    4.97 +            }
    4.98 +            return o1.clazz.getName().compareTo(o2.clazz.getName());
    4.99 +        }
   4.100 +    } // end of BindCompare
   4.101  }
     5.1 --- a/context/src/main/java/org/netbeans/html/context/spi/Contexts.java	Wed Dec 03 11:41:24 2014 +0100
     5.2 +++ b/context/src/main/java/org/netbeans/html/context/spi/Contexts.java	Thu Dec 04 09:21:55 2014 +0100
     5.3 @@ -42,6 +42,10 @@
     5.4   */
     5.5  package org.netbeans.html.context.spi;
     5.6  
     5.7 +import java.lang.annotation.ElementType;
     5.8 +import java.lang.annotation.Retention;
     5.9 +import java.lang.annotation.RetentionPolicy;
    5.10 +import java.lang.annotation.Target;
    5.11  import java.util.ServiceLoader;
    5.12  import net.java.html.BrwsrCtx;
    5.13  import org.netbeans.html.context.impl.CtxImpl;
    5.14 @@ -59,11 +63,23 @@
    5.15  
    5.16      /** Creates new, empty builder for creation of {@link BrwsrCtx}. At the
    5.17       * end call the {@link Builder#build()} method to generate the context.
    5.18 -     *
    5.19 +     * 
    5.20 +     * @param context instances of various classes or names of {@link Id technologies} 
    5.21 +     *    to be preferred and used in the built {@link BrwsrCtx context}.
    5.22 +     * @return new instance of the builder
    5.23 +     * @since 1.1
    5.24 +     */
    5.25 +    public static Builder newBuilder(Object... context) {
    5.26 +        return new Builder(context);
    5.27 +    }
    5.28 +    /** Creates new, empty builder for creation of {@link BrwsrCtx}. At the
    5.29 +     * end call the {@link Builder#build()} method to generate the context.
    5.30 +     * Simply calls {@link #newBuilder(java.lang.Object...) newBuilder(new Object[0])}.
    5.31 +     * 
    5.32       * @return new instance of the builder
    5.33       */
    5.34      public static Builder newBuilder() {
    5.35 -        return new Builder();
    5.36 +        return newBuilder(new Object[0]);
    5.37      }
    5.38  
    5.39      /** Seeks for the specified technology in the provided context.
    5.40 @@ -118,6 +134,23 @@
    5.41          }
    5.42          return found;
    5.43      }
    5.44 +    
    5.45 +    /** Identifies the technologies passed to {@link Builder context builder}
    5.46 +     * by a name. Each implementation of a technology 
    5.47 +     * {@link Builder#register(java.lang.Class, java.lang.Object, int) registered into a context}
    5.48 +     * can be annotated with a name (or multiple names). Such implementation
    5.49 +     * will later be 
    5.50 +     * {@link Contexts#fillInByProviders(java.lang.Class, org.netbeans.html.context.spi.Contexts.Builder)  preferred during lookup}
    5.51 +     * if their name(s) has been requested in when 
    5.52 +     * {@link Contexts#newBuilder(java.lang.Object...)  creating a context}.
    5.53 +     * @since 1.1
    5.54 +     */
    5.55 +    @Retention(RetentionPolicy.RUNTIME)
    5.56 +    @Target(ElementType.TYPE)
    5.57 +    public @interface Id {
    5.58 +        /** Identifier(s) for the implementation. */
    5.59 +        public String[] value();
    5.60 +    }
    5.61  
    5.62      /** Implementors of various HTML technologies should
    5.63       * register their implementation via <code>org.openide.util.lookup.ServiceProvider</code>, so
    5.64 @@ -152,9 +185,10 @@
    5.65       * @author Jaroslav Tulach
    5.66       */
    5.67      public static final class Builder {
    5.68 -        private final CtxImpl impl = new CtxImpl();
    5.69 +        private final CtxImpl impl;
    5.70  
    5.71 -        Builder() {
    5.72 +        public Builder(Object[] context) {
    5.73 +            this.impl = new CtxImpl(context);
    5.74          }
    5.75          
    5.76          /** Registers new technology into the context. Each technology is
     6.1 --- a/context/src/test/java/net/java/html/BrwsrCtxTest.java	Wed Dec 03 11:41:24 2014 +0100
     6.2 +++ b/context/src/test/java/net/java/html/BrwsrCtxTest.java	Thu Dec 04 09:21:55 2014 +0100
     6.3 @@ -44,6 +44,7 @@
     6.4  
     6.5  import org.netbeans.html.context.spi.Contexts;
     6.6  import static org.testng.Assert.*;
     6.7 +import org.testng.annotations.Test;
     6.8  
     6.9  /**
    6.10   *
    6.11 @@ -72,4 +73,48 @@
    6.12          assertTrue(arr[0], "Runnable was executed");
    6.13      }
    6.14      
    6.15 +    
    6.16 +    @Test public void defaultOrderOfRegistrations() {
    6.17 +        BrwsrCtx ctx = registerRs(Contexts.newBuilder());
    6.18 +        Class<? extends Runnable> clazz = Contexts.find(ctx, Runnable.class).getClass();
    6.19 +        assertEquals(clazz, R1.class, "R1 is registered at value 10");
    6.20 +    }
    6.21 +    
    6.22 +    @Test public void preferOne() {
    6.23 +        BrwsrCtx ctx = registerRs(Contexts.newBuilder("one"));
    6.24 +        Class<? extends Runnable> clazz = Contexts.find(ctx, Runnable.class).getClass();
    6.25 +        assertEquals(clazz, R1.class, "R1 is registered at value 10");
    6.26 +    }
    6.27 +
    6.28 +    @Test public void preferTwo() {
    6.29 +        BrwsrCtx ctx = registerRs(Contexts.newBuilder("two"));
    6.30 +        Class<? extends Runnable> clazz = Contexts.find(ctx, Runnable.class).getClass();
    6.31 +        assertEquals(clazz, R2.class, "R2 is preferred");
    6.32 +    }
    6.33 +
    6.34 +    @Test public void preferBoth() {
    6.35 +        BrwsrCtx ctx = registerRs(Contexts.newBuilder("one", "two"));
    6.36 +        Class<? extends Runnable> clazz = Contexts.find(ctx, Runnable.class).getClass();
    6.37 +        assertEquals(clazz, R1.class, "R1 is registered at value 10");
    6.38 +    }
    6.39 +    
    6.40 +    private static BrwsrCtx registerRs(Contexts.Builder b) {
    6.41 +        b.register(Runnable.class, new R1(), 10);
    6.42 +        b.register(Runnable.class, new R2(), 20);
    6.43 +        return b.build();
    6.44 +    }
    6.45 +
    6.46 +    @Contexts.Id("one")
    6.47 +    static final class R1 implements Runnable {
    6.48 +        @Override
    6.49 +        public void run() {
    6.50 +        }
    6.51 +    }
    6.52 +    @Contexts.Id("two")
    6.53 +    static final class R2 implements Runnable {
    6.54 +        @Override
    6.55 +        public void run() {
    6.56 +        }
    6.57 +    }
    6.58 +    
    6.59  }
    6.60 \ No newline at end of file
     7.1 --- a/json/src/main/java/org/netbeans/html/json/spi/Technology.java	Wed Dec 03 11:41:24 2014 +0100
     7.2 +++ b/json/src/main/java/org/netbeans/html/json/spi/Technology.java	Thu Dec 04 09:21:55 2014 +0100
     7.3 @@ -45,10 +45,17 @@
     7.4  import net.java.html.BrwsrCtx;
     7.5  import net.java.html.json.Model;
     7.6  import net.java.html.json.Models;
     7.7 +import org.netbeans.html.context.spi.Contexts.Id;
     7.8  
     7.9  /** An implementation of a binding between model classes (see {@link Model})
    7.10   * and particular technology like <a href="http://knockoutjs.com">knockout.js</a>
    7.11   * in a browser window, etc.
    7.12 + * Since introduction of {@link Id technology identifiers} one can choose between
    7.13 + * different background implementations to handle the conversion and
    7.14 + * communication requests. The currently known provider is
    7.15 + * <code>org.netbeans.html:ko4j</code> module which registers 
    7.16 + * a <a href="http://knockoutjs.com" target="_blank">knockout.js</a>
    7.17 + * implementation called <b>ko4j</b>.
    7.18   *
    7.19   * @author Jaroslav Tulach
    7.20   */
     8.1 --- a/json/src/main/java/org/netbeans/html/json/spi/Transfer.java	Wed Dec 03 11:41:24 2014 +0100
     8.2 +++ b/json/src/main/java/org/netbeans/html/json/spi/Transfer.java	Thu Dec 04 09:21:55 2014 +0100
     8.3 @@ -45,9 +45,17 @@
     8.4  import java.io.IOException;
     8.5  import java.io.InputStream;
     8.6  import org.netbeans.html.context.spi.Contexts.Builder;
     8.7 +import org.netbeans.html.context.spi.Contexts.Id;
     8.8  
     8.9  /** A {@link Builder service provider interface} responsible for 
    8.10   * conversion of JSON objects to Java ones and vice-versa.
    8.11 + * Since introduction of {@link Id technology identifiers} one can choose between
    8.12 + * different background implementations to handle the conversion and
    8.13 + * communication requests. The known providers include
    8.14 + * <code>org.netbeans.html:ko4j</code> module which registers 
    8.15 + * a native browser implementation called <b>xhr</b>, and a
    8.16 + * <code>org.netbeans.html:ko-ws-tyrus</code> module which registers 
    8.17 + * Java based implementation named <b>tyrus</b>.
    8.18   *
    8.19   * @author Jaroslav Tulach
    8.20   */
     9.1 --- a/json/src/main/java/org/netbeans/html/json/spi/WSTransfer.java	Wed Dec 03 11:41:24 2014 +0100
     9.2 +++ b/json/src/main/java/org/netbeans/html/json/spi/WSTransfer.java	Thu Dec 04 09:21:55 2014 +0100
     9.3 @@ -44,9 +44,17 @@
     9.4  
     9.5  import net.java.html.BrwsrCtx;
     9.6  import org.netbeans.html.context.spi.Contexts.Provider;
     9.7 +import org.netbeans.html.context.spi.Contexts.Id;
     9.8  
     9.9  /** Interface for providers of WebSocket protocol. Register into a 
    9.10 - * {@link BrwsrCtx context} in your own {@link Provider}
    9.11 + * {@link BrwsrCtx context} in your own {@link Provider}.
    9.12 + * Since introduction of {@link Id technology identifiers} one can choose between
    9.13 + * different background implementations to handle the conversion and
    9.14 + * communication requests. The known providers include
    9.15 + * <code>org.netbeans.html:ko4j</code> module which registers 
    9.16 + * a native browser implementation called <b>websocket</b>, and a
    9.17 + * <code>org.netbeans.html:ko-ws-tyrus</code> module which registers 
    9.18 + * Java based implementation named <b>tyrus</b>.
    9.19   *
    9.20   * @author Jaroslav Tulach
    9.21   * @param <WebSocket> internal implementation type representing the socket
    10.1 --- a/ko-felix-test/src/main/java/org/netbeans/html/ko/felix/test/KnockoutFelixTCKImpl.java	Wed Dec 03 11:41:24 2014 +0100
    10.2 +++ b/ko-felix-test/src/main/java/org/netbeans/html/ko/felix/test/KnockoutFelixTCKImpl.java	Thu Dec 04 09:21:55 2014 +0100
    10.3 @@ -46,6 +46,7 @@
    10.4  import java.io.IOException;
    10.5  import java.io.InputStreamReader;
    10.6  import java.lang.reflect.Constructor;
    10.7 +import java.lang.reflect.InvocationTargetException;
    10.8  import java.lang.reflect.Method;
    10.9  import java.net.URI;
   10.10  import java.net.URISyntaxException;
   10.11 @@ -140,16 +141,9 @@
   10.12      @Override
   10.13      public BrwsrCtx createContext() {
   10.14          try {
   10.15 -            Class<?> fxCls = loadOSGiClass(
   10.16 -                "org.netbeans.html.ko4j.FXContext",
   10.17 -                FrameworkUtil.getBundle(KnockoutFelixTCKImpl.class).getBundleContext()
   10.18 -            );
   10.19 -            final Constructor<?> cnstr = fxCls.getConstructor(Fn.Presenter.class);
   10.20 -            cnstr.setAccessible(true);
   10.21 -            Object fx = cnstr.newInstance(browserContext);
   10.22              Contexts.Builder cb = Contexts.newBuilder().
   10.23 -                register(Technology.class, (Technology)fx, 10).
   10.24 -                register(Transfer.class, (Transfer)fx, 10).
   10.25 +                register(Technology.class, (Technology)osgiInstance("KOTech"), 10).
   10.26 +                register(Transfer.class, (Transfer)osgiInstance("KOTransfer"), 10).
   10.27                  register(Executor.class, (Executor)browserContext, 10);
   10.28  //        if (fx.areWebSocketsSupported()) {
   10.29  //            cb.register(WSTransfer.class, fx, 10);
   10.30 @@ -160,6 +154,17 @@
   10.31          }
   10.32      }
   10.33  
   10.34 +    private Object osgiInstance(String simpleName) throws IllegalAccessException, SecurityException, IllegalArgumentException, Exception, NoSuchMethodException, InstantiationException, InvocationTargetException {
   10.35 +        Class<?> fxCls = loadOSGiClass(
   10.36 +                "org.netbeans.html.ko4j." + simpleName,
   10.37 +                FrameworkUtil.getBundle(KnockoutFelixTCKImpl.class).getBundleContext()
   10.38 +        );
   10.39 +        final Constructor<?> cnstr = fxCls.getDeclaredConstructor();
   10.40 +        cnstr.setAccessible(true);
   10.41 +        Object fx = cnstr.newInstance();
   10.42 +        return fx;
   10.43 +    }
   10.44 +
   10.45      @Override
   10.46      public Object createJSON(Map<String, Object> values) {
   10.47          JSONObject json = new JSONObject();
    11.1 --- a/ko-osgi-test/src/main/java/org/netbeans/html/ko/osgi/test/KnockoutEquinoxTCKImpl.java	Wed Dec 03 11:41:24 2014 +0100
    11.2 +++ b/ko-osgi-test/src/main/java/org/netbeans/html/ko/osgi/test/KnockoutEquinoxTCKImpl.java	Thu Dec 04 09:21:55 2014 +0100
    11.3 @@ -46,6 +46,7 @@
    11.4  import java.io.IOException;
    11.5  import java.io.InputStreamReader;
    11.6  import java.lang.reflect.Constructor;
    11.7 +import java.lang.reflect.InvocationTargetException;
    11.8  import java.lang.reflect.Method;
    11.9  import java.net.URI;
   11.10  import java.net.URISyntaxException;
   11.11 @@ -135,16 +136,9 @@
   11.12      @Override
   11.13      public BrwsrCtx createContext() {
   11.14          try {
   11.15 -            Class<?> fxCls = loadOSGiClass(
   11.16 -                "org.netbeans.html.ko4j.FXContext",
   11.17 -                FrameworkUtil.getBundle(KnockoutEquinoxTCKImpl.class).getBundleContext()
   11.18 -            );
   11.19 -            final Constructor<?> cnstr = fxCls.getConstructor(Fn.Presenter.class);
   11.20 -            cnstr.setAccessible(true);
   11.21 -            Object fx = cnstr.newInstance(browserContext);
   11.22              Contexts.Builder cb = Contexts.newBuilder().
   11.23 -                register(Technology.class, (Technology)fx, 10).
   11.24 -                register(Transfer.class, (Transfer)fx, 10).
   11.25 +                register(Technology.class, (Technology)osgiInstance("KOTech"), 10).
   11.26 +                register(Transfer.class, (Transfer)osgiInstance("KOTransfer"), 10).
   11.27                  register(Executor.class, (Executor)browserContext, 10);
   11.28  //        if (fx.areWebSocketsSupported()) {
   11.29  //            cb.register(WSTransfer.class, fx, 10);
   11.30 @@ -154,6 +148,16 @@
   11.31              throw new IllegalStateException(ex);
   11.32          }
   11.33      }
   11.34 +    private Object osgiInstance(String simpleName) throws IllegalAccessException, SecurityException, IllegalArgumentException, Exception, NoSuchMethodException, InstantiationException, InvocationTargetException {
   11.35 +        Class<?> fxCls = loadOSGiClass(
   11.36 +                "org.netbeans.html.ko4j." + simpleName,
   11.37 +                FrameworkUtil.getBundle(KnockoutEquinoxTCKImpl.class).getBundleContext()
   11.38 +        );
   11.39 +        final Constructor<?> cnstr = fxCls.getDeclaredConstructor();
   11.40 +        cnstr.setAccessible(true);
   11.41 +        Object fx = cnstr.newInstance();
   11.42 +        return fx;
   11.43 +    }
   11.44  
   11.45      @Override
   11.46      public Object createJSON(Map<String, Object> values) {
    12.1 --- a/ko-ws-tyrus/src/main/java/org/netbeans/html/wstyrus/TyrusContext.java	Wed Dec 03 11:41:24 2014 +0100
    12.2 +++ b/ko-ws-tyrus/src/main/java/org/netbeans/html/wstyrus/TyrusContext.java	Thu Dec 04 09:21:55 2014 +0100
    12.3 @@ -82,6 +82,7 @@
    12.4   *
    12.5   * @author Jaroslav Tulach
    12.6   */
    12.7 +@Contexts.Id("tyrus")
    12.8  @ServiceProvider(service = Contexts.Provider.class)
    12.9  public final class TyrusContext 
   12.10  implements Contexts.Provider, WSTransfer<Comm>, Transfer {
    13.1 --- a/ko4j/src/main/java/org/netbeans/html/ko4j/FXContext.java	Wed Dec 03 11:41:24 2014 +0100
    13.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.3 @@ -1,233 +0,0 @@
    13.4 -/**
    13.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    13.6 - *
    13.7 - * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
    13.8 - *
    13.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   13.10 - * Other names may be trademarks of their respective owners.
   13.11 - *
   13.12 - * The contents of this file are subject to the terms of either the GNU
   13.13 - * General Public License Version 2 only ("GPL") or the Common
   13.14 - * Development and Distribution License("CDDL") (collectively, the
   13.15 - * "License"). You may not use this file except in compliance with the
   13.16 - * License. You can obtain a copy of the License at
   13.17 - * http://www.netbeans.org/cddl-gplv2.html
   13.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   13.19 - * specific language governing permissions and limitations under the
   13.20 - * License.  When distributing the software, include this License Header
   13.21 - * Notice in each file and include the License file at
   13.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   13.23 - * particular file as subject to the "Classpath" exception as provided
   13.24 - * by Oracle in the GPL Version 2 section of the License file that
   13.25 - * accompanied this code. If applicable, add the following below the
   13.26 - * License Header, with the fields enclosed by brackets [] replaced by
   13.27 - * your own identifying information:
   13.28 - * "Portions Copyrighted [year] [name of copyright owner]"
   13.29 - *
   13.30 - * Contributor(s):
   13.31 - *
   13.32 - * The Original Software is NetBeans. The Initial Developer of the Original
   13.33 - * Software is Oracle. Portions Copyright 2013-2014 Oracle. All Rights Reserved.
   13.34 - *
   13.35 - * If you wish your version of this file to be governed by only the CDDL
   13.36 - * or only the GPL Version 2, indicate your decision by adding
   13.37 - * "[Contributor] elects to include this software in this distribution
   13.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
   13.39 - * single choice of license, a recipient has the option to distribute
   13.40 - * your version of this file under either the CDDL, the GPL Version 2 or
   13.41 - * to extend the choice of license to its licensees as provided above.
   13.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
   13.43 - * Version 2 license, then the option applies only if the new code is
   13.44 - * made subject to such option by the copyright holder.
   13.45 - */
   13.46 -package org.netbeans.html.ko4j;
   13.47 -
   13.48 -import java.io.ByteArrayOutputStream;
   13.49 -import java.io.Closeable;
   13.50 -import java.io.IOException;
   13.51 -import java.io.InputStream;
   13.52 -import java.io.InputStreamReader;
   13.53 -import java.io.Reader;
   13.54 -import java.net.URL;
   13.55 -import java.util.logging.Logger;
   13.56 -import org.netbeans.html.boot.spi.Fn;
   13.57 -import org.netbeans.html.json.spi.FunctionBinding;
   13.58 -import org.netbeans.html.json.spi.JSONCall;
   13.59 -import org.netbeans.html.json.spi.PropertyBinding;
   13.60 -import org.netbeans.html.json.spi.Technology;
   13.61 -import org.netbeans.html.json.spi.Transfer;
   13.62 -import org.netbeans.html.json.spi.WSTransfer;
   13.63 -
   13.64 -/** This is an implementation package - just
   13.65 - * include its JAR on classpath and use official {@link Context} API
   13.66 - * to access the functionality.
   13.67 - * <p>
   13.68 - *
   13.69 - * @author Jaroslav Tulach
   13.70 - */
   13.71 -final class FXContext
   13.72 -implements Technology.BatchInit<Object>, Technology.ValueMutated<Object>,
   13.73 -Transfer, WSTransfer<LoadWS> {
   13.74 -    static final Logger LOG = Logger.getLogger(FXContext.class.getName());
   13.75 -    private Object[] jsObjects;
   13.76 -    private int jsIndex;
   13.77 -
   13.78 -    public FXContext(Fn.Presenter browserContext) {
   13.79 -    }
   13.80 -    
   13.81 -    @Override
   13.82 -    public Object wrapModel(Object model, PropertyBinding[] propArr, FunctionBinding[] funcArr) {
   13.83 -        String[] propNames = new String[propArr.length];
   13.84 -        boolean[] propReadOnly = new boolean[propArr.length];
   13.85 -        Object[] propValues = new Object[propArr.length];
   13.86 -        for (int i = 0; i < propNames.length; i++) {
   13.87 -            propNames[i] = propArr[i].getPropertyName();
   13.88 -            propReadOnly[i] = propArr[i].isReadOnly();
   13.89 -            propValues[i] = propArr[i].getValue();
   13.90 -        }
   13.91 -        String[] funcNames = new String[funcArr.length];
   13.92 -        for (int i = 0; i < funcNames.length; i++) {
   13.93 -            funcNames[i] = funcArr[i].getFunctionName();
   13.94 -        }
   13.95 -        Object ret = getJSObject();
   13.96 -        Knockout.wrapModel(ret, model, 
   13.97 -            propNames, propReadOnly, propValues, propArr,
   13.98 -            funcNames, funcArr
   13.99 -        );
  13.100 -        return ret;
  13.101 -    }
  13.102 -    
  13.103 -    private Object getJSObject() {
  13.104 -        int len = 64;
  13.105 -        if (jsObjects != null && jsIndex < (len = jsObjects.length)) {
  13.106 -            return jsObjects[jsIndex++];
  13.107 -        }
  13.108 -        jsObjects = Knockout.allocJS(len * 2);
  13.109 -        jsIndex = 1;
  13.110 -        return jsObjects[0];
  13.111 -    }
  13.112 -    
  13.113 -    @Override
  13.114 -    public Object wrapModel(Object model) {
  13.115 -        throw new UnsupportedOperationException();
  13.116 -    }
  13.117 -
  13.118 -    @Override
  13.119 -    public void bind(PropertyBinding b, Object model, Object data) {
  13.120 -        throw new UnsupportedOperationException();
  13.121 -    }
  13.122 -
  13.123 -    @Override
  13.124 -    public void valueHasMutated(Object data, String propertyName) {
  13.125 -        Knockout.valueHasMutated(data, propertyName, null, null);
  13.126 -    }
  13.127 -    
  13.128 -    @Override
  13.129 -    public void valueHasMutated(Object data, String propertyName, Object oldValue, Object newValue) {
  13.130 -        Knockout.valueHasMutated(data, propertyName, oldValue, newValue);
  13.131 -    }
  13.132 -
  13.133 -    @Override
  13.134 -    public void expose(FunctionBinding fb, Object model, Object d) {
  13.135 -        throw new UnsupportedOperationException();
  13.136 -    }
  13.137 -
  13.138 -    @Override
  13.139 -    public void applyBindings(Object data) {
  13.140 -        Knockout.applyBindings(data);
  13.141 -    }
  13.142 -
  13.143 -    @Override
  13.144 -    public Object wrapArray(Object[] arr) {
  13.145 -        return arr;
  13.146 -    }
  13.147 -
  13.148 -    @Override
  13.149 -    public void extract(Object obj, String[] props, Object[] values) {
  13.150 -        LoadJSON.extractJSON(obj, props, values);
  13.151 -    }
  13.152 -
  13.153 -    @Override
  13.154 -    public void loadJSON(final JSONCall call) {
  13.155 -        if (call.isJSONP()) {
  13.156 -            String me = LoadJSON.createJSONP(call);
  13.157 -            LoadJSON.loadJSONP(call.composeURL(me), me);
  13.158 -        } else {
  13.159 -            String data = null;
  13.160 -            if (call.isDoOutput()) {
  13.161 -                try {
  13.162 -                    ByteArrayOutputStream bos = new ByteArrayOutputStream();
  13.163 -                    call.writeData(bos);
  13.164 -                    data = new String(bos.toByteArray(), "UTF-8");
  13.165 -                } catch (IOException ex) {
  13.166 -                    call.notifyError(ex);
  13.167 -                }
  13.168 -            }
  13.169 -            LoadJSON.loadJSON(call.composeURL(null), call, call.getMethod(), data);
  13.170 -        }
  13.171 -    }
  13.172 -
  13.173 -    @Override
  13.174 -    public <M> M toModel(Class<M> modelClass, Object data) {
  13.175 -        return modelClass.cast(Knockout.toModel(data));
  13.176 -    }
  13.177 -
  13.178 -    @Override
  13.179 -    public Object toJSON(InputStream is) throws IOException {
  13.180 -        StringBuilder sb = new StringBuilder();
  13.181 -        InputStreamReader r = new InputStreamReader(is);
  13.182 -        for (;;) {
  13.183 -            int ch = r.read();
  13.184 -            if (ch == -1) {
  13.185 -                break;
  13.186 -            }
  13.187 -            sb.append((char)ch);
  13.188 -        }
  13.189 -        return LoadJSON.parse(sb.toString());
  13.190 -    }
  13.191 -
  13.192 -    @Override
  13.193 -    public void runSafe(final Runnable r) {
  13.194 -        LOG.warning("Technology.runSafe has been deprecated. Use BrwsrCtx.execute!");
  13.195 -        r.run();
  13.196 -    }
  13.197 -
  13.198 -    @Override
  13.199 -    public LoadWS open(String url, JSONCall onReply) {
  13.200 -        return new LoadWS(onReply, url);
  13.201 -    }
  13.202 -
  13.203 -    @Override
  13.204 -    public void send(LoadWS socket, JSONCall data) {
  13.205 -        socket.send(data);
  13.206 -    }
  13.207 -
  13.208 -    @Override
  13.209 -    public void close(LoadWS socket) {
  13.210 -        socket.close();
  13.211 -    }
  13.212 -
  13.213 -    boolean areWebSocketsSupported() {
  13.214 -        return Knockout.areWebSocketsSupported();
  13.215 -    }
  13.216 -
  13.217 -    private static final class TrueFn extends Fn implements Fn.Presenter {
  13.218 -        @Override
  13.219 -        public Object invoke(Object thiz, Object... args) throws Exception {
  13.220 -            return true;
  13.221 -        }
  13.222 -
  13.223 -        @Override
  13.224 -        public Fn defineFn(String code, String... names) {
  13.225 -            return this;
  13.226 -        }
  13.227 -
  13.228 -        @Override
  13.229 -        public void displayPage(URL page, Runnable onPageLoad) {
  13.230 -        }
  13.231 -
  13.232 -        @Override
  13.233 -        public void loadScript(Reader code) throws Exception {
  13.234 -        }
  13.235 -    } // end of TrueFn
  13.236 -}
    14.1 --- a/ko4j/src/main/java/org/netbeans/html/ko4j/KO4J.java	Wed Dec 03 11:41:24 2014 +0100
    14.2 +++ b/ko4j/src/main/java/org/netbeans/html/ko4j/KO4J.java	Thu Dec 04 09:21:55 2014 +0100
    14.3 @@ -42,7 +42,9 @@
    14.4   */
    14.5  package org.netbeans.html.ko4j;
    14.6  
    14.7 +import java.util.logging.Logger;
    14.8  import net.java.html.json.Model;
    14.9 +import net.java.html.json.OnReceive;
   14.10  import org.netbeans.html.boot.spi.Fn;
   14.11  import org.netbeans.html.context.spi.Contexts;
   14.12  import org.netbeans.html.context.spi.Contexts.Provider;
   14.13 @@ -54,35 +56,49 @@
   14.14  /** Support for <a href="http://knockoutjs.com">knockout.js</a>
   14.15   * and its Java binding via {@link Model model classes}.
   14.16   * Registers {@link Provider}, so {@link java.util.ServiceLoader} can find it.
   14.17 + * The provider registers following technologies:
   14.18 + * <ul>
   14.19 + * <li><b>ko4j</b> - bindings for <a href="http://knockoutjs.com">knockout.js</a>
   14.20 + *   and the classes generated by the {@link Model} annotation.
   14.21 + * </li>
   14.22 + * <li><b>xhr</b> - <a href="http://www.w3.org/TR/XMLHttpRequest/">XMLHttpRequest</a>
   14.23 + *   based implementation for <em>REST</em> calls 
   14.24 + *   (<b>GET</b>, <b>PUT</b>, <b>POST</b>, <b>DELETE</b> methods) 
   14.25 + *   for {@link OnReceive} annotation.
   14.26 + * </li>
   14.27 + * <li><b>websocket</b> - 
   14.28 + *   native browser <a href="http://www.w3.org/TR/websockets/">websockets</a>
   14.29 + *   based implementation for {@link OnReceive} annotation and its <b>WebSocket</b>
   14.30 + *   subprotocol.
   14.31 + * </li>
   14.32 + * </ul>
   14.33   *
   14.34   * @author Jaroslav Tulach
   14.35   * @since 0.7
   14.36   */
   14.37  @ServiceProvider(service = Provider.class)
   14.38  public final class KO4J implements Provider {
   14.39 -    private final Fn.Presenter presenter;
   14.40 -    private FXContext c;
   14.41 +    static final Logger LOG = Logger.getLogger(KOSockets.class.getName());
   14.42 +    private KOTech ko4j;
   14.43 +    private KOTransfer trans;
   14.44 +    private KOSockets socks;
   14.45      
   14.46      public KO4J() {
   14.47          this(null);
   14.48      }
   14.49 -    
   14.50 +
   14.51 +    @Deprecated
   14.52      public KO4J(Fn.Presenter presenter) {
   14.53 -        this.presenter = presenter;
   14.54 -    }
   14.55 -    
   14.56 -    private FXContext getKO() {
   14.57 -        if (c == null) {
   14.58 -            c = new FXContext(presenter == null ? Fn.activePresenter() : presenter);
   14.59 -        }
   14.60 -        return c;
   14.61      }
   14.62      
   14.63      /** Return instance of the knockout.js for Java technology.
   14.64       * @return non-null instance
   14.65       */
   14.66      public Technology knockout() {
   14.67 -        return getKO();
   14.68 +        if (ko4j == null) {
   14.69 +            ko4j = new KOTech();
   14.70 +        }
   14.71 +        return ko4j;
   14.72      }
   14.73      
   14.74      /** Browser based implementation of transfer interface. Uses
   14.75 @@ -91,7 +107,10 @@
   14.76       * @return non-null instance
   14.77       */
   14.78      public Transfer transfer() {
   14.79 -        return getKO();
   14.80 +        if (trans == null) {
   14.81 +            trans = new KOTransfer();
   14.82 +        }
   14.83 +        return trans;
   14.84      }
   14.85      
   14.86      /** Returns browser based implementation of websocket transfer.
   14.87 @@ -102,7 +121,13 @@
   14.88       *   <code>WebSocket</code> object in the browser
   14.89       */
   14.90      public WSTransfer<?> websockets() {
   14.91 -        return getKO().areWebSocketsSupported() ? getKO() : null;
   14.92 +        if (!KOSockets.areWebSocketsSupported()) {
   14.93 +            return null;
   14.94 +        }
   14.95 +        if (socks == null) {
   14.96 +            socks = new KOSockets();
   14.97 +        }
   14.98 +        return socks;
   14.99      }
  14.100  
  14.101      /** Registers technologies at position 100:
    15.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.2 +++ b/ko4j/src/main/java/org/netbeans/html/ko4j/KOSockets.java	Thu Dec 04 09:21:55 2014 +0100
    15.3 @@ -0,0 +1,82 @@
    15.4 +/**
    15.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    15.6 + *
    15.7 + * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
    15.8 + *
    15.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   15.10 + * Other names may be trademarks of their respective owners.
   15.11 + *
   15.12 + * The contents of this file are subject to the terms of either the GNU
   15.13 + * General Public License Version 2 only ("GPL") or the Common
   15.14 + * Development and Distribution License("CDDL") (collectively, the
   15.15 + * "License"). You may not use this file except in compliance with the
   15.16 + * License. You can obtain a copy of the License at
   15.17 + * http://www.netbeans.org/cddl-gplv2.html
   15.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   15.19 + * specific language governing permissions and limitations under the
   15.20 + * License.  When distributing the software, include this License Header
   15.21 + * Notice in each file and include the License file at
   15.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   15.23 + * particular file as subject to the "Classpath" exception as provided
   15.24 + * by Oracle in the GPL Version 2 section of the License file that
   15.25 + * accompanied this code. If applicable, add the following below the
   15.26 + * License Header, with the fields enclosed by brackets [] replaced by
   15.27 + * your own identifying information:
   15.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   15.29 + *
   15.30 + * Contributor(s):
   15.31 + *
   15.32 + * The Original Software is NetBeans. The Initial Developer of the Original
   15.33 + * Software is Oracle. Portions Copyright 2013-2014 Oracle. All Rights Reserved.
   15.34 + *
   15.35 + * If you wish your version of this file to be governed by only the CDDL
   15.36 + * or only the GPL Version 2, indicate your decision by adding
   15.37 + * "[Contributor] elects to include this software in this distribution
   15.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   15.39 + * single choice of license, a recipient has the option to distribute
   15.40 + * your version of this file under either the CDDL, the GPL Version 2 or
   15.41 + * to extend the choice of license to its licensees as provided above.
   15.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   15.43 + * Version 2 license, then the option applies only if the new code is
   15.44 + * made subject to such option by the copyright holder.
   15.45 + */
   15.46 +package org.netbeans.html.ko4j;
   15.47 +
   15.48 +import net.java.html.js.JavaScriptBody;
   15.49 +import org.netbeans.html.context.spi.Contexts;
   15.50 +import org.netbeans.html.json.spi.JSONCall;
   15.51 +import org.netbeans.html.json.spi.WSTransfer;
   15.52 +
   15.53 +/** This is an implementation package - just
   15.54 + * include its JAR on classpath and use official {@link Context} API
   15.55 + * to access the functionality.
   15.56 + * <p>
   15.57 + *
   15.58 + * @author Jaroslav Tulach
   15.59 + */
   15.60 +@Contexts.Id("websocket")
   15.61 +final class KOSockets
   15.62 +implements WSTransfer<LoadWS> {
   15.63 +    KOSockets() {
   15.64 +    }
   15.65 +    
   15.66 +    @Override
   15.67 +    public LoadWS open(String url, JSONCall onReply) {
   15.68 +        return new LoadWS(onReply, url);
   15.69 +    }
   15.70 +
   15.71 +    @Override
   15.72 +    public void send(LoadWS socket, JSONCall data) {
   15.73 +        socket.send(data);
   15.74 +    }
   15.75 +
   15.76 +    @Override
   15.77 +    public void close(LoadWS socket) {
   15.78 +        socket.close();
   15.79 +    }
   15.80 +
   15.81 +    @JavaScriptBody(args = {}, body = "if (window['WebSocket']) return true; else return false;")
   15.82 +    static final boolean areWebSocketsSupported() {
   15.83 +        return false;
   15.84 +    }
   15.85 +}
    16.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.2 +++ b/ko4j/src/main/java/org/netbeans/html/ko4j/KOTech.java	Thu Dec 04 09:21:55 2014 +0100
    16.3 @@ -0,0 +1,144 @@
    16.4 +/**
    16.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    16.6 + *
    16.7 + * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
    16.8 + *
    16.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   16.10 + * Other names may be trademarks of their respective owners.
   16.11 + *
   16.12 + * The contents of this file are subject to the terms of either the GNU
   16.13 + * General Public License Version 2 only ("GPL") or the Common
   16.14 + * Development and Distribution License("CDDL") (collectively, the
   16.15 + * "License"). You may not use this file except in compliance with the
   16.16 + * License. You can obtain a copy of the License at
   16.17 + * http://www.netbeans.org/cddl-gplv2.html
   16.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   16.19 + * specific language governing permissions and limitations under the
   16.20 + * License.  When distributing the software, include this License Header
   16.21 + * Notice in each file and include the License file at
   16.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   16.23 + * particular file as subject to the "Classpath" exception as provided
   16.24 + * by Oracle in the GPL Version 2 section of the License file that
   16.25 + * accompanied this code. If applicable, add the following below the
   16.26 + * License Header, with the fields enclosed by brackets [] replaced by
   16.27 + * your own identifying information:
   16.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   16.29 + *
   16.30 + * Contributor(s):
   16.31 + *
   16.32 + * The Original Software is NetBeans. The Initial Developer of the Original
   16.33 + * Software is Oracle. Portions Copyright 2013-2014 Oracle. All Rights Reserved.
   16.34 + *
   16.35 + * If you wish your version of this file to be governed by only the CDDL
   16.36 + * or only the GPL Version 2, indicate your decision by adding
   16.37 + * "[Contributor] elects to include this software in this distribution
   16.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   16.39 + * single choice of license, a recipient has the option to distribute
   16.40 + * your version of this file under either the CDDL, the GPL Version 2 or
   16.41 + * to extend the choice of license to its licensees as provided above.
   16.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   16.43 + * Version 2 license, then the option applies only if the new code is
   16.44 + * made subject to such option by the copyright holder.
   16.45 + */
   16.46 +package org.netbeans.html.ko4j;
   16.47 +
   16.48 +import org.netbeans.html.context.spi.Contexts;
   16.49 +import org.netbeans.html.json.spi.FunctionBinding;
   16.50 +import org.netbeans.html.json.spi.PropertyBinding;
   16.51 +import org.netbeans.html.json.spi.Technology;
   16.52 +import static org.netbeans.html.ko4j.KO4J.LOG;
   16.53 +
   16.54 +/** This is an implementation package - just
   16.55 + * include its JAR on classpath and use official {@link Context} API
   16.56 + * to access the functionality.
   16.57 + * <p>
   16.58 + *
   16.59 + * @author Jaroslav Tulach
   16.60 + */
   16.61 +@Contexts.Id("ko4j")
   16.62 +final class KOTech
   16.63 +implements Technology.BatchInit<Object>, Technology.ValueMutated<Object> {
   16.64 +    private Object[] jsObjects;
   16.65 +    private int jsIndex;
   16.66 +
   16.67 +    public KOTech() {
   16.68 +    }
   16.69 +    
   16.70 +    @Override
   16.71 +    public Object wrapModel(Object model, PropertyBinding[] propArr, FunctionBinding[] funcArr) {
   16.72 +        String[] propNames = new String[propArr.length];
   16.73 +        boolean[] propReadOnly = new boolean[propArr.length];
   16.74 +        Object[] propValues = new Object[propArr.length];
   16.75 +        for (int i = 0; i < propNames.length; i++) {
   16.76 +            propNames[i] = propArr[i].getPropertyName();
   16.77 +            propReadOnly[i] = propArr[i].isReadOnly();
   16.78 +            propValues[i] = propArr[i].getValue();
   16.79 +        }
   16.80 +        String[] funcNames = new String[funcArr.length];
   16.81 +        for (int i = 0; i < funcNames.length; i++) {
   16.82 +            funcNames[i] = funcArr[i].getFunctionName();
   16.83 +        }
   16.84 +        Object ret = getJSObject();
   16.85 +        Knockout.wrapModel(ret, model, 
   16.86 +            propNames, propReadOnly, propValues, propArr,
   16.87 +            funcNames, funcArr
   16.88 +        );
   16.89 +        return ret;
   16.90 +    }
   16.91 +    
   16.92 +    private Object getJSObject() {
   16.93 +        int len = 64;
   16.94 +        if (jsObjects != null && jsIndex < (len = jsObjects.length)) {
   16.95 +            return jsObjects[jsIndex++];
   16.96 +        }
   16.97 +        jsObjects = Knockout.allocJS(len * 2);
   16.98 +        jsIndex = 1;
   16.99 +        return jsObjects[0];
  16.100 +    }
  16.101 +    
  16.102 +    @Override
  16.103 +    public Object wrapModel(Object model) {
  16.104 +        throw new UnsupportedOperationException();
  16.105 +    }
  16.106 +
  16.107 +    @Override
  16.108 +    public void bind(PropertyBinding b, Object model, Object data) {
  16.109 +        throw new UnsupportedOperationException();
  16.110 +    }
  16.111 +
  16.112 +    @Override
  16.113 +    public void valueHasMutated(Object data, String propertyName) {
  16.114 +        Knockout.valueHasMutated(data, propertyName, null, null);
  16.115 +    }
  16.116 +    
  16.117 +    @Override
  16.118 +    public void valueHasMutated(Object data, String propertyName, Object oldValue, Object newValue) {
  16.119 +        Knockout.valueHasMutated(data, propertyName, oldValue, newValue);
  16.120 +    }
  16.121 +
  16.122 +    @Override
  16.123 +    public void expose(FunctionBinding fb, Object model, Object d) {
  16.124 +        throw new UnsupportedOperationException();
  16.125 +    }
  16.126 +
  16.127 +    @Override
  16.128 +    public void applyBindings(Object data) {
  16.129 +        Knockout.applyBindings(data);
  16.130 +    }
  16.131 +
  16.132 +    @Override
  16.133 +    public Object wrapArray(Object[] arr) {
  16.134 +        return arr;
  16.135 +    }
  16.136 +    
  16.137 +    @Override
  16.138 +    public void runSafe(final Runnable r) {
  16.139 +        LOG.warning("Technology.runSafe has been deprecated. Use BrwsrCtx.execute!");
  16.140 +        r.run();
  16.141 +    }    
  16.142 +
  16.143 +    @Override
  16.144 +    public <M> M toModel(Class<M> modelClass, Object data) {
  16.145 +        return modelClass.cast(Knockout.toModel(data));
  16.146 +    }
  16.147 +}
    17.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    17.2 +++ b/ko4j/src/main/java/org/netbeans/html/ko4j/KOTransfer.java	Thu Dec 04 09:21:55 2014 +0100
    17.3 @@ -0,0 +1,104 @@
    17.4 +/**
    17.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    17.6 + *
    17.7 + * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
    17.8 + *
    17.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   17.10 + * Other names may be trademarks of their respective owners.
   17.11 + *
   17.12 + * The contents of this file are subject to the terms of either the GNU
   17.13 + * General Public License Version 2 only ("GPL") or the Common
   17.14 + * Development and Distribution License("CDDL") (collectively, the
   17.15 + * "License"). You may not use this file except in compliance with the
   17.16 + * License. You can obtain a copy of the License at
   17.17 + * http://www.netbeans.org/cddl-gplv2.html
   17.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   17.19 + * specific language governing permissions and limitations under the
   17.20 + * License.  When distributing the software, include this License Header
   17.21 + * Notice in each file and include the License file at
   17.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   17.23 + * particular file as subject to the "Classpath" exception as provided
   17.24 + * by Oracle in the GPL Version 2 section of the License file that
   17.25 + * accompanied this code. If applicable, add the following below the
   17.26 + * License Header, with the fields enclosed by brackets [] replaced by
   17.27 + * your own identifying information:
   17.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   17.29 + *
   17.30 + * Contributor(s):
   17.31 + *
   17.32 + * The Original Software is NetBeans. The Initial Developer of the Original
   17.33 + * Software is Oracle. Portions Copyright 2013-2014 Oracle. All Rights Reserved.
   17.34 + *
   17.35 + * If you wish your version of this file to be governed by only the CDDL
   17.36 + * or only the GPL Version 2, indicate your decision by adding
   17.37 + * "[Contributor] elects to include this software in this distribution
   17.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   17.39 + * single choice of license, a recipient has the option to distribute
   17.40 + * your version of this file under either the CDDL, the GPL Version 2 or
   17.41 + * to extend the choice of license to its licensees as provided above.
   17.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   17.43 + * Version 2 license, then the option applies only if the new code is
   17.44 + * made subject to such option by the copyright holder.
   17.45 + */
   17.46 +package org.netbeans.html.ko4j;
   17.47 +
   17.48 +import java.io.ByteArrayOutputStream;
   17.49 +import java.io.IOException;
   17.50 +import java.io.InputStream;
   17.51 +import java.io.InputStreamReader;
   17.52 +import org.netbeans.html.context.spi.Contexts;
   17.53 +import org.netbeans.html.json.spi.JSONCall;
   17.54 +import org.netbeans.html.json.spi.Transfer;
   17.55 +
   17.56 +/** This is an implementation package - just
   17.57 + * include its JAR on classpath and use official {@link Context} API
   17.58 + * to access the functionality.
   17.59 + * <p>
   17.60 + *
   17.61 + * @author Jaroslav Tulach
   17.62 + */
   17.63 +@Contexts.Id("xhr")
   17.64 +final class KOTransfer
   17.65 +implements Transfer {
   17.66 +    KOTransfer() {
   17.67 +    }
   17.68 +    
   17.69 +    @Override
   17.70 +    public void extract(Object obj, String[] props, Object[] values) {
   17.71 +        LoadJSON.extractJSON(obj, props, values);
   17.72 +    }
   17.73 +
   17.74 +    @Override
   17.75 +    public void loadJSON(final JSONCall call) {
   17.76 +        if (call.isJSONP()) {
   17.77 +            String me = LoadJSON.createJSONP(call);
   17.78 +            LoadJSON.loadJSONP(call.composeURL(me), me);
   17.79 +        } else {
   17.80 +            String data = null;
   17.81 +            if (call.isDoOutput()) {
   17.82 +                try {
   17.83 +                    ByteArrayOutputStream bos = new ByteArrayOutputStream();
   17.84 +                    call.writeData(bos);
   17.85 +                    data = new String(bos.toByteArray(), "UTF-8");
   17.86 +                } catch (IOException ex) {
   17.87 +                    call.notifyError(ex);
   17.88 +                }
   17.89 +            }
   17.90 +            LoadJSON.loadJSON(call.composeURL(null), call, call.getMethod(), data);
   17.91 +        }
   17.92 +    }
   17.93 +
   17.94 +    @Override
   17.95 +    public Object toJSON(InputStream is) throws IOException {
   17.96 +        StringBuilder sb = new StringBuilder();
   17.97 +        InputStreamReader r = new InputStreamReader(is);
   17.98 +        for (;;) {
   17.99 +            int ch = r.read();
  17.100 +            if (ch == -1) {
  17.101 +                break;
  17.102 +            }
  17.103 +            sb.append((char)ch);
  17.104 +        }
  17.105 +        return LoadJSON.parse(sb.toString());
  17.106 +    }
  17.107 +}
    18.1 --- a/ko4j/src/main/java/org/netbeans/html/ko4j/Knockout.java	Wed Dec 03 11:41:24 2014 +0100
    18.2 +++ b/ko4j/src/main/java/org/netbeans/html/ko4j/Knockout.java	Thu Dec 04 09:21:55 2014 +0100
    18.3 @@ -153,9 +153,4 @@
    18.4      static Object toModel(Object wrapper) {
    18.5          return toModelImpl(wrapper);
    18.6      }
    18.7 -    
    18.8 -    @JavaScriptBody(args = {}, body = "if (window['WebSocket']) return true; else return false;")
    18.9 -    static final boolean areWebSocketsSupported() {
   18.10 -        return false;
   18.11 -    }
   18.12  }
    19.1 --- a/ko4j/src/test/java/org/netbeans/html/ko4j/KnockoutFXTest.java	Wed Dec 03 11:41:24 2014 +0100
    19.2 +++ b/ko4j/src/test/java/org/netbeans/html/ko4j/KnockoutFXTest.java	Thu Dec 04 09:21:55 2014 +0100
    19.3 @@ -66,7 +66,6 @@
    19.4  import org.netbeans.html.json.spi.WSTransfer;
    19.5  import org.netbeans.html.json.tck.KOTest;
    19.6  import org.netbeans.html.json.tck.KnockoutTCK;
    19.7 -import org.netbeans.html.boot.impl.FnContext;
    19.8  import org.openide.util.lookup.ServiceProvider;
    19.9  import org.testng.Assert;
   19.10  import static org.testng.Assert.*;
   19.11 @@ -154,12 +153,12 @@
   19.12      
   19.13      @Override
   19.14      public BrwsrCtx createContext() {
   19.15 -        FXContext fx = new FXContext(browserContext);
   19.16 +        KO4J ko4j = new KO4J();
   19.17          Contexts.Builder cb = Contexts.newBuilder().
   19.18 -            register(Technology.class, fx, 10).
   19.19 -            register(Transfer.class, fx, 10);
   19.20 -        if (fx.areWebSocketsSupported()) {
   19.21 -            cb.register(WSTransfer.class, fx, 10);
   19.22 +            register(Technology.class, ko4j.knockout(), 10).
   19.23 +            register(Transfer.class, ko4j.transfer(), 10);
   19.24 +        if (ko4j.websockets() != null) {
   19.25 +            cb.register(WSTransfer.class, ko4j.websockets(), 10);
   19.26          }
   19.27          cb.register(Executor.class, (Executor)browserContext, 10);
   19.28          cb.register(Fn.Presenter.class, browserContext, 10);
    20.1 --- a/src/main/javadoc/overview.html	Wed Dec 03 11:41:24 2014 +0100
    20.2 +++ b/src/main/javadoc/overview.html	Thu Dec 04 09:21:55 2014 +0100
    20.3 @@ -75,6 +75,27 @@
    20.4           yet the application code can be written in Java.
    20.5          </p>
    20.6          
    20.7 +        <h3>What's New in Version 1.1?</h3>
    20.8 +        
    20.9 +        <p>
   20.10 +            The content of a {@link net.java.html.BrwsrCtx context}
   20.11 +            can be selected by registering implementations under specific
   20.12 +            {@link org.netbeans.html.context.spi.Contexts.Id technology identifiers} 
   20.13 +            and requesting them during 
   20.14 +            {@link org.netbeans.html.context.spi.Contexts#newBuilder(java.lang.Object...) construction} 
   20.15 +            of the context. <code>org.netbeans.html:ko4j</code> module's implementation
   20.16 +            offers <b>ko4j</b>, <b>xhr</b> and <b>websocket</b> identifiers
   20.17 +            for its registered services 
   20.18 +            (e.g. {@link org.netbeans.html.json.spi.Technology},
   20.19 +            {@link org.netbeans.html.json.spi.Transfer} and
   20.20 +            {@link org.netbeans.html.json.spi.WSTransfer}).
   20.21 +            <code>org.netbeans.html:ko-ws-tyrus</code>
   20.22 +            module registers its 
   20.23 +            {@link org.netbeans.html.json.spi.Transfer Java based JSON} and 
   20.24 +            {@link org.netbeans.html.json.spi.WSTransfer WebSocket} implementations
   20.25 +            under the name <b>tyrus</b>.
   20.26 +        </p>
   20.27 +        
   20.28          <h3>What's New in Version 1.0?</h3>
   20.29          
   20.30          <p>