Bringing the most recent changes in default branch to gc gc
authorJaroslav Tulach <jtulach@netbeans.org>
Tue, 09 Dec 2014 08:33:22 +0100
branchgc
changeset 892de02b7c13379
parent 890 5bea583947da
parent 889 548982033730
child 893 6bccaa2a63ec
Bringing the most recent changes in default branch to gc
json-tck/src/main/java/org/netbeans/html/json/tck/KnockoutTCK.java
ko4j/src/main/java/org/netbeans/html/ko4j/FXContext.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
pom.xml
src/main/javadoc/overview.html
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/boot-agent-test/pom.xml	Tue Dec 09 08:33:22 2014 +0100
     1.3 @@ -0,0 +1,61 @@
     1.4 +<?xml version="1.0" encoding="UTF-8"?>
     1.5 +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     1.6 +    <modelVersion>4.0.0</modelVersion>
     1.7 +    <parent>
     1.8 +        <groupId>org.netbeans.html</groupId>
     1.9 +        <artifactId>pom</artifactId>
    1.10 +        <version>2.0-SNAPSHOT</version>
    1.11 +    </parent>
    1.12 +    <artifactId>boot-agent-test</artifactId>
    1.13 +    <packaging>jar</packaging>
    1.14 +    <name>Dynamic Boot Test</name>
    1.15 +    <build>
    1.16 +        <plugins>
    1.17 +            <plugin>
    1.18 +                <groupId>org.apache.maven.plugins</groupId>
    1.19 +                <artifactId>maven-deploy-plugin</artifactId>
    1.20 +                <configuration>
    1.21 +                    <skip>true</skip>
    1.22 +                </configuration>
    1.23 +            </plugin>
    1.24 +        </plugins>
    1.25 +    </build>
    1.26 +    <dependencies>
    1.27 +        <dependency>
    1.28 +            <groupId>org.testng</groupId>
    1.29 +            <artifactId>testng</artifactId>
    1.30 +            <scope>test</scope>
    1.31 +        </dependency>
    1.32 +        <dependency>
    1.33 +            <groupId>org.netbeans.html</groupId>
    1.34 +            <artifactId>net.java.html</artifactId>
    1.35 +            <version>${project.version}</version>
    1.36 +            <scope>test</scope>
    1.37 +            <type>jar</type>
    1.38 +        </dependency>
    1.39 +        <dependency>
    1.40 +            <groupId>org.netbeans.html</groupId>
    1.41 +            <artifactId>net.java.html.boot</artifactId>
    1.42 +            <version>${project.version}</version>
    1.43 +            <scope>test</scope>
    1.44 +            <type>jar</type>
    1.45 +        </dependency>
    1.46 +        <dependency>
    1.47 +            <groupId>org.netbeans.api</groupId>
    1.48 +            <artifactId>org-openide-util-lookup</artifactId>
    1.49 +            <scope>test</scope>
    1.50 +            <type>jar</type>
    1.51 +        </dependency>
    1.52 +        <dependency>
    1.53 +            <groupId>${project.groupId}</groupId>
    1.54 +            <artifactId>net.java.html.boot.fx</artifactId>
    1.55 +            <version>${project.version}</version>
    1.56 +            <scope>test</scope>
    1.57 +        </dependency>
    1.58 +        <dependency>
    1.59 +            <groupId>org.ow2.asm</groupId>
    1.60 +            <artifactId>asm</artifactId>
    1.61 +            <scope>test</scope>
    1.62 +        </dependency>
    1.63 +    </dependencies>
    1.64 +</project>
    1.65 \ No newline at end of file
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/boot-agent-test/src/test/java/org/netbeans/html/bootagent/DynamicClassLoaderTest.java	Tue Dec 09 08:33:22 2014 +0100
     2.3 @@ -0,0 +1,126 @@
     2.4 +/**
     2.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     2.6 + *
     2.7 + * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
     2.8 + *
     2.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
    2.10 + * Other names may be trademarks of their respective owners.
    2.11 + *
    2.12 + * The contents of this file are subject to the terms of either the GNU
    2.13 + * General Public License Version 2 only ("GPL") or the Common
    2.14 + * Development and Distribution License("CDDL") (collectively, the
    2.15 + * "License"). You may not use this file except in compliance with the
    2.16 + * License. You can obtain a copy of the License at
    2.17 + * http://www.netbeans.org/cddl-gplv2.html
    2.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
    2.19 + * specific language governing permissions and limitations under the
    2.20 + * License.  When distributing the software, include this License Header
    2.21 + * Notice in each file and include the License file at
    2.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
    2.23 + * particular file as subject to the "Classpath" exception as provided
    2.24 + * by Oracle in the GPL Version 2 section of the License file that
    2.25 + * accompanied this code. If applicable, add the following below the
    2.26 + * License Header, with the fields enclosed by brackets [] replaced by
    2.27 + * your own identifying information:
    2.28 + * "Portions Copyrighted [year] [name of copyright owner]"
    2.29 + *
    2.30 + * Contributor(s):
    2.31 + *
    2.32 + * The Original Software is NetBeans. The Initial Developer of the Original
    2.33 + * Software is Oracle. Portions Copyright 2013-2014 Oracle. All Rights Reserved.
    2.34 + *
    2.35 + * If you wish your version of this file to be governed by only the CDDL
    2.36 + * or only the GPL Version 2, indicate your decision by adding
    2.37 + * "[Contributor] elects to include this software in this distribution
    2.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
    2.39 + * single choice of license, a recipient has the option to distribute
    2.40 + * your version of this file under either the CDDL, the GPL Version 2 or
    2.41 + * to extend the choice of license to its licensees as provided above.
    2.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
    2.43 + * Version 2 license, then the option applies only if the new code is
    2.44 + * made subject to such option by the copyright holder.
    2.45 + */
    2.46 +package org.netbeans.html.bootagent;
    2.47 +
    2.48 +import java.lang.reflect.Field;
    2.49 +import java.lang.reflect.Method;
    2.50 +import java.lang.reflect.Modifier;
    2.51 +import java.util.ArrayList;
    2.52 +import java.util.List;
    2.53 +import java.util.concurrent.Executors;
    2.54 +import net.java.html.BrwsrCtx;
    2.55 +import net.java.html.boot.BrowserBuilder;
    2.56 +import org.netbeans.html.boot.spi.Fn;
    2.57 +import org.testng.Assert;
    2.58 +import static org.testng.Assert.assertNotSame;
    2.59 +import static org.testng.Assert.assertSame;
    2.60 +import org.testng.annotations.Factory;
    2.61 +
    2.62 +/**
    2.63 + *
    2.64 + * @author Jaroslav Tulach
    2.65 + */
    2.66 +public class DynamicClassLoaderTest {
    2.67 +    private static Class<?> browserClass;
    2.68 +    private static Fn.Presenter browserPresenter;
    2.69 +    
    2.70 +    public DynamicClassLoaderTest() {
    2.71 +    }
    2.72 +
    2.73 +    @Factory public static Object[] compatibilityTests() throws Exception {
    2.74 +        final BrowserBuilder bb = BrowserBuilder.newBrowser().loadClass(DynamicClassLoaderTest.class).
    2.75 +            loadPage("empty.html").
    2.76 +            invoke("initialized");
    2.77 +
    2.78 +        Executors.newSingleThreadExecutor().submit(new Runnable() {
    2.79 +            @Override
    2.80 +            public void run() {
    2.81 +                bb.showAndWait();
    2.82 +            }
    2.83 +        });
    2.84 +
    2.85 +        List<Object> res = new ArrayList<Object>();
    2.86 +
    2.87 +        Class[] arr = new Class[] { loadClass() };
    2.88 +        for (Class c : arr) {
    2.89 +            for (Method m : c.getDeclaredMethods()) {
    2.90 +                if ((m.getModifiers() & Modifier.PUBLIC) != 0) {
    2.91 +                    res.add(new KOFx(browserPresenter, m));
    2.92 +                }
    2.93 +            }
    2.94 +        }
    2.95 +        return res.toArray();
    2.96 +    }
    2.97 +
    2.98 +    static synchronized Class<?> loadClass() throws InterruptedException {
    2.99 +        while (browserClass == null) {
   2.100 +            DynamicClassLoaderTest.class.wait();
   2.101 +        }
   2.102 +        return browserClass;
   2.103 +    }
   2.104 +    
   2.105 +    public static void ready(Class<?> browserCls) throws Exception {
   2.106 +        Class<?> origClazz = ClassLoader.getSystemClassLoader().loadClass(DynamicClassLoaderTest.class.getName());
   2.107 +        final Field f1 = origClazz.getDeclaredField("browserClass");
   2.108 +        f1.setAccessible(true);
   2.109 +        f1.set(null, browserCls);
   2.110 +        final Field f2 = origClazz.getDeclaredField("browserPresenter");
   2.111 +        f2.setAccessible(true);
   2.112 +        f2.set(null, Fn.activePresenter());
   2.113 +        synchronized (origClazz) {
   2.114 +            origClazz.notifyAll();
   2.115 +        }
   2.116 +    }
   2.117 +    
   2.118 +    public static void initialized() throws Exception {
   2.119 +        BrwsrCtx b1 = BrwsrCtx.findDefault(DynamicClassLoaderTest.class);
   2.120 +        assertNotSame(b1, BrwsrCtx.EMPTY, "Browser context is not empty");
   2.121 +        BrwsrCtx b2 = BrwsrCtx.findDefault(DynamicClassLoaderTest.class);
   2.122 +        assertSame(b1, b2, "Browser context remains stable");
   2.123 +        Assert.assertNotSame(DynamicClassLoaderTest.class.getClassLoader(),
   2.124 +            ClassLoader.getSystemClassLoader(),
   2.125 +            "Should use special classloader, not system one"
   2.126 +        );
   2.127 +        DynamicClassLoaderTest.ready(JavaScriptBodyTst.class);
   2.128 +    }
   2.129 +}
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/boot-agent-test/src/test/java/org/netbeans/html/bootagent/JavaScriptBodyTst.java	Tue Dec 09 08:33:22 2014 +0100
     3.3 @@ -0,0 +1,63 @@
     3.4 +/**
     3.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     3.6 + *
     3.7 + * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
     3.8 + *
     3.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
    3.10 + * Other names may be trademarks of their respective owners.
    3.11 + *
    3.12 + * The contents of this file are subject to the terms of either the GNU
    3.13 + * General Public License Version 2 only ("GPL") or the Common
    3.14 + * Development and Distribution License("CDDL") (collectively, the
    3.15 + * "License"). You may not use this file except in compliance with the
    3.16 + * License. You can obtain a copy of the License at
    3.17 + * http://www.netbeans.org/cddl-gplv2.html
    3.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
    3.19 + * specific language governing permissions and limitations under the
    3.20 + * License.  When distributing the software, include this License Header
    3.21 + * Notice in each file and include the License file at
    3.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
    3.23 + * particular file as subject to the "Classpath" exception as provided
    3.24 + * by Oracle in the GPL Version 2 section of the License file that
    3.25 + * accompanied this code. If applicable, add the following below the
    3.26 + * License Header, with the fields enclosed by brackets [] replaced by
    3.27 + * your own identifying information:
    3.28 + * "Portions Copyrighted [year] [name of copyright owner]"
    3.29 + *
    3.30 + * Contributor(s):
    3.31 + *
    3.32 + * The Original Software is NetBeans. The Initial Developer of the Original
    3.33 + * Software is Oracle. Portions Copyright 2013-2014 Oracle. All Rights Reserved.
    3.34 + *
    3.35 + * If you wish your version of this file to be governed by only the CDDL
    3.36 + * or only the GPL Version 2, indicate your decision by adding
    3.37 + * "[Contributor] elects to include this software in this distribution
    3.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
    3.39 + * single choice of license, a recipient has the option to distribute
    3.40 + * your version of this file under either the CDDL, the GPL Version 2 or
    3.41 + * to extend the choice of license to its licensees as provided above.
    3.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
    3.43 + * Version 2 license, then the option applies only if the new code is
    3.44 + * made subject to such option by the copyright holder.
    3.45 + */
    3.46 +package org.netbeans.html.bootagent;
    3.47 +
    3.48 +import net.java.html.js.JavaScriptBody;
    3.49 +
    3.50 +/**
    3.51 + *
    3.52 + * @author Jaroslav Tulach
    3.53 + */
    3.54 +public class JavaScriptBodyTst {
    3.55 +    
    3.56 +    public JavaScriptBodyTst() {
    3.57 +    }
    3.58 +
    3.59 +    public void assert42() {
    3.60 +        int v = mul(7, 6);
    3.61 +        assert v == 42 : "Really 42: " + v;
    3.62 +    }
    3.63 +    
    3.64 +    @JavaScriptBody(args = { "x", "y" }, body = "return x * y;")
    3.65 +    private static native int mul(int x, int y);
    3.66 +}
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/boot-agent-test/src/test/java/org/netbeans/html/bootagent/KOFx.java	Tue Dec 09 08:33:22 2014 +0100
     4.3 @@ -0,0 +1,125 @@
     4.4 +/**
     4.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     4.6 + *
     4.7 + * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
     4.8 + *
     4.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
    4.10 + * Other names may be trademarks of their respective owners.
    4.11 + *
    4.12 + * The contents of this file are subject to the terms of either the GNU
    4.13 + * General Public License Version 2 only ("GPL") or the Common
    4.14 + * Development and Distribution License("CDDL") (collectively, the
    4.15 + * "License"). You may not use this file except in compliance with the
    4.16 + * License. You can obtain a copy of the License at
    4.17 + * http://www.netbeans.org/cddl-gplv2.html
    4.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
    4.19 + * specific language governing permissions and limitations under the
    4.20 + * License.  When distributing the software, include this License Header
    4.21 + * Notice in each file and include the License file at
    4.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
    4.23 + * particular file as subject to the "Classpath" exception as provided
    4.24 + * by Oracle in the GPL Version 2 section of the License file that
    4.25 + * accompanied this code. If applicable, add the following below the
    4.26 + * License Header, with the fields enclosed by brackets [] replaced by
    4.27 + * your own identifying information:
    4.28 + * "Portions Copyrighted [year] [name of copyright owner]"
    4.29 + *
    4.30 + * Contributor(s):
    4.31 + *
    4.32 + * The Original Software is NetBeans. The Initial Developer of the Original
    4.33 + * Software is Oracle. Portions Copyright 2013-2014 Oracle. All Rights Reserved.
    4.34 + *
    4.35 + * If you wish your version of this file to be governed by only the CDDL
    4.36 + * or only the GPL Version 2, indicate your decision by adding
    4.37 + * "[Contributor] elects to include this software in this distribution
    4.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
    4.39 + * single choice of license, a recipient has the option to distribute
    4.40 + * your version of this file under either the CDDL, the GPL Version 2 or
    4.41 + * to extend the choice of license to its licensees as provided above.
    4.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
    4.43 + * Version 2 license, then the option applies only if the new code is
    4.44 + * made subject to such option by the copyright holder.
    4.45 + */
    4.46 +package org.netbeans.html.bootagent;
    4.47 +
    4.48 +import java.lang.reflect.InvocationTargetException;
    4.49 +import java.lang.reflect.Method;
    4.50 +import javafx.application.Platform;
    4.51 +import org.netbeans.html.boot.impl.FnContext;
    4.52 +import org.netbeans.html.boot.spi.Fn;
    4.53 +import org.testng.IHookCallBack;
    4.54 +import org.testng.IHookable;
    4.55 +import org.testng.ITest;
    4.56 +import org.testng.ITestResult;
    4.57 +import org.testng.annotations.Test;
    4.58 +
    4.59 +/**
    4.60 + *
    4.61 + * @author Jaroslav Tulach
    4.62 + */
    4.63 +public final class KOFx implements ITest, IHookable, Runnable {
    4.64 +    private final Fn.Presenter p;
    4.65 +    private final Method m;
    4.66 +    private Object result;
    4.67 +    private Object inst;
    4.68 +
    4.69 +    KOFx(Fn.Presenter p, Method m) {
    4.70 +        this.p = p;
    4.71 +        this.m = m;
    4.72 +    }
    4.73 +
    4.74 +    @Override
    4.75 +    public String getTestName() {
    4.76 +        return m.getName();
    4.77 +    }
    4.78 +
    4.79 +    @Test
    4.80 +    public synchronized void executeTest() throws Exception {
    4.81 +        if (result == null) {
    4.82 +            Platform.runLater(this);
    4.83 +            wait();
    4.84 +        }
    4.85 +        if (result instanceof Exception) {
    4.86 +            throw (Exception)result;
    4.87 +        }
    4.88 +        if (result instanceof Error) {
    4.89 +            throw (Error)result;
    4.90 +        }
    4.91 +    }
    4.92 +
    4.93 +    @Override
    4.94 +    public synchronized void run() {
    4.95 +        boolean notify = true;
    4.96 +        try {
    4.97 +            FnContext.currentPresenter(p);
    4.98 +            if (inst == null) {
    4.99 +                inst = m.getDeclaringClass().newInstance();
   4.100 +            }
   4.101 +            result = m.invoke(inst);
   4.102 +            if (result == null) {
   4.103 +                result = this;
   4.104 +            }
   4.105 +        } catch (InvocationTargetException ex) {
   4.106 +            Throwable r = ex.getTargetException();
   4.107 +            if (r instanceof InterruptedException) {
   4.108 +                notify = false;
   4.109 +                Platform.runLater(this);
   4.110 +                return;
   4.111 +            }
   4.112 +            result = r;
   4.113 +        } catch (Exception ex) {
   4.114 +            result = ex;
   4.115 +        } finally {
   4.116 +            if (notify) {
   4.117 +                notifyAll();
   4.118 +            }
   4.119 +            FnContext.currentPresenter(null);
   4.120 +        }
   4.121 +    }
   4.122 +
   4.123 +    @Override
   4.124 +    public void run(IHookCallBack ihcb, ITestResult itr) {
   4.125 +        ihcb.runTestMethod(itr);
   4.126 +    }
   4.127 +    
   4.128 +}
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/boot-agent-test/src/test/resources/org/netbeans/html/bootagent/empty.html	Tue Dec 09 08:33:22 2014 +0100
     5.3 @@ -0,0 +1,55 @@
     5.4 +<!--
     5.5 +
     5.6 +    DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     5.7 +
     5.8 +    Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
     5.9 +
    5.10 +    Oracle and Java are registered trademarks of Oracle and/or its affiliates.
    5.11 +    Other names may be trademarks of their respective owners.
    5.12 +
    5.13 +    The contents of this file are subject to the terms of either the GNU
    5.14 +    General Public License Version 2 only ("GPL") or the Common
    5.15 +    Development and Distribution License("CDDL") (collectively, the
    5.16 +    "License"). You may not use this file except in compliance with the
    5.17 +    License. You can obtain a copy of the License at
    5.18 +    http://www.netbeans.org/cddl-gplv2.html
    5.19 +    or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
    5.20 +    specific language governing permissions and limitations under the
    5.21 +    License.  When distributing the software, include this License Header
    5.22 +    Notice in each file and include the License file at
    5.23 +    nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
    5.24 +    particular file as subject to the "Classpath" exception as provided
    5.25 +    by Oracle in the GPL Version 2 section of the License file that
    5.26 +    accompanied this code. If applicable, add the following below the
    5.27 +    License Header, with the fields enclosed by brackets [] replaced by
    5.28 +    your own identifying information:
    5.29 +    "Portions Copyrighted [year] [name of copyright owner]"
    5.30 +
    5.31 +    Contributor(s):
    5.32 +
    5.33 +    The Original Software is NetBeans. The Initial Developer of the Original
    5.34 +    Software is Oracle. Portions Copyright 2013-2014 Oracle. All Rights Reserved.
    5.35 +
    5.36 +    If you wish your version of this file to be governed by only the CDDL
    5.37 +    or only the GPL Version 2, indicate your decision by adding
    5.38 +    "[Contributor] elects to include this software in this distribution
    5.39 +    under the [CDDL or GPL Version 2] license." If you do not indicate a
    5.40 +    single choice of license, a recipient has the option to distribute
    5.41 +    your version of this file under either the CDDL, the GPL Version 2 or
    5.42 +    to extend the choice of license to its licensees as provided above.
    5.43 +    However, if you add GPL Version 2 code and therefore, elected the GPL
    5.44 +    Version 2 license, then the option applies only if the new code is
    5.45 +    made subject to such option by the copyright holder.
    5.46 +
    5.47 +-->
    5.48 +<!DOCTYPE html>
    5.49 +<html>
    5.50 +    <head>
    5.51 +        <title>Bootstrap Dynamically</title>
    5.52 +        <meta charset="UTF-8">
    5.53 +        <meta name="viewport" content="width=device-width, initial-scale=1.0">
    5.54 +    </head>
    5.55 +    <body>
    5.56 +        <div>Bootstrap Dynamically</div>
    5.57 +    </body>
    5.58 +</html>
     6.1 --- a/boot-fx/src/main/java/net/java/html/boot/fx/FXBrowsers.java	Tue Dec 09 07:23:22 2014 +0100
     6.2 +++ b/boot-fx/src/main/java/net/java/html/boot/fx/FXBrowsers.java	Tue Dec 09 08:33:22 2014 +0100
     6.3 @@ -52,6 +52,8 @@
     6.4  import net.java.html.boot.BrowserBuilder;
     6.5  import net.java.html.js.JavaScriptBody;
     6.6  import org.netbeans.html.boot.fx.AbstractFXPresenter;
     6.7 +import org.netbeans.html.context.spi.Contexts;
     6.8 +import org.netbeans.html.context.spi.Contexts.Id;
     6.9  
    6.10  /** Utility methods to use {@link WebView} and {@link JavaScriptBody} code
    6.11   * in existing <em>JavaFX</em> applications.
    6.12 @@ -82,6 +84,16 @@
    6.13       * <p>
    6.14       * This method sets {@link WebView#getUserData()} and {@link #runInBrowser(javafx.scene.web.WebView, java.lang.Runnable)}
    6.15       * relies on the value. Please don't alter it.
    6.16 +     * <p>
    6.17 +     * Since introduction of {@link Id technology identifiers} the 
    6.18 +     * provided <code>args</code> strings are also passed to the 
    6.19 +     * {@link BrwsrCtx context} when it is being 
    6.20 +     * {@link Contexts#newBuilder(java.lang.Object...) created}
    6.21 +     * and can influence the selection
    6.22 +     * of available technologies 
    6.23 +     * (like {@link org.netbeans.html.json.spi.Technology},
    6.24 +     * {@link org.netbeans.html.json.spi.Transfer} or
    6.25 +     * {@link org.netbeans.html.json.spi.WSTransfer}).
    6.26       * 
    6.27       * @param webView the instance of Web View to tweak
    6.28       * @param url the URL of the HTML page to load into the view
    6.29 @@ -94,7 +106,10 @@
    6.30          Class<?> onPageLoad, String methodName,
    6.31          String... args
    6.32      ) {
    6.33 -        BrowserBuilder.newBrowser(new Load(webView)).
    6.34 +        Object[] context = new Object[args.length + 1];
    6.35 +        System.arraycopy(args, 0, context, 1, args.length);
    6.36 +        context[0] = new Load(webView);
    6.37 +        BrowserBuilder.newBrowser(context).
    6.38              loadPage(url.toExternalForm()).
    6.39              loadClass(onPageLoad).
    6.40              invoke(methodName, args).
    6.41 @@ -126,8 +141,8 @@
    6.42      
    6.43      /** Enables the Java/JavaScript bridge (that supports {@link JavaScriptBody} and co.)
    6.44       * in the provided <code>webView</code>. This method returns 
    6.45 -     * immediately. Once the support is active, it calls back specified
    6.46 -     * method in <code>onPageLoad</code>'s run method. 
    6.47 +     * immediately. Once the support is active, it calls back {@link Runnable#run() run}
    6.48 +     * method in <code>onPageLoad</code>. 
    6.49       * This is more convenient way to initialize the webview, 
    6.50       * but it requires one to make sure
    6.51       * all {@link JavaScriptBody} methods has been post-processed during
    6.52 @@ -145,7 +160,37 @@
    6.53      public static void load(
    6.54          WebView webView, final URL url, Runnable onPageLoad, ClassLoader loader
    6.55      ) {
    6.56 -        BrowserBuilder.newBrowser(new Load(webView)).
    6.57 +        load(webView, url, onPageLoad, loader, new Object[0]);
    6.58 +    }
    6.59 +    
    6.60 +    /** Enables the Java/JavaScript bridge (that supports {@link JavaScriptBody} and co.)
    6.61 +     * in the provided <code>webView</code>. This method returns 
    6.62 +     * immediately. Once the support is active, it calls back {@link Runnable#run() run}
    6.63 +     * method in <code>onPageLoad</code>. 
    6.64 +     * This is more convenient way to initialize the webview, 
    6.65 +     * but it requires one to make sure
    6.66 +     * all {@link JavaScriptBody} methods has been post-processed during
    6.67 +     * compilation and there will be no need to instantiate new classloader.
    6.68 +     * <p>
    6.69 +     * This method sets {@link WebView#getUserData()} and {@link #runInBrowser(javafx.scene.web.WebView, java.lang.Runnable)}
    6.70 +     * relies on the value. Please don't alter it.
    6.71 +     * 
    6.72 +     * @param webView the instance of Web View to tweak
    6.73 +     * @param url the URL of the HTML page to load into the view
    6.74 +     * @param onPageLoad callback to call when the page is ready
    6.75 +     * @param loader the loader to use when constructing initial {@link BrwsrCtx} or <code>null</code>
    6.76 +     * @param context additonal configuration to pass to {@link BrowserBuilder#newBrowser(java.lang.Object...)}
    6.77 +     *   and {@link Contexts#newBuilder(java.lang.Object...)} factory methods 
    6.78 +     * @since 1.1
    6.79 +     */
    6.80 +    public static void load(
    6.81 +        WebView webView, final URL url, Runnable onPageLoad, ClassLoader loader,
    6.82 +        Object... context
    6.83 +    ) {
    6.84 +        Object[] newCtx = new Object[context.length + 1];
    6.85 +        System.arraycopy(context, 0, newCtx, 1, context.length);
    6.86 +        newCtx[0] = new Load(webView);
    6.87 +        BrowserBuilder.newBrowser(newCtx).
    6.88                  loadPage(url.toExternalForm()).
    6.89                  loadFinished(onPageLoad).
    6.90                  classloader(loader).
     7.1 --- a/boot-fx/src/main/java/org/netbeans/html/boot/fx/FXToolbar.java	Tue Dec 09 07:23:22 2014 +0100
     7.2 +++ b/boot-fx/src/main/java/org/netbeans/html/boot/fx/FXToolbar.java	Tue Dec 09 08:33:22 2014 +0100
     7.3 @@ -42,8 +42,6 @@
     7.4   */
     7.5  package org.netbeans.html.boot.fx;
     7.6  
     7.7 -import java.io.IOException;
     7.8 -import java.net.URISyntaxException;
     7.9  import java.util.ArrayList;
    7.10  import java.util.List;
    7.11  import java.util.logging.Level;
    7.12 @@ -55,10 +53,11 @@
    7.13  import javafx.collections.FXCollections;
    7.14  import javafx.event.ActionEvent;
    7.15  import javafx.event.EventHandler;
    7.16 +import javafx.scene.Group;
    7.17 +import javafx.scene.Scene;
    7.18  import javafx.scene.control.Button;
    7.19  import javafx.scene.control.CheckBox;
    7.20  import javafx.scene.control.ComboBox;
    7.21 -import javafx.scene.control.ScrollPane;
    7.22  import javafx.scene.control.Separator;
    7.23  import javafx.scene.control.Toggle;
    7.24  import javafx.scene.control.ToggleButton;
    7.25 @@ -69,6 +68,9 @@
    7.26  import javafx.scene.image.ImageView;
    7.27  import javafx.scene.layout.BorderPane;
    7.28  import javafx.scene.web.WebView;
    7.29 +import javafx.stage.Screen;
    7.30 +import javafx.stage.Stage;
    7.31 +import javafx.stage.Window;
    7.32  
    7.33  final class FXToolbar extends ToolBar {
    7.34      private final ArrayList<ResizeBtn> resizeButtons;
    7.35 @@ -185,21 +187,25 @@
    7.36  
    7.37      }
    7.38  
    7.39 -    private void _resize( final double width, final double height ) {
    7.40 -        ScrollPane scroll;
    7.41 -        if (container.getCenter() == webView) {
    7.42 -            scroll = new ScrollPane();
    7.43 -            scroll.setContent(webView);
    7.44 -            container.setCenter(scroll);
    7.45 -        } else {
    7.46 -            scroll = (ScrollPane) container.getCenter();
    7.47 -        }
    7.48 -        scroll.setPrefViewportWidth( width );
    7.49 -        scroll.setPrefViewportHeight(height );
    7.50 -        webView.setMaxWidth( width );
    7.51 -        webView.setMaxHeight( height );
    7.52 -        webView.setMinWidth( width );
    7.53 -        webView.setMinHeight( height );
    7.54 +    private void _resize(final double width, final double height) {
    7.55 +        Window window = container.getScene().getWindow();
    7.56 +        // size difference between root node and window depends on OS and Decorations
    7.57 +        double diffY = window.getHeight() - container.getHeight();
    7.58 +        double diffX = window.getWidth() - container.getWidth();
    7.59 +
    7.60 +        webView.setMaxWidth(width);
    7.61 +        webView.setMaxHeight(height);
    7.62 +        webView.setMinWidth(width);
    7.63 +        webView.setMinHeight(height);
    7.64 +        javafx.geometry.Rectangle2D screenBounds = Screen.getPrimary().getBounds();
    7.65 +        double scaleX = screenBounds.getWidth() / ( width + diffX );
    7.66 +        double scaleY = screenBounds.getHeight() / ( height + diffY );
    7.67 +        // calculate scale factor if too big for device, the .1 adds some padding
    7.68 +        double scale = Math.min(Math.min(scaleX, scaleY), 1.1) - .1;
    7.69 +        webView.setScaleX(scale);
    7.70 +        webView.setScaleY(scale);
    7.71 +        container.getScene().setRoot(new Group());
    7.72 +        ((Stage)window).setScene(new Scene(container, width * scale, height * scale));
    7.73      }
    7.74  
    7.75      private void _autofit() {
     8.1 --- a/boot/pom.xml	Tue Dec 09 07:23:22 2014 +0100
     8.2 +++ b/boot/pom.xml	Tue Dec 09 08:33:22 2014 +0100
     8.3 @@ -36,6 +36,8 @@
     8.4        <groupId>org.ow2.asm</groupId>
     8.5        <artifactId>asm</artifactId>
     8.6        <type>jar</type>
     8.7 +      <scope>provided</scope>
     8.8 +      <optional>true</optional>
     8.9      </dependency>
    8.10      <dependency>
    8.11        <groupId>org.testng</groupId>
     9.1 --- a/boot/src/main/java/net/java/html/boot/BrowserBuilder.java	Tue Dec 09 07:23:22 2014 +0100
     9.2 +++ b/boot/src/main/java/net/java/html/boot/BrowserBuilder.java	Tue Dec 09 08:33:22 2014 +0100
     9.3 @@ -63,7 +63,9 @@
     9.4  import net.java.html.BrwsrCtx;
     9.5  import net.java.html.js.JavaScriptBody;
     9.6  import org.netbeans.html.boot.spi.Fn;
     9.7 +import org.netbeans.html.boot.spi.Fn.Presenter;
     9.8  import org.netbeans.html.context.spi.Contexts;
     9.9 +import org.netbeans.html.context.spi.Contexts.Id;
    9.10  import org.netbeans.html.boot.impl.FindResources;
    9.11  import org.netbeans.html.boot.impl.FnContext;
    9.12  import org.netbeans.html.boot.impl.FnUtils;
    9.13 @@ -120,6 +122,15 @@
    9.14      /** Entry method to obtain a new browser builder. Follow by calling 
    9.15       * its instance methods like {@link #loadClass(java.lang.Class)} and
    9.16       * {@link #loadPage(java.lang.String)}.
    9.17 +     * Since introduction of {@link Id technology identifiers} the 
    9.18 +     * provided <code>context</code> objects are also passed to the 
    9.19 +     * {@link BrwsrCtx context} when it is being 
    9.20 +     * {@link Contexts#newBuilder(java.lang.Object...) created}
    9.21 +     * and can influence the selection
    9.22 +     * of available technologies 
    9.23 +     * (like {@link org.netbeans.html.json.spi.Technology},
    9.24 +     * {@link org.netbeans.html.json.spi.Transfer} or
    9.25 +     * {@link org.netbeans.html.json.spi.WSTransfer}) by name.
    9.26       * 
    9.27       * @param context any instances that should be available to the builder -
    9.28       *   implementation dependant
    9.29 @@ -210,7 +221,7 @@
    9.30      }
    9.31  
    9.32      /** Loader to use when searching for classes to initialize. 
    9.33 -     * If specified, this loader is going to be used to load {@link Fn.Presenter}
    9.34 +     * If specified, this loader is going to be used to load {@link Presenter}
    9.35       * and {@link Contexts#fillInByProviders(java.lang.Class, org.netbeans.html.context.spi.Contexts.Builder) fill} {@link BrwsrCtx} in.
    9.36       * Specifying special classloader may be useful in modular systems, 
    9.37       * like OSGi, where one needs to load classes from many otherwise independent
    9.38 @@ -272,13 +283,16 @@
    9.39          
    9.40          final ClassLoader activeLoader;
    9.41          if (loader != null) {
    9.42 -            if (!FnUtils.isJavaScriptCapable(loader)) {
    9.43 +            if (!FnContext.isJavaScriptCapable(loader)) {
    9.44                  throw new IllegalStateException("Loader cannot resolve @JavaScriptBody: " + loader);
    9.45              }
    9.46              activeLoader = loader;
    9.47 -        } else if (FnUtils.isJavaScriptCapable(myCls.getClassLoader())) {
    9.48 +        } else if (FnContext.isJavaScriptCapable(myCls.getClassLoader())) {
    9.49              activeLoader = myCls.getClassLoader();
    9.50          } else {
    9.51 +            if (!FnContext.isAsmPresent()) {
    9.52 +                throw new IllegalStateException("Cannot find asm-5.0.jar classes!");
    9.53 +            }
    9.54              FImpl impl = new FImpl(myCls.getClassLoader());
    9.55              activeLoader = FnUtils.newLoader(impl, dfnr, myCls.getClassLoader().getParent());
    9.56          }
    9.57 @@ -297,7 +311,7 @@
    9.58                      if (browserClass != null) {
    9.59                          browserClass[0] = newClazz;
    9.60                      }
    9.61 -                    Contexts.Builder cb = Contexts.newBuilder();
    9.62 +                    Contexts.Builder cb = Contexts.newBuilder(context);
    9.63                      if (!Contexts.fillInByProviders(newClazz, cb)) {
    9.64                          LOG.log(Level.WARNING, "Using empty technology for {0}", newClazz);
    9.65                      }
    10.1 --- a/boot/src/main/java/net/java/html/js/package.html	Tue Dec 09 07:23:22 2014 +0100
    10.2 +++ b/boot/src/main/java/net/java/html/js/package.html	Tue Dec 09 08:33:22 2014 +0100
    10.3 @@ -197,7 +197,41 @@
    10.4          passing of arrays works OK. It is however good to keep it in mind to 
    10.5          avoid unwanted surprises.
    10.6          
    10.7 +        <h3>Instance Reference to JavaScript Object</h3>
    10.8 +        
    10.9 +        When writing wrappers around existing JavaScript libraries, it may be
   10.10 +        useful to hold a reference to some JavaScript object from a Java 
   10.11 +        instance and use it later.
   10.12 +<pre>
   10.13 +<b>class</b> WrapperAroundJsObj {
   10.14 +  <b>private final</b> Object js;
   10.15 +
   10.16 +  WrapperAroundJsObj() {
   10.17 +    js = initValue();
   10.18 +  }
   10.19 +
   10.20 +  <b>public void</b> set(int v) {
   10.21 +    setValue(js, v);
   10.22 +  }
   10.23 +
   10.24 +  {@link net.java.html.js.JavaScriptBody @JavaScriptBody}(args = {}, body = "return { value : 0 };")
   10.25 +  <b>private static native</b> Object initValue();
   10.26 +
   10.27 +  {@link net.java.html.js.JavaScriptBody @JavaScriptBody}(
   10.28 +    args = { "js", "v" }, body = "js.value = v;", wait4js = false
   10.29 +  )
   10.30 +  <b>private static native void</b> setValue(Object js, int v);
   10.31 +}            
   10.32 +</pre>      
   10.33 +        The type of the Java reference is {@link java.lang.Object}. 
   10.34 +        From a Java perspective it has no additional methods or fields, however
   10.35 +        its properties can be manipulated from JavaScript. Send the object back
   10.36 +        to JavaScript by passing it as a parameter of some method 
   10.37 +        (like the <code>setValue</code> one) and perform necessary JavaScript
   10.38 +        calls or changes on it.
   10.39 +        
   10.40          <h3>Post Process Classes</h3>
   10.41 +        <a name="post-process"></a>
   10.42  
   10.43          Classes with {@link net.java.html.js.JavaScriptBody} annotated methods need to
   10.44          be post processed before they can be used - e.g. their <code>native</code>
   10.45 @@ -257,7 +291,9 @@
   10.46          will create a special classloader to that does the processing before
   10.47          loading the bytecode into the virtual machine.
   10.48          <p></p>
   10.49 -        The options are rich, however to avoid any troubles, it is recommended
   10.50 +        The options are rich, however to avoid any troubles (as the runtime
   10.51 +        processing needs to also include <code>asm-5.0.jar</code> on application
   10.52 +        classpath), it is recommended
   10.53          to perform the <b>compile time</b> processing.
   10.54          
   10.55          <h3>Getting Started</h3>
    11.1 --- a/boot/src/main/java/org/netbeans/html/boot/impl/FnContext.java	Tue Dec 09 07:23:22 2014 +0100
    11.2 +++ b/boot/src/main/java/org/netbeans/html/boot/impl/FnContext.java	Tue Dec 09 08:33:22 2014 +0100
    11.3 @@ -45,8 +45,10 @@
    11.4  import java.io.Closeable;
    11.5  import java.io.Flushable;
    11.6  import java.io.IOException;
    11.7 +import java.util.logging.Level;
    11.8  import java.util.logging.Logger;
    11.9  import org.netbeans.html.boot.spi.Fn;
   11.10 +import org.objectweb.asm.Opcodes;
   11.11  
   11.12  /**
   11.13   *
   11.14 @@ -60,6 +62,33 @@
   11.15          DUMMY.prev = DUMMY;
   11.16      }
   11.17  
   11.18 +    public static boolean isJavaScriptCapable(ClassLoader l) {
   11.19 +        if (l instanceof JsClassLoader) {
   11.20 +            return true;
   11.21 +        }
   11.22 +        if (l.getResource("META-INF/net.java.html.js.classes") != null) {
   11.23 +            return false;
   11.24 +        }
   11.25 +        return true;
   11.26 +    }
   11.27 +
   11.28 +    public static boolean isAsmPresent() {
   11.29 +        Throwable t;
   11.30 +        try {
   11.31 +            Class.forName(Opcodes.class.getName());
   11.32 +            return true;
   11.33 +        } catch (LinkageError ex) {
   11.34 +            t = ex;
   11.35 +        } catch (ClassNotFoundException ex) {
   11.36 +            t = ex;
   11.37 +        }
   11.38 +        LOG.log(Level.SEVERE, "When using @JavaScriptBody methods, one needs to either:");
   11.39 +        LOG.log(Level.SEVERE, " - include asm-5.0.jar on runtime classpath");
   11.40 +        LOG.log(Level.SEVERE, " - post process classes, see http://bits.netbeans.org/html+java/dev/net/java/html/js/package-summary.html#post-process");
   11.41 +        LOG.log(Level.SEVERE, "Cannot initialize asm-5.0.jar!", t);
   11.42 +        return false;
   11.43 +    }
   11.44 +
   11.45      private Object prev;
   11.46      private final Fn.Presenter current;
   11.47      private FnContext(Fn.Presenter prevP, Fn.Presenter newP) {
    12.1 --- a/boot/src/main/java/org/netbeans/html/boot/impl/FnUtils.java	Tue Dec 09 07:23:22 2014 +0100
    12.2 +++ b/boot/src/main/java/org/netbeans/html/boot/impl/FnUtils.java	Tue Dec 09 08:33:22 2014 +0100
    12.3 @@ -108,16 +108,6 @@
    12.4          return bytecode;
    12.5      }
    12.6      
    12.7 -    public static boolean isJavaScriptCapable(ClassLoader l) {
    12.8 -        if (l instanceof JsClassLoader) {
    12.9 -            return true;
   12.10 -        }
   12.11 -        if (l.getResource("META-INF/net.java.html.js.classes") != null) {
   12.12 -            return false;
   12.13 -        }
   12.14 -        return true;
   12.15 -    }
   12.16 -    
   12.17      public static boolean isValid(Fn fn) {
   12.18          return fn != null && fn.isValid();
   12.19      }
    13.1 --- a/context/src/main/java/net/java/html/BrwsrCtx.java	Tue Dec 09 07:23:22 2014 +0100
    13.2 +++ b/context/src/main/java/net/java/html/BrwsrCtx.java	Tue Dec 09 08:33:22 2014 +0100
    13.3 @@ -47,6 +47,7 @@
    13.4  import org.netbeans.html.context.impl.CtxAccssr;
    13.5  import org.netbeans.html.context.impl.CtxImpl;
    13.6  import org.netbeans.html.context.spi.Contexts;
    13.7 +import org.netbeans.html.context.spi.Contexts.Id;
    13.8  
    13.9  /** Represents context where the <code>net.java.html.json.Model</code>
   13.10   * and other objects
   13.11 @@ -54,7 +55,12 @@
   13.12   * The context is also associated with the actual HTML technology
   13.13   * in the HTML page - there is likely to be different context for 
   13.14   * <a href="http://knockoutjs.com">knockout.js</a> and different one
   13.15 - * for <a href="http://angularjs.org">angular</a>.
   13.16 + * for <a href="http://angularjs.org">angular</a>. Since version 1.1
   13.17 + * the content of contexts can be selected by registering
   13.18 + * implementations under specific
   13.19 + * {@link Id technology identifiers} and requesting them during 
   13.20 + * {@link Contexts#newBuilder(java.lang.Object...) construction} of the
   13.21 + * context.
   13.22   *
   13.23   * @author Jaroslav Tulach
   13.24   */
    14.1 --- a/context/src/main/java/org/netbeans/html/context/impl/CtxImpl.java	Tue Dec 09 07:23:22 2014 +0100
    14.2 +++ b/context/src/main/java/org/netbeans/html/context/impl/CtxImpl.java	Tue Dec 09 08:33:22 2014 +0100
    14.3 @@ -44,8 +44,10 @@
    14.4  
    14.5  import java.util.ArrayList;
    14.6  import java.util.Collections;
    14.7 +import java.util.Comparator;
    14.8  import java.util.List;
    14.9  import net.java.html.BrwsrCtx;
   14.10 +import org.netbeans.html.context.spi.Contexts;
   14.11  
   14.12  /** Implementation detail. Holds list of technologies for particular
   14.13   * {@link BrwsrCtx}.
   14.14 @@ -54,13 +56,15 @@
   14.15   */
   14.16  public final class CtxImpl {
   14.17      private final List<Bind<?>> techs;
   14.18 +    private final Object[] context;
   14.19      
   14.20 -    public CtxImpl() {
   14.21 -        techs = new ArrayList<Bind<?>>();
   14.22 +    public CtxImpl(Object[] context) {
   14.23 +        this(context, new ArrayList<Bind<?>>());
   14.24      }
   14.25      
   14.26 -    private CtxImpl(List<Bind<?>> techs) {
   14.27 +    private CtxImpl(Object[] context, List<Bind<?>> techs) {
   14.28          this.techs = techs;
   14.29 +        this.context = context;
   14.30      }
   14.31      
   14.32      public static <Tech> Tech find(BrwsrCtx context, Class<Tech> technology) {
   14.33 @@ -74,9 +78,9 @@
   14.34      }
   14.35  
   14.36      public BrwsrCtx build() {
   14.37 -        Collections.sort(techs);
   14.38 +        Collections.sort(techs, new BindCompare());
   14.39          final List<Bind<?>> arr = Collections.unmodifiableList(techs);
   14.40 -        CtxImpl impl = new CtxImpl(arr);
   14.41 +        CtxImpl impl = new CtxImpl(context, arr);
   14.42          BrwsrCtx ctx = CtxAccssr.getDefault().newContext(impl);
   14.43          return ctx;
   14.44      }
   14.45 @@ -85,7 +89,7 @@
   14.46          techs.add(new Bind<Tech>(type, impl, priority));
   14.47      }
   14.48      
   14.49 -    private static final class Bind<Tech> implements Comparable<Bind<?>> {
   14.50 +    private static final class Bind<Tech> {
   14.51          private final Class<Tech> clazz;
   14.52          private final Tech impl;
   14.53          private final int priority;
   14.54 @@ -97,16 +101,39 @@
   14.55          }
   14.56  
   14.57          @Override
   14.58 -        public int compareTo(Bind<?> o) {
   14.59 -            if (priority != o.priority) {
   14.60 -                return priority - o.priority;
   14.61 -            }
   14.62 -            return clazz.getName().compareTo(o.clazz.getName());
   14.63 -        }
   14.64 -
   14.65 -        @Override
   14.66          public String toString() {
   14.67              return "Bind{" + "clazz=" + clazz + "@" + clazz.getClassLoader() + ", impl=" + impl + ", priority=" + priority + '}';
   14.68          }
   14.69      }
   14.70 +    
   14.71 +    private final class BindCompare implements Comparator<Bind<?>> {
   14.72 +        boolean isPrefered(Bind<?> b) {
   14.73 +            final Class<?> implClazz = b.impl.getClass();
   14.74 +            Contexts.Id id = implClazz.getAnnotation(Contexts.Id.class);
   14.75 +            if (id == null) {
   14.76 +                return false;
   14.77 +            }
   14.78 +            for (String v : id.value()) {
   14.79 +                for (Object c : context) {
   14.80 +                    if (v.equals(c)) {
   14.81 +                        return true;
   14.82 +                    }
   14.83 +                }
   14.84 +            }
   14.85 +            return false;
   14.86 +        }
   14.87 +        
   14.88 +        @Override
   14.89 +        public int compare(Bind<?> o1, Bind<?> o2) {
   14.90 +            boolean p1 = isPrefered(o1);
   14.91 +            boolean p2 = isPrefered(o2);
   14.92 +            if (p1 != p2) {
   14.93 +                return p1 ? -1 : 1;
   14.94 +            }
   14.95 +            if (o1.priority != o2.priority) {
   14.96 +                return o1.priority - o2.priority;
   14.97 +            }
   14.98 +            return o1.clazz.getName().compareTo(o2.clazz.getName());
   14.99 +        }
  14.100 +    } // end of BindCompare
  14.101  }
    15.1 --- a/context/src/main/java/org/netbeans/html/context/spi/Contexts.java	Tue Dec 09 07:23:22 2014 +0100
    15.2 +++ b/context/src/main/java/org/netbeans/html/context/spi/Contexts.java	Tue Dec 09 08:33:22 2014 +0100
    15.3 @@ -42,6 +42,10 @@
    15.4   */
    15.5  package org.netbeans.html.context.spi;
    15.6  
    15.7 +import java.lang.annotation.ElementType;
    15.8 +import java.lang.annotation.Retention;
    15.9 +import java.lang.annotation.RetentionPolicy;
   15.10 +import java.lang.annotation.Target;
   15.11  import java.util.ServiceLoader;
   15.12  import net.java.html.BrwsrCtx;
   15.13  import org.netbeans.html.context.impl.CtxImpl;
   15.14 @@ -59,11 +63,23 @@
   15.15  
   15.16      /** Creates new, empty builder for creation of {@link BrwsrCtx}. At the
   15.17       * end call the {@link Builder#build()} method to generate the context.
   15.18 -     *
   15.19 +     * 
   15.20 +     * @param context instances of various classes or names of {@link Id technologies} 
   15.21 +     *    to be preferred and used in the built {@link BrwsrCtx context}.
   15.22 +     * @return new instance of the builder
   15.23 +     * @since 1.1
   15.24 +     */
   15.25 +    public static Builder newBuilder(Object... context) {
   15.26 +        return new Builder(context);
   15.27 +    }
   15.28 +    /** Creates new, empty builder for creation of {@link BrwsrCtx}. At the
   15.29 +     * end call the {@link Builder#build()} method to generate the context.
   15.30 +     * Simply calls {@link #newBuilder(java.lang.Object...) newBuilder(new Object[0])}.
   15.31 +     * 
   15.32       * @return new instance of the builder
   15.33       */
   15.34      public static Builder newBuilder() {
   15.35 -        return new Builder();
   15.36 +        return newBuilder(new Object[0]);
   15.37      }
   15.38  
   15.39      /** Seeks for the specified technology in the provided context.
   15.40 @@ -118,6 +134,23 @@
   15.41          }
   15.42          return found;
   15.43      }
   15.44 +    
   15.45 +    /** Identifies the technologies passed to {@link Builder context builder}
   15.46 +     * by a name. Each implementation of a technology 
   15.47 +     * {@link Builder#register(java.lang.Class, java.lang.Object, int) registered into a context}
   15.48 +     * can be annotated with a name (or multiple names). Such implementation
   15.49 +     * will later be 
   15.50 +     * {@link Contexts#fillInByProviders(java.lang.Class, org.netbeans.html.context.spi.Contexts.Builder)  preferred during lookup}
   15.51 +     * if their name(s) has been requested in when 
   15.52 +     * {@link Contexts#newBuilder(java.lang.Object...)  creating a context}.
   15.53 +     * @since 1.1
   15.54 +     */
   15.55 +    @Retention(RetentionPolicy.RUNTIME)
   15.56 +    @Target(ElementType.TYPE)
   15.57 +    public @interface Id {
   15.58 +        /** Identifier(s) for the implementation. */
   15.59 +        public String[] value();
   15.60 +    }
   15.61  
   15.62      /** Implementors of various HTML technologies should
   15.63       * register their implementation via <code>org.openide.util.lookup.ServiceProvider</code>, so
   15.64 @@ -152,9 +185,10 @@
   15.65       * @author Jaroslav Tulach
   15.66       */
   15.67      public static final class Builder {
   15.68 -        private final CtxImpl impl = new CtxImpl();
   15.69 +        private final CtxImpl impl;
   15.70  
   15.71 -        Builder() {
   15.72 +        public Builder(Object[] context) {
   15.73 +            this.impl = new CtxImpl(context);
   15.74          }
   15.75          
   15.76          /** Registers new technology into the context. Each technology is
    16.1 --- a/context/src/test/java/net/java/html/BrwsrCtxTest.java	Tue Dec 09 07:23:22 2014 +0100
    16.2 +++ b/context/src/test/java/net/java/html/BrwsrCtxTest.java	Tue Dec 09 08:33:22 2014 +0100
    16.3 @@ -44,6 +44,7 @@
    16.4  
    16.5  import org.netbeans.html.context.spi.Contexts;
    16.6  import static org.testng.Assert.*;
    16.7 +import org.testng.annotations.Test;
    16.8  
    16.9  /**
   16.10   *
   16.11 @@ -72,4 +73,48 @@
   16.12          assertTrue(arr[0], "Runnable was executed");
   16.13      }
   16.14      
   16.15 +    
   16.16 +    @Test public void defaultOrderOfRegistrations() {
   16.17 +        BrwsrCtx ctx = registerRs(Contexts.newBuilder());
   16.18 +        Class<? extends Runnable> clazz = Contexts.find(ctx, Runnable.class).getClass();
   16.19 +        assertEquals(clazz, R1.class, "R1 is registered at value 10");
   16.20 +    }
   16.21 +    
   16.22 +    @Test public void preferOne() {
   16.23 +        BrwsrCtx ctx = registerRs(Contexts.newBuilder("one"));
   16.24 +        Class<? extends Runnable> clazz = Contexts.find(ctx, Runnable.class).getClass();
   16.25 +        assertEquals(clazz, R1.class, "R1 is registered at value 10");
   16.26 +    }
   16.27 +
   16.28 +    @Test public void preferTwo() {
   16.29 +        BrwsrCtx ctx = registerRs(Contexts.newBuilder("two"));
   16.30 +        Class<? extends Runnable> clazz = Contexts.find(ctx, Runnable.class).getClass();
   16.31 +        assertEquals(clazz, R2.class, "R2 is preferred");
   16.32 +    }
   16.33 +
   16.34 +    @Test public void preferBoth() {
   16.35 +        BrwsrCtx ctx = registerRs(Contexts.newBuilder("one", "two"));
   16.36 +        Class<? extends Runnable> clazz = Contexts.find(ctx, Runnable.class).getClass();
   16.37 +        assertEquals(clazz, R1.class, "R1 is registered at value 10");
   16.38 +    }
   16.39 +    
   16.40 +    private static BrwsrCtx registerRs(Contexts.Builder b) {
   16.41 +        b.register(Runnable.class, new R1(), 10);
   16.42 +        b.register(Runnable.class, new R2(), 20);
   16.43 +        return b.build();
   16.44 +    }
   16.45 +
   16.46 +    @Contexts.Id("one")
   16.47 +    static final class R1 implements Runnable {
   16.48 +        @Override
   16.49 +        public void run() {
   16.50 +        }
   16.51 +    }
   16.52 +    @Contexts.Id("two")
   16.53 +    static final class R2 implements Runnable {
   16.54 +        @Override
   16.55 +        public void run() {
   16.56 +        }
   16.57 +    }
   16.58 +    
   16.59  }
   16.60 \ No newline at end of file
    17.1 --- a/geo/src/main/java/org/netbeans/html/geo/spi/GLProvider.java	Tue Dec 09 07:23:22 2014 +0100
    17.2 +++ b/geo/src/main/java/org/netbeans/html/geo/spi/GLProvider.java	Tue Dec 09 08:33:22 2014 +0100
    17.3 @@ -47,7 +47,7 @@
    17.4  import net.java.html.geo.Position;
    17.5  import net.java.html.geo.Position.Handle;
    17.6  import net.java.html.geo.Position.Coordinates;
    17.7 -import org.netbeans.html.context.spi.Contexts;
    17.8 +import org.netbeans.html.context.spi.Contexts.Builder;
    17.9  import org.netbeans.html.geo.impl.Accessor;
   17.10  import org.openide.util.lookup.ServiceProvider;
   17.11  
   17.12 @@ -55,7 +55,7 @@
   17.13   * Subclass this class, implement its method and register it into the system.
   17.14   * You can either use {@link ServiceProvider} to register globally, or 
   17.15   * one can register into {@link BrwsrCtx} (via 
   17.16 - * {@link Contexts.Builder#register(java.lang.Class, java.lang.Object, int) context builder}).
   17.17 + * {@link Builder#register(java.lang.Class, java.lang.Object, int) context builder}).
   17.18   * <p>
   17.19   * There is default system provider (used as a fallback) based on 
   17.20   * <a href="http://www.w3.org/TR/geolocation-API/">
   17.21 @@ -93,11 +93,11 @@
   17.22   * </pre>
   17.23   *
   17.24   * @author Jaroslav Tulach
   17.25 - * @param <Watch> your choosen type to represent one query (one time) or watch (repeated) request -
   17.26 + * @param <Watch> your chosen type to represent one query (one time) or watch (repeated) request -
   17.27   *   this type is used in {@link #start(org.netbeans.html.geo.spi.GLProvider.Query) start}
   17.28   *   and {@link #stop(java.lang.Object) stop} methods.
   17.29   * 
   17.30 - * @param <Coords> your choosen type to represent geolocation coordinates -
   17.31 + * @param <Coords> your chosen type to represent geolocation coordinates -
   17.32   *   use in many methods in this class like {@link #latitude(java.lang.Object)} and
   17.33   *   {@link #longitude(java.lang.Object)}.
   17.34   * 
   17.35 @@ -263,7 +263,7 @@
   17.36          
   17.37          /**
   17.38           * Is this one time or repeated request? Mimics value provided in
   17.39 -         * {@link Handle#Handle(boolean) constructor}.
   17.40 +         * {@link Handle constructor}.
   17.41           *
   17.42           * @return true if this is one time request, false if the request is
   17.43           * permanent (up until {@link Handle#stop() } is called).
    18.1 --- a/json-tck/src/main/java/org/netbeans/html/json/tck/KnockoutTCK.java	Tue Dec 09 07:23:22 2014 +0100
    18.2 +++ b/json-tck/src/main/java/org/netbeans/html/json/tck/KnockoutTCK.java	Tue Dec 09 08:33:22 2014 +0100
    18.3 @@ -55,6 +55,7 @@
    18.4  import net.java.html.json.tests.WebSocketTest;
    18.5  import org.netbeans.html.context.spi.Contexts.Builder;
    18.6  import org.openide.util.lookup.ServiceProvider;
    18.7 +import org.testng.annotations.Factory;
    18.8  
    18.9  /** Entry point for providers of different HTML binding technologies (like
   18.10   * Knockout.js in JavaFX's WebView). Sample usage:
   18.11 @@ -67,7 +68,7 @@
   18.12          // use {@link Builder}.{@link Builder#build() build}();
   18.13      }
   18.14  
   18.15 -    {@code @}{@link org.testng.annotations.Factory} public static Object[] create() {
   18.16 +    {@code @}{@link Factory} public static Object[] create() {
   18.17          return VMTest.newTests().withClasses({@link KnockoutTCK#testClasses}()).build();
   18.18      }
   18.19  }
    19.1 --- a/json/src/main/java/net/java/html/json/Model.java	Tue Dec 09 07:23:22 2014 +0100
    19.2 +++ b/json/src/main/java/net/java/html/json/Model.java	Tue Dec 09 08:33:22 2014 +0100
    19.3 @@ -50,19 +50,19 @@
    19.4  import java.util.List;
    19.5  
    19.6  /** Defines a model class that represents a single 
    19.7 - * <a href="http://en.wikipedia.org/wiki/JSON">JSON</a>-like object
    19.8 + * <a target="_blank" href="http://en.wikipedia.org/wiki/JSON">JSON</a>-like object
    19.9   * named {@link #className()}. The generated class contains
   19.10   * getters and setters for properties defined via {@link #properties()} and
   19.11   * getters for other, derived properties defined by annotating methods
   19.12   * of this class by {@link ComputedProperty}. Each property
   19.13   * can be of primitive type, an {@link Enum enum type} or (in order to create 
   19.14 - * nested <a href="http://en.wikipedia.org/wiki/JSON">JSON</a> structure)
   19.15 + * nested <a target="_blank" href="http://en.wikipedia.org/wiki/JSON">JSON</a> structure)
   19.16   * of another {@link Model class generated by @Model} annotation. Each property
   19.17   * can either represent a single value or be an array of its values.
   19.18   * <p>
   19.19   * The {@link #className() generated class}'s <code>toString</code> method
   19.20   * converts the state of the object into 
   19.21 - * <a href="http://en.wikipedia.org/wiki/JSON">JSON</a> format. One can
   19.22 + * <a target="_blank" href="http://en.wikipedia.org/wiki/JSON">JSON</a> format. One can
   19.23   * use {@link Models#parse(net.java.html.BrwsrCtx, java.lang.Class, java.io.InputStream)}
   19.24   * method to read the JSON text stored in a file or other stream back into the Java model. 
   19.25   * One can also use {@link OnReceive @OnReceive} annotation to read the model
   19.26 @@ -109,7 +109,7 @@
   19.27   *   <b>new</b> Address("Markoušovice", "Úpice"),
   19.28   *   <b>new</b> Address("V Parku", "Praha")
   19.29   * );
   19.30 - * // p.toString() then returns equivalent of following <a href="http://en.wikipedia.org/wiki/JSON">JSON</a> object
   19.31 + * // p.toString() then returns equivalent of following <a target="_blank" href="http://en.wikipedia.org/wiki/JSON">JSON</a> object
   19.32   * {
   19.33   *   "firstName" : "Jaroslav",
   19.34   *   "lastName" : "Tulach",
   19.35 @@ -120,10 +120,10 @@
   19.36   * }
   19.37   * </pre>
   19.38   * <p>
   19.39 - * In case you are using <a href="http://knockoutjs.com/">Knockout technology</a>
   19.40 + * In case you are using <a target="_blank" href="http://knockoutjs.com/">Knockout technology</a>
   19.41   * for Java then you can associate such model object with surrounding HTML page by
   19.42   * calling: <code>p.applyBindings();</code>. The page can then use regular
   19.43 - * <a href="http://knockoutjs.com/">Knockout</a> bindings to reference your
   19.44 + * <a target="_blank" href="http://knockoutjs.com/">Knockout</a> bindings to reference your
   19.45   * model and create dynamic connection between your model in Java and 
   19.46   * live DOM structure in the browser:
   19.47   * <pre>
   19.48 @@ -132,7 +132,58 @@
   19.49   *   Lives in &lt;span data-bind="text: town"/&gt;
   19.50   * &lt;/div&gt;
   19.51   * </pre>
   19.52 - * <p>
   19.53 + * 
   19.54 + * <h4>Access Raw <a target="_blank" href="http://knockoutjs.com/">Knockout</a> Observables</h4>
   19.55 + * 
   19.56 + * One can obtain <quote>raw</quote> JavaScript object representing the 
   19.57 + * instance of {@link Model model class} (with appropriate
   19.58 + * <a target="_blank" href="http://knockoutjs.com/">Knockout</a> <b>observable</b> properties)
   19.59 + * by calling {@link Models#toRaw(java.lang.Object) Models.toRaw(p)}. For 
   19.60 + * example here is a way to obtain the value of <code>fullName</code> property
   19.61 + * (inefficient as it switches between Java and JavaScript back and forth, 
   19.62 + * but functional and instructive) via a JavaScript call:
   19.63 + * <pre>
   19.64 + * {@link net.java.html.js.JavaScriptBody @JavaScriptBody}(args = "raw", javacall = true, body =
   19.65 + *   "return raw.fullName();" // yes, the <a target="_blank" href="http://knockoutjs.com/">Knockout</a> property is a function
   19.66 + * )
   19.67 + * static native String jsFullName(Object raw);
   19.68 + * // and later
   19.69 + * Person p = ...;
   19.70 + * String fullName = jsFullName({@link Models#toRaw(java.lang.Object) Models.toRaw(p)});
   19.71 + * </pre>
   19.72 + * The above shows how to read a value from <a target="_blank" href="http://knockoutjs.com/">Knockout</a>
   19.73 + * observable. There is a way to change the value too:
   19.74 + * One can pass a parameter to the property-function and then
   19.75 + * it acts like a setter (of course not in the case of read only <code>fullName</code> property,
   19.76 + * but for <code>firstName</code> or <code>lastName</code> the setter is
   19.77 + * available). Everything mentioned in this paragraph applies only when 
   19.78 + * <a target="_blank" href="http://knockoutjs.com/">Knockout</a> technology is active
   19.79 + * other technologies may behave differently.
   19.80 + * 
   19.81 + * <h4>Copy to Plain JSON</h4>
   19.82 + * There is a way to pass a value of a Java {@link Model model class} instance 
   19.83 + * by copy and convert 
   19.84 + * the {@link Model the whole object} into plain 
   19.85 + * <a target="_blank" href="http://en.wikipedia.org/wiki/JSON">JSON</a>. Just
   19.86 + * print it as a string and parse it in JavaScript:
   19.87 + * <pre>
   19.88 + * {@link net.java.html.js.JavaScriptBody @JavaScriptBody}(args = { "txt" }, body =
   19.89 + *   "return JSON.parse(txt);"
   19.90 + * )
   19.91 + * private static native Object parseJSON(String txt);
   19.92 + * 
   19.93 + * public static Object toPlainJSON(Object model) {
   19.94 + *   return parseJSON(model.toString());
   19.95 + * }
   19.96 + * </pre>
   19.97 + * The newly returned instance is a one time copy of the original model and is no longer
   19.98 + * connected to it. The copy based behavior is independent on any 
   19.99 + * particular technology and should work
  19.100 + * in <a target="_blank" href="http://knockoutjs.com/">Knockout</a> as well as other
  19.101 + * technology implementations.
  19.102 + * 
  19.103 + * <h4>References</h4>
  19.104 + * 
  19.105   * Visit an <a target="_blank" href="http://dew.apidesign.org/dew/#7510833">on-line demo</a>
  19.106   * to see a histogram driven by the {@link Model} annotation or try 
  19.107   * a little <a target="_blank" href="http://dew.apidesign.org/dew/#7263102">math test</a>.
    20.1 --- a/json/src/main/java/org/netbeans/html/json/spi/Technology.java	Tue Dec 09 07:23:22 2014 +0100
    20.2 +++ b/json/src/main/java/org/netbeans/html/json/spi/Technology.java	Tue Dec 09 08:33:22 2014 +0100
    20.3 @@ -45,10 +45,17 @@
    20.4  import net.java.html.BrwsrCtx;
    20.5  import net.java.html.json.Model;
    20.6  import net.java.html.json.Models;
    20.7 +import org.netbeans.html.context.spi.Contexts.Id;
    20.8  
    20.9  /** An implementation of a binding between model classes (see {@link Model})
   20.10   * and particular technology like <a href="http://knockoutjs.com">knockout.js</a>
   20.11   * in a browser window, etc.
   20.12 + * Since introduction of {@link Id technology identifiers} one can choose between
   20.13 + * different background implementations to handle the conversion and
   20.14 + * communication requests. The currently known provider is
   20.15 + * <code>org.netbeans.html:ko4j</code> module which registers 
   20.16 + * a <a href="http://knockoutjs.com" target="_blank">knockout.js</a>
   20.17 + * implementation called <b>ko4j</b>.
   20.18   *
   20.19   * @author Jaroslav Tulach
   20.20   */
    21.1 --- a/json/src/main/java/org/netbeans/html/json/spi/Transfer.java	Tue Dec 09 07:23:22 2014 +0100
    21.2 +++ b/json/src/main/java/org/netbeans/html/json/spi/Transfer.java	Tue Dec 09 08:33:22 2014 +0100
    21.3 @@ -45,9 +45,17 @@
    21.4  import java.io.IOException;
    21.5  import java.io.InputStream;
    21.6  import org.netbeans.html.context.spi.Contexts.Builder;
    21.7 +import org.netbeans.html.context.spi.Contexts.Id;
    21.8  
    21.9  /** A {@link Builder service provider interface} responsible for 
   21.10   * conversion of JSON objects to Java ones and vice-versa.
   21.11 + * Since introduction of {@link Id technology identifiers} one can choose between
   21.12 + * different background implementations to handle the conversion and
   21.13 + * communication requests. The known providers include
   21.14 + * <code>org.netbeans.html:ko4j</code> module which registers 
   21.15 + * a native browser implementation called <b>xhr</b>, and a
   21.16 + * <code>org.netbeans.html:ko-ws-tyrus</code> module which registers 
   21.17 + * Java based implementation named <b>tyrus</b>.
   21.18   *
   21.19   * @author Jaroslav Tulach
   21.20   */
    22.1 --- a/json/src/main/java/org/netbeans/html/json/spi/WSTransfer.java	Tue Dec 09 07:23:22 2014 +0100
    22.2 +++ b/json/src/main/java/org/netbeans/html/json/spi/WSTransfer.java	Tue Dec 09 08:33:22 2014 +0100
    22.3 @@ -44,9 +44,17 @@
    22.4  
    22.5  import net.java.html.BrwsrCtx;
    22.6  import org.netbeans.html.context.spi.Contexts.Provider;
    22.7 +import org.netbeans.html.context.spi.Contexts.Id;
    22.8  
    22.9  /** Interface for providers of WebSocket protocol. Register into a 
   22.10 - * {@link BrwsrCtx context} in your own {@link Provider}
   22.11 + * {@link BrwsrCtx context} in your own {@link Provider}.
   22.12 + * Since introduction of {@link Id technology identifiers} one can choose between
   22.13 + * different background implementations to handle the conversion and
   22.14 + * communication requests. The known providers include
   22.15 + * <code>org.netbeans.html:ko4j</code> module which registers 
   22.16 + * a native browser implementation called <b>websocket</b>, and a
   22.17 + * <code>org.netbeans.html:ko-ws-tyrus</code> module which registers 
   22.18 + * Java based implementation named <b>tyrus</b>.
   22.19   *
   22.20   * @author Jaroslav Tulach
   22.21   * @param <WebSocket> internal implementation type representing the socket
    23.1 --- a/json/src/test/java/net/java/html/json/MapModelTest.java	Tue Dec 09 07:23:22 2014 +0100
    23.2 +++ b/json/src/test/java/net/java/html/json/MapModelTest.java	Tue Dec 09 08:33:22 2014 +0100
    23.3 @@ -47,6 +47,8 @@
    23.4  import java.io.InputStream;
    23.5  import java.lang.reflect.InvocationTargetException;
    23.6  import java.util.HashMap;
    23.7 +import java.util.Iterator;
    23.8 +import java.util.ListIterator;
    23.9  import java.util.Map;
   23.10  import org.netbeans.html.context.spi.Contexts;
   23.11  import org.netbeans.html.json.spi.FunctionBinding;
   23.12 @@ -179,6 +181,62 @@
   23.13          
   23.14          assertEquals(p.getSex(), Sex.FEMALE, "Changed");
   23.15      }
   23.16 +    
   23.17 +    @Test public void removeViaIterator() {
   23.18 +        People p = Models.bind(new People(), c);
   23.19 +        p.getNicknames().add("One");
   23.20 +        p.getNicknames().add("Two");
   23.21 +        p.getNicknames().add("Three");
   23.22 +
   23.23 +        Map m = (Map)Models.toRaw(p);
   23.24 +        Object o = m.get("nicknames");
   23.25 +        assertNotNull(o, "List registered in the model");
   23.26 +        assertEquals(o.getClass(), One.class);
   23.27 +        One one = (One)o;
   23.28 +        
   23.29 +        
   23.30 +        assertEquals(one.changes, 0, "No change");
   23.31 +        
   23.32 +        Iterator<String> it = p.getNicknames().iterator();
   23.33 +        assertEquals(it.next(), "One");
   23.34 +        assertEquals(it.next(), "Two");
   23.35 +        it.remove();
   23.36 +        assertEquals(it.next(), "Three");
   23.37 +        assertFalse(it.hasNext());
   23.38 +        
   23.39 +        
   23.40 +        assertEquals(one.changes, 1, "One change");
   23.41 +    }
   23.42 +    
   23.43 +    @Test public void removeViaListIterator() {
   23.44 +        People p = Models.bind(new People(), c);
   23.45 +        p.getNicknames().add("One");
   23.46 +        p.getNicknames().add("Two");
   23.47 +        p.getNicknames().add("Three");
   23.48 +
   23.49 +        Map m = (Map)Models.toRaw(p);
   23.50 +        Object o = m.get("nicknames");
   23.51 +        assertNotNull(o, "List registered in the model");
   23.52 +        assertEquals(o.getClass(), One.class);
   23.53 +        One one = (One)o;
   23.54 +        
   23.55 +        
   23.56 +        assertEquals(one.changes, 0, "No change");
   23.57 +        
   23.58 +        ListIterator<String> it = p.getNicknames().listIterator(1);
   23.59 +        assertEquals(it.next(), "Two");
   23.60 +        it.remove();
   23.61 +        assertEquals(it.next(), "Three");
   23.62 +        assertFalse(it.hasNext());
   23.63 +        
   23.64 +        
   23.65 +        assertEquals(one.changes, 1, "One change");
   23.66 +        
   23.67 +        it.set("3");
   23.68 +        assertEquals(p.getNicknames().get(1), "3");
   23.69 +        
   23.70 +        assertEquals(one.changes, 2, "Snd change");
   23.71 +    }
   23.72  
   23.73      static final class One {
   23.74          int changes;
    24.1 --- a/ko-felix-test/src/main/java/org/netbeans/html/ko/felix/test/KnockoutFelixTCKImpl.java	Tue Dec 09 07:23:22 2014 +0100
    24.2 +++ b/ko-felix-test/src/main/java/org/netbeans/html/ko/felix/test/KnockoutFelixTCKImpl.java	Tue Dec 09 08:33:22 2014 +0100
    24.3 @@ -46,6 +46,7 @@
    24.4  import java.io.IOException;
    24.5  import java.io.InputStreamReader;
    24.6  import java.lang.reflect.Constructor;
    24.7 +import java.lang.reflect.InvocationTargetException;
    24.8  import java.lang.reflect.Method;
    24.9  import java.net.URI;
   24.10  import java.net.URISyntaxException;
   24.11 @@ -140,16 +141,9 @@
   24.12      @Override
   24.13      public BrwsrCtx createContext() {
   24.14          try {
   24.15 -            Class<?> fxCls = loadOSGiClass(
   24.16 -                "org.netbeans.html.ko4j.FXContext",
   24.17 -                FrameworkUtil.getBundle(KnockoutFelixTCKImpl.class).getBundleContext()
   24.18 -            );
   24.19 -            final Constructor<?> cnstr = fxCls.getConstructor(Fn.Presenter.class);
   24.20 -            cnstr.setAccessible(true);
   24.21 -            Object fx = cnstr.newInstance(browserContext);
   24.22              Contexts.Builder cb = Contexts.newBuilder().
   24.23 -                register(Technology.class, (Technology)fx, 10).
   24.24 -                register(Transfer.class, (Transfer)fx, 10).
   24.25 +                register(Technology.class, (Technology)osgiInstance("KOTech"), 10).
   24.26 +                register(Transfer.class, (Transfer)osgiInstance("KOTransfer"), 10).
   24.27                  register(Executor.class, (Executor)browserContext, 10);
   24.28  //        if (fx.areWebSocketsSupported()) {
   24.29  //            cb.register(WSTransfer.class, fx, 10);
   24.30 @@ -160,6 +154,17 @@
   24.31          }
   24.32      }
   24.33  
   24.34 +    private Object osgiInstance(String simpleName) throws IllegalAccessException, SecurityException, IllegalArgumentException, Exception, NoSuchMethodException, InstantiationException, InvocationTargetException {
   24.35 +        Class<?> fxCls = loadOSGiClass(
   24.36 +                "org.netbeans.html.ko4j." + simpleName,
   24.37 +                FrameworkUtil.getBundle(KnockoutFelixTCKImpl.class).getBundleContext()
   24.38 +        );
   24.39 +        final Constructor<?> cnstr = fxCls.getDeclaredConstructor();
   24.40 +        cnstr.setAccessible(true);
   24.41 +        Object fx = cnstr.newInstance();
   24.42 +        return fx;
   24.43 +    }
   24.44 +
   24.45      @Override
   24.46      public Object createJSON(Map<String, Object> values) {
   24.47          JSONObject json = new JSONObject();
    25.1 --- a/ko-osgi-test/src/main/java/org/netbeans/html/ko/osgi/test/KnockoutEquinoxTCKImpl.java	Tue Dec 09 07:23:22 2014 +0100
    25.2 +++ b/ko-osgi-test/src/main/java/org/netbeans/html/ko/osgi/test/KnockoutEquinoxTCKImpl.java	Tue Dec 09 08:33:22 2014 +0100
    25.3 @@ -46,6 +46,7 @@
    25.4  import java.io.IOException;
    25.5  import java.io.InputStreamReader;
    25.6  import java.lang.reflect.Constructor;
    25.7 +import java.lang.reflect.InvocationTargetException;
    25.8  import java.lang.reflect.Method;
    25.9  import java.net.URI;
   25.10  import java.net.URISyntaxException;
   25.11 @@ -135,16 +136,9 @@
   25.12      @Override
   25.13      public BrwsrCtx createContext() {
   25.14          try {
   25.15 -            Class<?> fxCls = loadOSGiClass(
   25.16 -                "org.netbeans.html.ko4j.FXContext",
   25.17 -                FrameworkUtil.getBundle(KnockoutEquinoxTCKImpl.class).getBundleContext()
   25.18 -            );
   25.19 -            final Constructor<?> cnstr = fxCls.getConstructor(Fn.Presenter.class);
   25.20 -            cnstr.setAccessible(true);
   25.21 -            Object fx = cnstr.newInstance(browserContext);
   25.22              Contexts.Builder cb = Contexts.newBuilder().
   25.23 -                register(Technology.class, (Technology)fx, 10).
   25.24 -                register(Transfer.class, (Transfer)fx, 10).
   25.25 +                register(Technology.class, (Technology)osgiInstance("KOTech"), 10).
   25.26 +                register(Transfer.class, (Transfer)osgiInstance("KOTransfer"), 10).
   25.27                  register(Executor.class, (Executor)browserContext, 10);
   25.28  //        if (fx.areWebSocketsSupported()) {
   25.29  //            cb.register(WSTransfer.class, fx, 10);
   25.30 @@ -154,6 +148,16 @@
   25.31              throw new IllegalStateException(ex);
   25.32          }
   25.33      }
   25.34 +    private Object osgiInstance(String simpleName) throws IllegalAccessException, SecurityException, IllegalArgumentException, Exception, NoSuchMethodException, InstantiationException, InvocationTargetException {
   25.35 +        Class<?> fxCls = loadOSGiClass(
   25.36 +                "org.netbeans.html.ko4j." + simpleName,
   25.37 +                FrameworkUtil.getBundle(KnockoutEquinoxTCKImpl.class).getBundleContext()
   25.38 +        );
   25.39 +        final Constructor<?> cnstr = fxCls.getDeclaredConstructor();
   25.40 +        cnstr.setAccessible(true);
   25.41 +        Object fx = cnstr.newInstance();
   25.42 +        return fx;
   25.43 +    }
   25.44  
   25.45      @Override
   25.46      public Object createJSON(Map<String, Object> values) {
    26.1 --- a/ko-ws-tyrus/src/main/java/org/netbeans/html/wstyrus/TyrusContext.java	Tue Dec 09 07:23:22 2014 +0100
    26.2 +++ b/ko-ws-tyrus/src/main/java/org/netbeans/html/wstyrus/TyrusContext.java	Tue Dec 09 08:33:22 2014 +0100
    26.3 @@ -82,6 +82,7 @@
    26.4   *
    26.5   * @author Jaroslav Tulach
    26.6   */
    26.7 +@Contexts.Id("tyrus")
    26.8  @ServiceProvider(service = Contexts.Provider.class)
    26.9  public final class TyrusContext 
   26.10  implements Contexts.Provider, WSTransfer<Comm>, Transfer {
    27.1 --- a/ko4j/pom.xml	Tue Dec 09 07:23:22 2014 +0100
    27.2 +++ b/ko4j/pom.xml	Tue Dec 09 08:33:22 2014 +0100
    27.3 @@ -15,6 +15,7 @@
    27.4    <properties>
    27.5      <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    27.6      <bundleSymbolicName>org.netbeans.html.ko4j</bundleSymbolicName>
    27.7 +    <netbeans.compile.on.save>none</netbeans.compile.on.save> 
    27.8    </properties>
    27.9    <build>
   27.10        <plugins>
   27.11 @@ -92,7 +93,6 @@
   27.12          <groupId>javax.servlet</groupId>
   27.13          <artifactId>javax.servlet-api</artifactId>
   27.14          <scope>test</scope>
   27.15 -        <version>3.1.0</version>
   27.16      </dependency>
   27.17    </dependencies>
   27.18      <description>Binds net.java.html.json APIs together with knockout.js</description>
    28.1 --- a/ko4j/src/main/java/org/netbeans/html/ko4j/FXContext.java	Tue Dec 09 07:23:22 2014 +0100
    28.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    28.3 @@ -1,243 +0,0 @@
    28.4 -/**
    28.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    28.6 - *
    28.7 - * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
    28.8 - *
    28.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   28.10 - * Other names may be trademarks of their respective owners.
   28.11 - *
   28.12 - * The contents of this file are subject to the terms of either the GNU
   28.13 - * General Public License Version 2 only ("GPL") or the Common
   28.14 - * Development and Distribution License("CDDL") (collectively, the
   28.15 - * "License"). You may not use this file except in compliance with the
   28.16 - * License. You can obtain a copy of the License at
   28.17 - * http://www.netbeans.org/cddl-gplv2.html
   28.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   28.19 - * specific language governing permissions and limitations under the
   28.20 - * License.  When distributing the software, include this License Header
   28.21 - * Notice in each file and include the License file at
   28.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   28.23 - * particular file as subject to the "Classpath" exception as provided
   28.24 - * by Oracle in the GPL Version 2 section of the License file that
   28.25 - * accompanied this code. If applicable, add the following below the
   28.26 - * License Header, with the fields enclosed by brackets [] replaced by
   28.27 - * your own identifying information:
   28.28 - * "Portions Copyrighted [year] [name of copyright owner]"
   28.29 - *
   28.30 - * Contributor(s):
   28.31 - *
   28.32 - * The Original Software is NetBeans. The Initial Developer of the Original
   28.33 - * Software is Oracle. Portions Copyright 2013-2014 Oracle. All Rights Reserved.
   28.34 - *
   28.35 - * If you wish your version of this file to be governed by only the CDDL
   28.36 - * or only the GPL Version 2, indicate your decision by adding
   28.37 - * "[Contributor] elects to include this software in this distribution
   28.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
   28.39 - * single choice of license, a recipient has the option to distribute
   28.40 - * your version of this file under either the CDDL, the GPL Version 2 or
   28.41 - * to extend the choice of license to its licensees as provided above.
   28.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
   28.43 - * Version 2 license, then the option applies only if the new code is
   28.44 - * made subject to such option by the copyright holder.
   28.45 - */
   28.46 -package org.netbeans.html.ko4j;
   28.47 -
   28.48 -import java.io.ByteArrayOutputStream;
   28.49 -import java.io.IOException;
   28.50 -import java.io.InputStream;
   28.51 -import java.io.InputStreamReader;
   28.52 -import java.io.Reader;
   28.53 -import java.net.URL;
   28.54 -import java.util.logging.Logger;
   28.55 -import org.netbeans.html.boot.spi.Fn;
   28.56 -import org.netbeans.html.json.spi.FunctionBinding;
   28.57 -import org.netbeans.html.json.spi.JSONCall;
   28.58 -import org.netbeans.html.json.spi.PropertyBinding;
   28.59 -import org.netbeans.html.json.spi.Technology;
   28.60 -import org.netbeans.html.json.spi.Transfer;
   28.61 -import org.netbeans.html.json.spi.WSTransfer;
   28.62 -
   28.63 -/** This is an implementation package - just
   28.64 - * include its JAR on classpath and use official {@link Context} API
   28.65 - * to access the functionality.
   28.66 - * <p>
   28.67 - *
   28.68 - * @author Jaroslav Tulach
   28.69 - */
   28.70 -final class FXContext
   28.71 -implements Technology.BatchInit<Object>, Technology.ValueMutated<Object>,
   28.72 -Transfer, WSTransfer<LoadWS> {
   28.73 -    static final Logger LOG = Logger.getLogger(FXContext.class.getName());
   28.74 -    private Object[] jsObjects;
   28.75 -    private int jsIndex;
   28.76 -
   28.77 -    public FXContext(Fn.Presenter browserContext) {
   28.78 -    }
   28.79 -    
   28.80 -    @Override
   28.81 -    public Object wrapModel(Object model, PropertyBinding[] propArr, FunctionBinding[] funcArr) {
   28.82 -        String[] propNames = new String[propArr.length];
   28.83 -        boolean[] propReadOnly = new boolean[propArr.length];
   28.84 -        Object[] propValues = new Object[propArr.length];
   28.85 -        for (int i = 0; i < propNames.length; i++) {
   28.86 -            propNames[i] = propArr[i].getPropertyName();
   28.87 -            propReadOnly[i] = propArr[i].isReadOnly();
   28.88 -            propValues[i] = propArr[i].getValue();
   28.89 -        }
   28.90 -        String[] funcNames = new String[funcArr.length];
   28.91 -        for (int i = 0; i < funcNames.length; i++) {
   28.92 -            funcNames[i] = funcArr[i].getFunctionName();
   28.93 -        }
   28.94 -        Object ret = getJSObject();
   28.95 -        Knockout.wrapModel(new Knockout(model, ret, propArr, funcArr),
   28.96 -            ret, 
   28.97 -            propNames, propReadOnly, propValues,
   28.98 -            funcNames
   28.99 -        );
  28.100 -        return ret;
  28.101 -    }
  28.102 -    
  28.103 -    private Object getJSObject() {
  28.104 -        int len = 64;
  28.105 -        if (jsObjects != null && jsIndex < (len = jsObjects.length)) {
  28.106 -            Object ret = jsObjects[jsIndex];
  28.107 -            jsObjects[jsIndex] = null;
  28.108 -            jsIndex++;
  28.109 -            return ret;
  28.110 -        }
  28.111 -        jsObjects = Knockout.allocJS(len * 2);
  28.112 -        jsIndex = 1;
  28.113 -        Object ret = jsObjects[0];
  28.114 -        jsObjects[0] = null;
  28.115 -        return ret;
  28.116 -    }
  28.117 -    
  28.118 -    @Override
  28.119 -    public Object wrapModel(Object model) {
  28.120 -        throw new UnsupportedOperationException();
  28.121 -    }
  28.122 -
  28.123 -    @Override
  28.124 -    public void bind(PropertyBinding b, Object model, Object data) {
  28.125 -        throw new UnsupportedOperationException();
  28.126 -    }
  28.127 -
  28.128 -    @Override
  28.129 -    public void valueHasMutated(Object data, String propertyName) {
  28.130 -        Knockout.cleanUp();
  28.131 -        Knockout.valueHasMutated(data, propertyName, null, null);
  28.132 -    }
  28.133 -    
  28.134 -    @Override
  28.135 -    public void valueHasMutated(Object data, String propertyName, Object oldValue, Object newValue) {
  28.136 -        Knockout.cleanUp();
  28.137 -        Knockout.valueHasMutated(data, propertyName, oldValue, newValue);
  28.138 -    }
  28.139 -
  28.140 -    @Override
  28.141 -    public void expose(FunctionBinding fb, Object model, Object d) {
  28.142 -        throw new UnsupportedOperationException();
  28.143 -    }
  28.144 -
  28.145 -    @Override
  28.146 -    public void applyBindings(Object data) {
  28.147 -        Object ko = Knockout.applyBindings(data);
  28.148 -        if (ko instanceof Knockout) {
  28.149 -            ((Knockout)ko).hold();
  28.150 -        }
  28.151 -    }
  28.152 -
  28.153 -    @Override
  28.154 -    public Object wrapArray(Object[] arr) {
  28.155 -        return arr;
  28.156 -    }
  28.157 -
  28.158 -    @Override
  28.159 -    public void extract(Object obj, String[] props, Object[] values) {
  28.160 -        LoadJSON.extractJSON(obj, props, values);
  28.161 -    }
  28.162 -
  28.163 -    @Override
  28.164 -    public void loadJSON(final JSONCall call) {
  28.165 -        if (call.isJSONP()) {
  28.166 -            String me = LoadJSON.createJSONP(call);
  28.167 -            LoadJSON.loadJSONP(call.composeURL(me), me);
  28.168 -        } else {
  28.169 -            String data = null;
  28.170 -            if (call.isDoOutput()) {
  28.171 -                try {
  28.172 -                    ByteArrayOutputStream bos = new ByteArrayOutputStream();
  28.173 -                    call.writeData(bos);
  28.174 -                    data = new String(bos.toByteArray(), "UTF-8");
  28.175 -                } catch (IOException ex) {
  28.176 -                    call.notifyError(ex);
  28.177 -                }
  28.178 -            }
  28.179 -            LoadJSON.loadJSON(call.composeURL(null), call, call.getMethod(), data);
  28.180 -        }
  28.181 -    }
  28.182 -
  28.183 -    @Override
  28.184 -    public <M> M toModel(Class<M> modelClass, Object data) {
  28.185 -        return modelClass.cast(Knockout.toModel(data));
  28.186 -    }
  28.187 -
  28.188 -    @Override
  28.189 -    public Object toJSON(InputStream is) throws IOException {
  28.190 -        StringBuilder sb = new StringBuilder();
  28.191 -        InputStreamReader r = new InputStreamReader(is);
  28.192 -        for (;;) {
  28.193 -            int ch = r.read();
  28.194 -            if (ch == -1) {
  28.195 -                break;
  28.196 -            }
  28.197 -            sb.append((char)ch);
  28.198 -        }
  28.199 -        return LoadJSON.parse(sb.toString());
  28.200 -    }
  28.201 -
  28.202 -    @Override
  28.203 -    public void runSafe(final Runnable r) {
  28.204 -        LOG.warning("Technology.runSafe has been deprecated. Use BrwsrCtx.execute!");
  28.205 -        r.run();
  28.206 -    }
  28.207 -
  28.208 -    @Override
  28.209 -    public LoadWS open(String url, JSONCall onReply) {
  28.210 -        return new LoadWS(onReply, url);
  28.211 -    }
  28.212 -
  28.213 -    @Override
  28.214 -    public void send(LoadWS socket, JSONCall data) {
  28.215 -        socket.send(data);
  28.216 -    }
  28.217 -
  28.218 -    @Override
  28.219 -    public void close(LoadWS socket) {
  28.220 -        socket.close();
  28.221 -    }
  28.222 -
  28.223 -    boolean areWebSocketsSupported() {
  28.224 -        return Knockout.areWebSocketsSupported();
  28.225 -    }
  28.226 -
  28.227 -    private static final class TrueFn extends Fn implements Fn.Presenter {
  28.228 -        @Override
  28.229 -        public Object invoke(Object thiz, Object... args) throws Exception {
  28.230 -            return true;
  28.231 -        }
  28.232 -
  28.233 -        @Override
  28.234 -        public Fn defineFn(String code, String... names) {
  28.235 -            return this;
  28.236 -        }
  28.237 -
  28.238 -        @Override
  28.239 -        public void displayPage(URL page, Runnable onPageLoad) {
  28.240 -        }
  28.241 -
  28.242 -        @Override
  28.243 -        public void loadScript(Reader code) throws Exception {
  28.244 -        }
  28.245 -    } // end of TrueFn
  28.246 -}
    29.1 --- a/ko4j/src/main/java/org/netbeans/html/ko4j/KO4J.java	Tue Dec 09 07:23:22 2014 +0100
    29.2 +++ b/ko4j/src/main/java/org/netbeans/html/ko4j/KO4J.java	Tue Dec 09 08:33:22 2014 +0100
    29.3 @@ -42,7 +42,9 @@
    29.4   */
    29.5  package org.netbeans.html.ko4j;
    29.6  
    29.7 +import java.util.logging.Logger;
    29.8  import net.java.html.json.Model;
    29.9 +import net.java.html.json.OnReceive;
   29.10  import org.netbeans.html.boot.spi.Fn;
   29.11  import org.netbeans.html.context.spi.Contexts;
   29.12  import org.netbeans.html.context.spi.Contexts.Provider;
   29.13 @@ -54,35 +56,49 @@
   29.14  /** Support for <a href="http://knockoutjs.com">knockout.js</a>
   29.15   * and its Java binding via {@link Model model classes}.
   29.16   * Registers {@link Provider}, so {@link java.util.ServiceLoader} can find it.
   29.17 + * The provider registers following technologies:
   29.18 + * <ul>
   29.19 + * <li><b>ko4j</b> - bindings for <a href="http://knockoutjs.com">knockout.js</a>
   29.20 + *   and the classes generated by the {@link Model} annotation.
   29.21 + * </li>
   29.22 + * <li><b>xhr</b> - <a href="http://www.w3.org/TR/XMLHttpRequest/">XMLHttpRequest</a>
   29.23 + *   based implementation for <em>REST</em> calls 
   29.24 + *   (<b>GET</b>, <b>PUT</b>, <b>POST</b>, <b>DELETE</b> methods) 
   29.25 + *   for {@link OnReceive} annotation.
   29.26 + * </li>
   29.27 + * <li><b>websocket</b> - 
   29.28 + *   native browser <a href="http://www.w3.org/TR/websockets/">websockets</a>
   29.29 + *   based implementation for {@link OnReceive} annotation and its <b>WebSocket</b>
   29.30 + *   subprotocol.
   29.31 + * </li>
   29.32 + * </ul>
   29.33   *
   29.34   * @author Jaroslav Tulach
   29.35   * @since 0.7
   29.36   */
   29.37  @ServiceProvider(service = Provider.class)
   29.38  public final class KO4J implements Provider {
   29.39 -    private final Fn.Presenter presenter;
   29.40 -    private FXContext c;
   29.41 +    static final Logger LOG = Logger.getLogger(KOSockets.class.getName());
   29.42 +    private KOTech ko4j;
   29.43 +    private KOTransfer trans;
   29.44 +    private KOSockets socks;
   29.45      
   29.46      public KO4J() {
   29.47          this(null);
   29.48      }
   29.49 -    
   29.50 +
   29.51 +    @Deprecated
   29.52      public KO4J(Fn.Presenter presenter) {
   29.53 -        this.presenter = presenter;
   29.54 -    }
   29.55 -    
   29.56 -    private FXContext getKO() {
   29.57 -        if (c == null) {
   29.58 -            c = new FXContext(presenter == null ? Fn.activePresenter() : presenter);
   29.59 -        }
   29.60 -        return c;
   29.61      }
   29.62      
   29.63      /** Return instance of the knockout.js for Java technology.
   29.64       * @return non-null instance
   29.65       */
   29.66      public Technology knockout() {
   29.67 -        return getKO();
   29.68 +        if (ko4j == null) {
   29.69 +            ko4j = new KOTech();
   29.70 +        }
   29.71 +        return ko4j;
   29.72      }
   29.73      
   29.74      /** Browser based implementation of transfer interface. Uses
   29.75 @@ -91,7 +107,10 @@
   29.76       * @return non-null instance
   29.77       */
   29.78      public Transfer transfer() {
   29.79 -        return getKO();
   29.80 +        if (trans == null) {
   29.81 +            trans = new KOTransfer();
   29.82 +        }
   29.83 +        return trans;
   29.84      }
   29.85      
   29.86      /** Returns browser based implementation of websocket transfer.
   29.87 @@ -102,7 +121,13 @@
   29.88       *   <code>WebSocket</code> object in the browser
   29.89       */
   29.90      public WSTransfer<?> websockets() {
   29.91 -        return getKO().areWebSocketsSupported() ? getKO() : null;
   29.92 +        if (!KOSockets.areWebSocketsSupported()) {
   29.93 +            return null;
   29.94 +        }
   29.95 +        if (socks == null) {
   29.96 +            socks = new KOSockets();
   29.97 +        }
   29.98 +        return socks;
   29.99      }
  29.100  
  29.101      /** Registers technologies at position 100:
    30.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    30.2 +++ b/ko4j/src/main/java/org/netbeans/html/ko4j/KOSockets.java	Tue Dec 09 08:33:22 2014 +0100
    30.3 @@ -0,0 +1,81 @@
    30.4 +/**
    30.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    30.6 + *
    30.7 + * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
    30.8 + *
    30.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   30.10 + * Other names may be trademarks of their respective owners.
   30.11 + *
   30.12 + * The contents of this file are subject to the terms of either the GNU
   30.13 + * General Public License Version 2 only ("GPL") or the Common
   30.14 + * Development and Distribution License("CDDL") (collectively, the
   30.15 + * "License"). You may not use this file except in compliance with the
   30.16 + * License. You can obtain a copy of the License at
   30.17 + * http://www.netbeans.org/cddl-gplv2.html
   30.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   30.19 + * specific language governing permissions and limitations under the
   30.20 + * License.  When distributing the software, include this License Header
   30.21 + * Notice in each file and include the License file at
   30.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   30.23 + * particular file as subject to the "Classpath" exception as provided
   30.24 + * by Oracle in the GPL Version 2 section of the License file that
   30.25 + * accompanied this code. If applicable, add the following below the
   30.26 + * License Header, with the fields enclosed by brackets [] replaced by
   30.27 + * your own identifying information:
   30.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   30.29 + *
   30.30 + * Contributor(s):
   30.31 + *
   30.32 + * The Original Software is NetBeans. The Initial Developer of the Original
   30.33 + * Software is Oracle. Portions Copyright 2013-2014 Oracle. All Rights Reserved.
   30.34 + *
   30.35 + * If you wish your version of this file to be governed by only the CDDL
   30.36 + * or only the GPL Version 2, indicate your decision by adding
   30.37 + * "[Contributor] elects to include this software in this distribution
   30.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   30.39 + * single choice of license, a recipient has the option to distribute
   30.40 + * your version of this file under either the CDDL, the GPL Version 2 or
   30.41 + * to extend the choice of license to its licensees as provided above.
   30.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   30.43 + * Version 2 license, then the option applies only if the new code is
   30.44 + * made subject to such option by the copyright holder.
   30.45 + */
   30.46 +package org.netbeans.html.ko4j;
   30.47 +
   30.48 +import net.java.html.js.JavaScriptBody;
   30.49 +import org.netbeans.html.context.spi.Contexts;
   30.50 +import org.netbeans.html.json.spi.JSONCall;
   30.51 +import org.netbeans.html.json.spi.WSTransfer;
   30.52 +
   30.53 +/** This is an implementation package - just
   30.54 + * include its JAR on classpath and use official {@link Context} API
   30.55 + * to access the functionality.
   30.56 + *
   30.57 + * @author Jaroslav Tulach
   30.58 + */
   30.59 +@Contexts.Id("websocket")
   30.60 +final class KOSockets
   30.61 +implements WSTransfer<LoadWS> {
   30.62 +    KOSockets() {
   30.63 +    }
   30.64 +    
   30.65 +    @Override
   30.66 +    public LoadWS open(String url, JSONCall onReply) {
   30.67 +        return new LoadWS(onReply, url);
   30.68 +    }
   30.69 +
   30.70 +    @Override
   30.71 +    public void send(LoadWS socket, JSONCall data) {
   30.72 +        socket.send(data);
   30.73 +    }
   30.74 +
   30.75 +    @Override
   30.76 +    public void close(LoadWS socket) {
   30.77 +        socket.close();
   30.78 +    }
   30.79 +
   30.80 +    @JavaScriptBody(args = {}, body = "if (window['WebSocket']) return true; else return false;")
   30.81 +    static final boolean areWebSocketsSupported() {
   30.82 +        return false;
   30.83 +    }
   30.84 +}
    31.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    31.2 +++ b/ko4j/src/main/java/org/netbeans/html/ko4j/KOTech.java	Tue Dec 09 08:33:22 2014 +0100
    31.3 @@ -0,0 +1,155 @@
    31.4 +/**
    31.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    31.6 + *
    31.7 + * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
    31.8 + *
    31.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   31.10 + * Other names may be trademarks of their respective owners.
   31.11 + *
   31.12 + * The contents of this file are subject to the terms of either the GNU
   31.13 + * General Public License Version 2 only ("GPL") or the Common
   31.14 + * Development and Distribution License("CDDL") (collectively, the
   31.15 + * "License"). You may not use this file except in compliance with the
   31.16 + * License. You can obtain a copy of the License at
   31.17 + * http://www.netbeans.org/cddl-gplv2.html
   31.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   31.19 + * specific language governing permissions and limitations under the
   31.20 + * License.  When distributing the software, include this License Header
   31.21 + * Notice in each file and include the License file at
   31.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   31.23 + * particular file as subject to the "Classpath" exception as provided
   31.24 + * by Oracle in the GPL Version 2 section of the License file that
   31.25 + * accompanied this code. If applicable, add the following below the
   31.26 + * License Header, with the fields enclosed by brackets [] replaced by
   31.27 + * your own identifying information:
   31.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   31.29 + *
   31.30 + * Contributor(s):
   31.31 + *
   31.32 + * The Original Software is NetBeans. The Initial Developer of the Original
   31.33 + * Software is Oracle. Portions Copyright 2013-2014 Oracle. All Rights Reserved.
   31.34 + *
   31.35 + * If you wish your version of this file to be governed by only the CDDL
   31.36 + * or only the GPL Version 2, indicate your decision by adding
   31.37 + * "[Contributor] elects to include this software in this distribution
   31.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   31.39 + * single choice of license, a recipient has the option to distribute
   31.40 + * your version of this file under either the CDDL, the GPL Version 2 or
   31.41 + * to extend the choice of license to its licensees as provided above.
   31.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   31.43 + * Version 2 license, then the option applies only if the new code is
   31.44 + * made subject to such option by the copyright holder.
   31.45 + */
   31.46 +package org.netbeans.html.ko4j;
   31.47 +
   31.48 +import org.netbeans.html.context.spi.Contexts;
   31.49 +import org.netbeans.html.json.spi.FunctionBinding;
   31.50 +import org.netbeans.html.json.spi.PropertyBinding;
   31.51 +import org.netbeans.html.json.spi.Technology;
   31.52 +import static org.netbeans.html.ko4j.KO4J.LOG;
   31.53 +
   31.54 +/** This is an implementation package - just
   31.55 + * include its JAR on classpath and use official {@link Context} API
   31.56 + * to access the functionality.
   31.57 + * <p>
   31.58 + *
   31.59 + * @author Jaroslav Tulach
   31.60 + */
   31.61 +@Contexts.Id("ko4j")
   31.62 +final class KOTech
   31.63 +implements Technology.BatchInit<Object>, Technology.ValueMutated<Object> {
   31.64 +    private Object[] jsObjects;
   31.65 +    private int jsIndex;
   31.66 +
   31.67 +    public KOTech() {
   31.68 +    }
   31.69 +    
   31.70 +    @Override
   31.71 +    public Object wrapModel(Object model, PropertyBinding[] propArr, FunctionBinding[] funcArr) {
   31.72 +        String[] propNames = new String[propArr.length];
   31.73 +        boolean[] propReadOnly = new boolean[propArr.length];
   31.74 +        Object[] propValues = new Object[propArr.length];
   31.75 +        for (int i = 0; i < propNames.length; i++) {
   31.76 +            propNames[i] = propArr[i].getPropertyName();
   31.77 +            propReadOnly[i] = propArr[i].isReadOnly();
   31.78 +            propValues[i] = propArr[i].getValue();
   31.79 +        }
   31.80 +        String[] funcNames = new String[funcArr.length];
   31.81 +        for (int i = 0; i < funcNames.length; i++) {
   31.82 +            funcNames[i] = funcArr[i].getFunctionName();
   31.83 +        }
   31.84 +        Object ret = getJSObject();
   31.85 +        Knockout.wrapModel(new Knockout(model, ret, propArr, funcArr),
   31.86 +            ret, 
   31.87 +            propNames, propReadOnly, propValues,
   31.88 +            funcNames
   31.89 +        );
   31.90 +        return ret;
   31.91 +    }
   31.92 +    
   31.93 +    private Object getJSObject() {
   31.94 +        int len = 64;
   31.95 +        if (jsObjects != null && jsIndex < (len = jsObjects.length)) {
   31.96 +            Object ret = jsObjects[jsIndex];
   31.97 +            jsObjects[jsIndex] = null;
   31.98 +            jsIndex++;
   31.99 +            return ret;
  31.100 +        }
  31.101 +        jsObjects = Knockout.allocJS(len * 2);
  31.102 +        jsIndex = 1;
  31.103 +        Object ret = jsObjects[0];
  31.104 +        jsObjects[0] = null;
  31.105 +        return ret;
  31.106 +    }
  31.107 +    
  31.108 +    @Override
  31.109 +    public Object wrapModel(Object model) {
  31.110 +        throw new UnsupportedOperationException();
  31.111 +    }
  31.112 +
  31.113 +    @Override
  31.114 +    public void bind(PropertyBinding b, Object model, Object data) {
  31.115 +        throw new UnsupportedOperationException();
  31.116 +    }
  31.117 +
  31.118 +    @Override
  31.119 +    public void valueHasMutated(Object data, String propertyName) {
  31.120 +        Knockout.cleanUp();
  31.121 +        Knockout.valueHasMutated(data, propertyName, null, null);
  31.122 +    }
  31.123 +    
  31.124 +    @Override
  31.125 +    public void valueHasMutated(Object data, String propertyName, Object oldValue, Object newValue) {
  31.126 +        Knockout.cleanUp();
  31.127 +        Knockout.valueHasMutated(data, propertyName, oldValue, newValue);
  31.128 +    }
  31.129 +
  31.130 +    @Override
  31.131 +    public void expose(FunctionBinding fb, Object model, Object d) {
  31.132 +        throw new UnsupportedOperationException();
  31.133 +    }
  31.134 +
  31.135 +    @Override
  31.136 +    public void applyBindings(Object data) {
  31.137 +        Object ko = Knockout.applyBindings(data);
  31.138 +        if (ko instanceof Knockout) {
  31.139 +            ((Knockout)ko).hold();
  31.140 +        }
  31.141 +    }
  31.142 +
  31.143 +    @Override
  31.144 +    public Object wrapArray(Object[] arr) {
  31.145 +        return arr;
  31.146 +    }
  31.147 +    
  31.148 +    @Override
  31.149 +    public void runSafe(final Runnable r) {
  31.150 +        LOG.warning("Technology.runSafe has been deprecated. Use BrwsrCtx.execute!");
  31.151 +        r.run();
  31.152 +    }    
  31.153 +
  31.154 +    @Override
  31.155 +    public <M> M toModel(Class<M> modelClass, Object data) {
  31.156 +        return modelClass.cast(Knockout.toModel(data));
  31.157 +    }
  31.158 +}
    32.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    32.2 +++ b/ko4j/src/main/java/org/netbeans/html/ko4j/KOTransfer.java	Tue Dec 09 08:33:22 2014 +0100
    32.3 @@ -0,0 +1,104 @@
    32.4 +/**
    32.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    32.6 + *
    32.7 + * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
    32.8 + *
    32.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   32.10 + * Other names may be trademarks of their respective owners.
   32.11 + *
   32.12 + * The contents of this file are subject to the terms of either the GNU
   32.13 + * General Public License Version 2 only ("GPL") or the Common
   32.14 + * Development and Distribution License("CDDL") (collectively, the
   32.15 + * "License"). You may not use this file except in compliance with the
   32.16 + * License. You can obtain a copy of the License at
   32.17 + * http://www.netbeans.org/cddl-gplv2.html
   32.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   32.19 + * specific language governing permissions and limitations under the
   32.20 + * License.  When distributing the software, include this License Header
   32.21 + * Notice in each file and include the License file at
   32.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   32.23 + * particular file as subject to the "Classpath" exception as provided
   32.24 + * by Oracle in the GPL Version 2 section of the License file that
   32.25 + * accompanied this code. If applicable, add the following below the
   32.26 + * License Header, with the fields enclosed by brackets [] replaced by
   32.27 + * your own identifying information:
   32.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   32.29 + *
   32.30 + * Contributor(s):
   32.31 + *
   32.32 + * The Original Software is NetBeans. The Initial Developer of the Original
   32.33 + * Software is Oracle. Portions Copyright 2013-2014 Oracle. All Rights Reserved.
   32.34 + *
   32.35 + * If you wish your version of this file to be governed by only the CDDL
   32.36 + * or only the GPL Version 2, indicate your decision by adding
   32.37 + * "[Contributor] elects to include this software in this distribution
   32.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   32.39 + * single choice of license, a recipient has the option to distribute
   32.40 + * your version of this file under either the CDDL, the GPL Version 2 or
   32.41 + * to extend the choice of license to its licensees as provided above.
   32.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   32.43 + * Version 2 license, then the option applies only if the new code is
   32.44 + * made subject to such option by the copyright holder.
   32.45 + */
   32.46 +package org.netbeans.html.ko4j;
   32.47 +
   32.48 +import java.io.ByteArrayOutputStream;
   32.49 +import java.io.IOException;
   32.50 +import java.io.InputStream;
   32.51 +import java.io.InputStreamReader;
   32.52 +import org.netbeans.html.context.spi.Contexts;
   32.53 +import org.netbeans.html.json.spi.JSONCall;
   32.54 +import org.netbeans.html.json.spi.Transfer;
   32.55 +
   32.56 +/** This is an implementation package - just
   32.57 + * include its JAR on classpath and use official {@link Context} API
   32.58 + * to access the functionality.
   32.59 + * <p>
   32.60 + *
   32.61 + * @author Jaroslav Tulach
   32.62 + */
   32.63 +@Contexts.Id("xhr")
   32.64 +final class KOTransfer
   32.65 +implements Transfer {
   32.66 +    KOTransfer() {
   32.67 +    }
   32.68 +    
   32.69 +    @Override
   32.70 +    public void extract(Object obj, String[] props, Object[] values) {
   32.71 +        LoadJSON.extractJSON(obj, props, values);
   32.72 +    }
   32.73 +
   32.74 +    @Override
   32.75 +    public void loadJSON(final JSONCall call) {
   32.76 +        if (call.isJSONP()) {
   32.77 +            String me = LoadJSON.createJSONP(call);
   32.78 +            LoadJSON.loadJSONP(call.composeURL(me), me);
   32.79 +        } else {
   32.80 +            String data = null;
   32.81 +            if (call.isDoOutput()) {
   32.82 +                try {
   32.83 +                    ByteArrayOutputStream bos = new ByteArrayOutputStream();
   32.84 +                    call.writeData(bos);
   32.85 +                    data = new String(bos.toByteArray(), "UTF-8");
   32.86 +                } catch (IOException ex) {
   32.87 +                    call.notifyError(ex);
   32.88 +                }
   32.89 +            }
   32.90 +            LoadJSON.loadJSON(call.composeURL(null), call, call.getMethod(), data);
   32.91 +        }
   32.92 +    }
   32.93 +
   32.94 +    @Override
   32.95 +    public Object toJSON(InputStream is) throws IOException {
   32.96 +        StringBuilder sb = new StringBuilder();
   32.97 +        InputStreamReader r = new InputStreamReader(is);
   32.98 +        for (;;) {
   32.99 +            int ch = r.read();
  32.100 +            if (ch == -1) {
  32.101 +                break;
  32.102 +            }
  32.103 +            sb.append((char)ch);
  32.104 +        }
  32.105 +        return LoadJSON.parse(sb.toString());
  32.106 +    }
  32.107 +}
    33.1 --- a/ko4j/src/main/java/org/netbeans/html/ko4j/Knockout.java	Tue Dec 09 07:23:22 2014 +0100
    33.2 +++ b/ko4j/src/main/java/org/netbeans/html/ko4j/Knockout.java	Tue Dec 09 08:33:22 2014 +0100
    33.3 @@ -229,9 +229,4 @@
    33.4              return o;
    33.5          }
    33.6      }
    33.7 -    
    33.8 -    @JavaScriptBody(args = {}, body = "if (window['WebSocket']) return true; else return false;")
    33.9 -    static final boolean areWebSocketsSupported() {
   33.10 -        return false;
   33.11 -    }
   33.12  }
    34.1 --- a/ko4j/src/test/java/org/netbeans/html/ko4j/KnockoutFXTest.java	Tue Dec 09 07:23:22 2014 +0100
    34.2 +++ b/ko4j/src/test/java/org/netbeans/html/ko4j/KnockoutFXTest.java	Tue Dec 09 08:33:22 2014 +0100
    34.3 @@ -153,12 +153,12 @@
    34.4      
    34.5      @Override
    34.6      public BrwsrCtx createContext() {
    34.7 -        FXContext fx = new FXContext(browserContext);
    34.8 +        KO4J ko4j = new KO4J();
    34.9          Contexts.Builder cb = Contexts.newBuilder().
   34.10 -            register(Technology.class, fx, 10).
   34.11 -            register(Transfer.class, fx, 10);
   34.12 -        if (fx.areWebSocketsSupported()) {
   34.13 -            cb.register(WSTransfer.class, fx, 10);
   34.14 +            register(Technology.class, ko4j.knockout(), 10).
   34.15 +            register(Transfer.class, ko4j.transfer(), 10);
   34.16 +        if (ko4j.websockets() != null) {
   34.17 +            cb.register(WSTransfer.class, ko4j.websockets(), 10);
   34.18          }
   34.19          cb.register(Executor.class, (Executor)browserContext, 10);
   34.20          cb.register(Fn.Presenter.class, browserContext, 10);
    35.1 --- a/pom.xml	Tue Dec 09 07:23:22 2014 +0100
    35.2 +++ b/pom.xml	Tue Dec 09 08:33:22 2014 +0100
    35.3 @@ -35,6 +35,7 @@
    35.4      <module>ko-osgi-test</module>
    35.5      <module>equinox-agentclass-hook</module>
    35.6      <module>boot-script</module>
    35.7 +    <module>boot-agent-test</module>
    35.8    </modules>
    35.9    <licenses>
   35.10        <license>
   35.11 @@ -246,7 +247,7 @@
   35.12          <dependency>
   35.13              <groupId>org.ow2.asm</groupId>
   35.14              <artifactId>asm</artifactId>
   35.15 -            <version>4.1</version>
   35.16 +            <version>5.0</version>
   35.17          </dependency>
   35.18          <dependency>
   35.19            <groupId>org.netbeans.api</groupId>
    36.1 --- a/src/main/javadoc/overview.html	Tue Dec 09 07:23:22 2014 +0100
    36.2 +++ b/src/main/javadoc/overview.html	Tue Dec 09 08:33:22 2014 +0100
    36.3 @@ -78,6 +78,22 @@
    36.4          <h3>What's New in Version 1.1?</h3>
    36.5          
    36.6          <p>
    36.7 +            The content of a {@link net.java.html.BrwsrCtx context}
    36.8 +            can be selected by registering implementations under specific
    36.9 +            {@link org.netbeans.html.context.spi.Contexts.Id technology identifiers} 
   36.10 +            and requesting them during 
   36.11 +            {@link org.netbeans.html.context.spi.Contexts#newBuilder(java.lang.Object...) construction} 
   36.12 +            of the context. <code>org.netbeans.html:ko4j</code> module's implementation
   36.13 +            offers <b>ko4j</b>, <b>xhr</b> and <b>websocket</b> identifiers
   36.14 +            for its registered services 
   36.15 +            (e.g. {@link org.netbeans.html.json.spi.Technology},
   36.16 +            {@link org.netbeans.html.json.spi.Transfer} and
   36.17 +            {@link org.netbeans.html.json.spi.WSTransfer}).
   36.18 +            <code>org.netbeans.html:ko-ws-tyrus</code>
   36.19 +            module registers its 
   36.20 +            {@link org.netbeans.html.json.spi.Transfer Java based JSON} and 
   36.21 +            {@link org.netbeans.html.json.spi.WSTransfer WebSocket} implementations
   36.22 +            under the name <b>tyrus</b>.
   36.23              Memory model when using Knockout bindings has been improved
   36.24              (required additions of two new methods:
   36.25              {@link org.netbeans.html.json.spi.PropertyBinding#weak()} and
   36.26 @@ -107,6 +123,28 @@
   36.27              prevent endless debugging when one forgets to do so.
   36.28          </p>
   36.29          
   36.30 +        <p>
   36.31 +        What's new in older versions? Click the 
   36.32 +        <a href="#" onclick="return showHistoric(true)">link</a> 
   36.33 +        to view even more 
   36.34 +        <a href="#" onclick="return showHistoric(true)">historic changes</a> below:
   36.35 +        </p>
   36.36 +        
   36.37 +        <a name="historic.changes"></a>
   36.38 +        <div id="historic.changes">
   36.39 +            <script>
   36.40 +            function showHistoric(show) {
   36.41 +                var e = document.getElementById("historic.changes");
   36.42 +                if (show) {
   36.43 +                    e.style.display="block";
   36.44 +                } else {
   36.45 +                    e.style.display="none";
   36.46 +                }
   36.47 +                return false;
   36.48 +            }
   36.49 +            showHistoric(false);
   36.50 +            </script>
   36.51 +            
   36.52          <h3>What's New in Version 0.9?</h3>
   36.53          
   36.54          <p>
   36.55 @@ -173,7 +211,7 @@
   36.56          </p>
   36.57          
   36.58          
   36.59 -        <h3>What's New in Older Versions?</h3>
   36.60 +        <h3>What's New in 0.7.x Versions?</h3>
   36.61          
   36.62          <p>
   36.63              {@link net.java.html.js.JavaScriptBody} annotation has new attribute
   36.64 @@ -190,6 +228,7 @@
   36.65              See example 
   36.66              {@link net.java.html.BrwsrCtx#execute(java.lang.Runnable) using Java timer}.
   36.67          </p>
   36.68 +        </div>
   36.69          
   36.70          <h3>Interesting Entry Points</h3>
   36.71