BrwsrCtx.execute(Runnable) and using it whenever one mangles with @Model classes
1.1 --- a/boot-fx/src/test/java/org/netbeans/html/boot/fx/BootstrapTest.java Mon Mar 03 15:14:46 2014 +0100
1.2 +++ b/boot-fx/src/test/java/org/netbeans/html/boot/fx/BootstrapTest.java Mon Mar 03 23:30:02 2014 +0100
1.3 @@ -47,10 +47,16 @@
1.4 import java.util.ArrayList;
1.5 import java.util.List;
1.6 import java.util.concurrent.Executors;
1.7 +import net.java.html.BrwsrCtx;
1.8 import net.java.html.boot.BrowserBuilder;
1.9 import org.apidesign.html.boot.spi.Fn;
1.10 +import org.apidesign.html.context.spi.Contexts;
1.11 import org.apidesign.html.json.tck.KOTest;
1.12 +import org.openide.util.lookup.ServiceProvider;
1.13 import org.testng.Assert;
1.14 +import static org.testng.Assert.assertNotSame;
1.15 +import static org.testng.Assert.assertSame;
1.16 +import static org.testng.Assert.assertTrue;
1.17 import org.testng.annotations.Factory;
1.18
1.19 /**
1.20 @@ -106,6 +112,11 @@
1.21 }
1.22
1.23 public static void initialized() throws Exception {
1.24 + BrwsrCtx b1 = BrwsrCtx.findDefault(BootstrapTest.class);
1.25 + TestingProvider.assertCalled("Our context created");
1.26 + assertNotSame(b1, BrwsrCtx.EMPTY, "Browser context is not empty");
1.27 + BrwsrCtx b2 = BrwsrCtx.findDefault(BootstrapTest.class);
1.28 + assertSame(b1, b2, "Browser context remains stable");
1.29 Assert.assertSame(
1.30 BootstrapTest.class.getClassLoader(),
1.31 ClassLoader.getSystemClassLoader(),
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2.2 +++ b/boot-fx/src/test/java/org/netbeans/html/boot/fx/TestingProvider.java Mon Mar 03 23:30:02 2014 +0100
2.3 @@ -0,0 +1,65 @@
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.boot.fx;
2.47 +
2.48 +import org.apidesign.html.context.spi.Contexts;
2.49 +import org.openide.util.lookup.ServiceProvider;
2.50 +import static org.testng.Assert.assertTrue;
2.51 +
2.52 +/**
2.53 + *
2.54 + * @author Jaroslav Tulach <jtulach@netbeans.org>
2.55 + */
2.56 +@ServiceProvider(service = Contexts.Provider.class)
2.57 +public final class TestingProvider implements Contexts.Provider {
2.58 +
2.59 + static void assertCalled(String msg) {
2.60 + assertTrue(Boolean.getBoolean(TestingProvider.class.getName()), msg);
2.61 + }
2.62 +
2.63 + @Override
2.64 + public void fillContext(Contexts.Builder context, Class<?> requestor) {
2.65 + System.setProperty(TestingProvider.class.getName(), "true");
2.66 + }
2.67 +
2.68 +}
3.1 --- a/boot/pom.xml Mon Mar 03 15:14:46 2014 +0100
3.2 +++ b/boot/pom.xml Mon Mar 03 23:30:02 2014 +0100
3.3 @@ -48,6 +48,12 @@
3.4 <artifactId>org-openide-util-lookup</artifactId>
3.5 <scope>provided</scope>
3.6 </dependency>
3.7 + <dependency>
3.8 + <groupId>org.netbeans.html</groupId>
3.9 + <artifactId>net.java.html</artifactId>
3.10 + <version>${project.version}</version>
3.11 + <type>jar</type>
3.12 + </dependency>
3.13 </dependencies>
3.14 <description>Builder to launch your Java/HTML based application.</description>
3.15 </project>
4.1 --- a/boot/src/main/java/net/java/html/boot/BrowserBuilder.java Mon Mar 03 15:14:46 2014 +0100
4.2 +++ b/boot/src/main/java/net/java/html/boot/BrowserBuilder.java Mon Mar 03 23:30:02 2014 +0100
4.3 @@ -53,6 +53,7 @@
4.4 import java.util.ServiceLoader;
4.5 import java.util.logging.Level;
4.6 import java.util.logging.Logger;
4.7 +import net.java.html.BrwsrCtx;
4.8 import net.java.html.js.JavaScriptBody;
4.9 import org.apidesign.html.boot.spi.Fn;
4.10 import org.netbeans.html.boot.impl.FindResources;
4.11 @@ -235,14 +236,21 @@
4.12
4.13 final Fn.Presenter currentP = dfnr;
4.14 class OnPageLoad implements Runnable {
4.15 + Class<?> newClazz;
4.16 @Override
4.17 public void run() {
4.18 try {
4.19 - Thread.currentThread().setContextClassLoader(loader);
4.20 - Class<?> newClazz = Class.forName(clazz.getName(), true, loader);
4.21 - if (browserClass != null) {
4.22 - browserClass[0] = newClazz;
4.23 + if (newClazz == null) {
4.24 + Thread.currentThread().setContextClassLoader(loader);
4.25 + newClazz = Class.forName(clazz.getName(), true, loader);
4.26 + if (browserClass != null) {
4.27 + browserClass[0] = newClazz;
4.28 + }
4.29 + BrwsrCtx c = BrwsrCtx.findDefault(newClazz);
4.30 + c.execute(this);
4.31 + return;
4.32 }
4.33 +
4.34 if (onLoad != null) {
4.35 onLoad.run();
4.36 }
5.1 --- a/context/pom.xml Mon Mar 03 15:14:46 2014 +0100
5.2 +++ b/context/pom.xml Mon Mar 03 23:30:02 2014 +0100
5.3 @@ -30,6 +30,12 @@
5.4 </plugins>
5.5 </build>
5.6 <dependencies>
5.7 + <dependency>
5.8 + <groupId>org.testng</groupId>
5.9 + <artifactId>testng</artifactId>
5.10 + <version>6.8.1</version>
5.11 + <scope>test</scope>
5.12 + </dependency>
5.13 </dependencies>
5.14 <description>Representation of an HTML page context a Java program operates in.</description>
5.15 </project>
6.1 --- a/context/src/main/java/net/java/html/BrwsrCtx.java Mon Mar 03 15:14:46 2014 +0100
6.2 +++ b/context/src/main/java/net/java/html/BrwsrCtx.java Mon Mar 03 23:30:02 2014 +0100
6.3 @@ -83,6 +83,9 @@
6.4 */
6.5 public static final BrwsrCtx EMPTY = Contexts.newBuilder().build();
6.6
6.7 + /** currently {@link #execute(java.lang.Runnable) activated context} */
6.8 + private static final ThreadLocal<BrwsrCtx> CURRENT = new ThreadLocal<BrwsrCtx>();
6.9 +
6.10 /** Seeks for the default context that is associated with the requesting
6.11 * class. If no suitable context is found, a warning message is
6.12 * printed and {@link #EMPTY} context is returned.
6.13 @@ -91,6 +94,11 @@
6.14 * @return appropriate context for the request
6.15 */
6.16 public static BrwsrCtx findDefault(Class<?> requestor) {
6.17 + BrwsrCtx brwsr = CURRENT.get();
6.18 + if (brwsr != null) {
6.19 + return brwsr;
6.20 + }
6.21 +
6.22 org.apidesign.html.context.spi.Contexts.Builder cb = Contexts.newBuilder();
6.23 boolean found = false;
6.24
6.25 @@ -130,5 +138,21 @@
6.26 }
6.27 return cb.build();
6.28 }
6.29 -
6.30 +
6.31 + /** Runs provided code in the context of this {@link BrwsrCtx}.
6.32 + * While the <code>exec</code> is running, the {@link #findDefault(java.lang.Class)}
6.33 + * method returns <code>this</code>.
6.34 + *
6.35 + * @param exec the code to execute
6.36 + * @since 0.7.6
6.37 + */
6.38 + public final void execute(Runnable exec) {
6.39 + BrwsrCtx prev = CURRENT.get();
6.40 + try {
6.41 + CURRENT.set(this);
6.42 + exec.run();
6.43 + } finally {
6.44 + CURRENT.set(prev);
6.45 + }
6.46 + }
6.47 }
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
7.2 +++ b/context/src/test/java/net/java/html/BrwsrCtxTest.java Mon Mar 03 23:30:02 2014 +0100
7.3 @@ -0,0 +1,75 @@
7.4 +/**
7.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
7.6 + *
7.7 + * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
7.8 + *
7.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7.10 + * Other names may be trademarks of their respective owners.
7.11 + *
7.12 + * The contents of this file are subject to the terms of either the GNU
7.13 + * General Public License Version 2 only ("GPL") or the Common
7.14 + * Development and Distribution License("CDDL") (collectively, the
7.15 + * "License"). You may not use this file except in compliance with the
7.16 + * License. You can obtain a copy of the License at
7.17 + * http://www.netbeans.org/cddl-gplv2.html
7.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
7.19 + * specific language governing permissions and limitations under the
7.20 + * License. When distributing the software, include this License Header
7.21 + * Notice in each file and include the License file at
7.22 + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
7.23 + * particular file as subject to the "Classpath" exception as provided
7.24 + * by Oracle in the GPL Version 2 section of the License file that
7.25 + * accompanied this code. If applicable, add the following below the
7.26 + * License Header, with the fields enclosed by brackets [] replaced by
7.27 + * your own identifying information:
7.28 + * "Portions Copyrighted [year] [name of copyright owner]"
7.29 + *
7.30 + * Contributor(s):
7.31 + *
7.32 + * The Original Software is NetBeans. The Initial Developer of the Original
7.33 + * Software is Oracle. Portions Copyright 2013-2014 Oracle. All Rights Reserved.
7.34 + *
7.35 + * If you wish your version of this file to be governed by only the CDDL
7.36 + * or only the GPL Version 2, indicate your decision by adding
7.37 + * "[Contributor] elects to include this software in this distribution
7.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
7.39 + * single choice of license, a recipient has the option to distribute
7.40 + * your version of this file under either the CDDL, the GPL Version 2 or
7.41 + * to extend the choice of license to its licensees as provided above.
7.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
7.43 + * Version 2 license, then the option applies only if the new code is
7.44 + * made subject to such option by the copyright holder.
7.45 + */
7.46 +package net.java.html;
7.47 +
7.48 +import org.apidesign.html.context.spi.Contexts;
7.49 +import static org.testng.Assert.*;
7.50 +
7.51 +/**
7.52 + *
7.53 + * @author Jaroslav Tulach <jtulach@netbeans.org>
7.54 + */
7.55 +public class BrwsrCtxTest {
7.56 +
7.57 + public BrwsrCtxTest() {
7.58 + }
7.59 +
7.60 +
7.61 + @org.testng.annotations.Test
7.62 + public void canSetAssociateCtx() {
7.63 + final BrwsrCtx ctx = Contexts.newBuilder().build();
7.64 + final boolean[] arr = { false };
7.65 +
7.66 + assertNotSame(BrwsrCtx.findDefault(BrwsrCtxTest.class), ctx, "Not associated yet");
7.67 + ctx.execute(new Runnable() {
7.68 + @Override public void run() {
7.69 + assertSame(BrwsrCtx.findDefault(BrwsrCtxTest.class), ctx, "Once same");
7.70 + assertSame(BrwsrCtx.findDefault(BrwsrCtxTest.class), ctx, "2nd same");
7.71 + arr[0] = true;
7.72 + }
7.73 + });
7.74 + assertNotSame(BrwsrCtx.findDefault(BrwsrCtxTest.class), ctx, "Not associated again");
7.75 + assertTrue(arr[0], "Runnable was executed");
7.76 + }
7.77 +
7.78 +}
7.79 \ No newline at end of file
8.1 --- a/json-tck/src/main/java/net/java/html/json/tests/JSONTest.java Mon Mar 03 15:14:46 2014 +0100
8.2 +++ b/json-tck/src/main/java/net/java/html/json/tests/JSONTest.java Mon Mar 03 23:30:02 2014 +0100
8.3 @@ -71,6 +71,7 @@
8.4 @ModelOperation static void assignFetched(JSONik m, Person p) {
8.5 m.setFetched(p);
8.6 }
8.7 + private BrwsrCtx ctx;
8.8
8.9 @KOTest public void toJSONInABrowser() throws Throwable {
8.10 Person p = Models.bind(new Person(), newContext());
8.11 @@ -150,16 +151,20 @@
8.12 assert p2.getFirstName().equals(p.getFirstName()) :
8.13 "Should be the same: " + p.getFirstName() + " != " + p2.getFirstName();
8.14 }
8.15 +
8.16 + private static BrwsrCtx onCallback;
8.17
8.18 @OnReceive(url="{url}")
8.19 static void fetch(Person p, JSONik model) {
8.20 model.setFetched(p);
8.21 + onCallback = BrwsrCtx.findDefault(model.getClass());
8.22 }
8.23
8.24 @OnReceive(url="{url}", onError = "setMessage")
8.25 static void fetchArray(Person[] p, JSONik model) {
8.26 model.setFetchedCount(p.length);
8.27 model.setFetched(p[0]);
8.28 + onCallback = BrwsrCtx.findDefault(model.getClass());
8.29 }
8.30
8.31 static void setMessage(JSONik m, Exception t) {
8.32 @@ -191,7 +196,7 @@
8.33 JSONTest.class, "{'firstName': 'Sitar', 'sex': 'MALE'}",
8.34 "application/json"
8.35 );
8.36 - js = Models.bind(new JSONik(), newContext());
8.37 + js = Models.bind(new JSONik(), ctx = newContext());
8.38 js.applyBindings();
8.39
8.40 js.setFetched(null);
8.41 @@ -205,6 +210,8 @@
8.42
8.43 assert "Sitar".equals(p.getFirstName()) : "Expecting Sitar: " + p.getFirstName();
8.44 assert Sex.MALE.equals(p.getSex()) : "Expecting MALE: " + p.getSex();
8.45 +
8.46 + assert ctx == onCallback;
8.47 }
8.48
8.49 @OnReceive(url="{url}?callme={me}", jsonp = "me")
9.1 --- a/json-tck/src/main/java/net/java/html/json/tests/KnockoutTest.java Mon Mar 03 15:14:46 2014 +0100
9.2 +++ b/json-tck/src/main/java/net/java/html/json/tests/KnockoutTest.java Mon Mar 03 23:30:02 2014 +0100
9.3 @@ -51,6 +51,7 @@
9.4 import net.java.html.json.Property;
9.5 import org.apidesign.html.json.tck.KOTest;
9.6 import org.apidesign.html.json.tck.KnockoutTCK;
9.7 +import static org.testng.Assert.assertSame;
9.8
9.9 /**
9.10 *
9.11 @@ -215,13 +216,16 @@
9.12 + "</div>\n"
9.13 );
9.14 try {
9.15 - Pair m = Models.bind(new Pair(null, null, new Pair("First", "Last", null)), newContext());
9.16 + final BrwsrCtx ctx = newContext();
9.17 + Pair m = Models.bind(new Pair(null, null, new Pair("First", "Last", null)), ctx);
9.18 m.applyBindings();
9.19
9.20 int cnt = countChildren("ul");
9.21 assert cnt == 2 : "Two children now, but was " + cnt;
9.22
9.23 triggerChildClick("ul", 1);
9.24 +
9.25 + assertSame(PairModel.ctx, ctx, "Context remains the same");
9.26
9.27 assert "Last".equals(m.getFirstName()) : "We got callback from 2nd child " + m.getFirstName();
9.28 } finally {
10.1 --- a/json-tck/src/main/java/net/java/html/json/tests/PairModel.java Mon Mar 03 15:14:46 2014 +0100
10.2 +++ b/json-tck/src/main/java/net/java/html/json/tests/PairModel.java Mon Mar 03 23:30:02 2014 +0100
10.3 @@ -44,6 +44,7 @@
10.4
10.5 import java.util.Arrays;
10.6 import java.util.List;
10.7 +import net.java.html.BrwsrCtx;
10.8 import net.java.html.json.ComputedProperty;
10.9 import net.java.html.json.Function;
10.10 import net.java.html.json.Model;
10.11 @@ -59,6 +60,8 @@
10.12 @Property(name = "next", type = Pair.class)
10.13 })
10.14 class PairModel {
10.15 + static BrwsrCtx ctx;
10.16 +
10.17 @ComputedProperty
10.18 static List<String> bothNames(String firstName, String lastName) {
10.19 return Arrays.asList(firstName, lastName);
10.20 @@ -71,6 +74,7 @@
10.21
10.22 @Function
10.23 static void assignFirstName(Pair m, String data) {
10.24 + ctx = BrwsrCtx.findDefault(Pair.class);
10.25 m.setFirstName(data);
10.26 }
10.27 }
11.1 --- a/json/src/main/java/org/apidesign/html/json/spi/FunctionBinding.java Mon Mar 03 15:14:46 2014 +0100
11.2 +++ b/json/src/main/java/org/apidesign/html/json/spi/FunctionBinding.java Mon Mar 03 23:30:02 2014 +0100
11.3 @@ -42,6 +42,7 @@
11.4 */
11.5 package org.apidesign.html.json.spi;
11.6
11.7 +import net.java.html.BrwsrCtx;
11.8 import net.java.html.json.Function;
11.9 import net.java.html.json.Model;
11.10
11.11 @@ -91,12 +92,19 @@
11.12 }
11.13
11.14 @Override
11.15 - public void call(Object data, Object ev) {
11.16 - try {
11.17 - access.call(model, index, data, ev);
11.18 - } catch (Throwable ex) {
11.19 - ex.printStackTrace();
11.20 + public void call(final Object data, final Object ev) {
11.21 + BrwsrCtx ctx = access.protoFor(model).getContext();
11.22 + class Dispatch implements Runnable {
11.23 + @Override
11.24 + public void run() {
11.25 + try {
11.26 + access.call(model, index, data, ev);
11.27 + } catch (Throwable ex) {
11.28 + ex.printStackTrace();
11.29 + }
11.30 + }
11.31 }
11.32 + ctx.execute(new Dispatch());
11.33 }
11.34 }
11.35 }
12.1 --- a/json/src/main/java/org/netbeans/html/json/impl/JSON.java Mon Mar 03 15:14:46 2014 +0100
12.2 +++ b/json/src/main/java/org/netbeans/html/json/impl/JSON.java Mon Mar 03 23:30:02 2014 +0100
12.3 @@ -80,8 +80,14 @@
12.4 return t == null ? EmptyTech.EMPTY : t;
12.5 }
12.6
12.7 - public static void runInBrowser(BrwsrCtx c, Runnable runnable) {
12.8 - findTechnology(c).runSafe(runnable);
12.9 + public static void runInBrowser(final BrwsrCtx c, final Runnable runnable) {
12.10 + class Wrap implements Runnable {
12.11 + @Override
12.12 + public void run() {
12.13 + c.execute(runnable);
12.14 + }
12.15 + }
12.16 + findTechnology(c).runSafe(new Wrap());
12.17 }
12.18
12.19 public static void extract(BrwsrCtx c, Object value, String[] props, Object[] values) {
12.20 @@ -492,7 +498,7 @@
12.21 }
12.22
12.23 @Override
12.24 - public synchronized void runSafe(Runnable r) {
12.25 + public void runSafe(Runnable r) {
12.26 r.run();
12.27 }
12.28
13.1 --- a/json/src/test/java/net/java/html/json/OperationTest.java Mon Mar 03 15:14:46 2014 +0100
13.2 +++ b/json/src/test/java/net/java/html/json/OperationTest.java Mon Mar 03 23:30:02 2014 +0100
13.3 @@ -42,7 +42,10 @@
13.4 */
13.5 package net.java.html.json;
13.6
13.7 +import net.java.html.BrwsrCtx;
13.8 +import org.apidesign.html.context.spi.Contexts;
13.9 import static org.testng.Assert.assertEquals;
13.10 +import static org.testng.Assert.assertSame;
13.11 import org.testng.annotations.Test;
13.12
13.13 /**
13.14 @@ -53,13 +56,15 @@
13.15 @Property(name = "names", type = String.class, array = true)
13.16 })
13.17 public class OperationTest {
13.18 - @ModelOperation static void add(OpModel m, String name) {
13.19 + @ModelOperation static void add(OpModel m, String name, BrwsrCtx exp) {
13.20 + assertSame(BrwsrCtx.findDefault(OpModel.class), exp, "Context is passed in");
13.21 m.getNames().add(name);
13.22 }
13.23
13.24 @Test public void addOneToTheModel() {
13.25 - OpModel m = new OpModel("One");
13.26 - m.add("Second");
13.27 + BrwsrCtx ctx = Contexts.newBuilder().build();
13.28 + OpModel m = Models.bind(new OpModel("One"), ctx);
13.29 + m.add("Second", ctx);
13.30 assertEquals(m.getNames().size(), 2, "Both are there: " + m.getNames());
13.31 }
13.32 }