1.1 --- a/boot-fx/src/main/java/org/netbeans/html/boot/fx/AbstractFXPresenter.java Thu Jul 17 17:22:41 2014 +0200
1.2 +++ b/boot-fx/src/main/java/org/netbeans/html/boot/fx/AbstractFXPresenter.java Thu Jul 17 18:01:03 2014 +0200
1.3 @@ -64,13 +64,28 @@
1.4 * @author Jaroslav Tulach
1.5 */
1.6 public abstract class AbstractFXPresenter
1.7 -implements Fn.Presenter, Fn.ToJavaScript, Fn.FromJavaScript, Executor {
1.8 +implements Fn.Presenter, Fn.ToJavaScript, Fn.FromJavaScript, Executor, Cloneable {
1.9 static final Logger LOG = Logger.getLogger(FXPresenter.class.getName());
1.10 protected static int cnt;
1.11 - protected List<String> scripts;
1.12 protected Runnable onLoad;
1.13 protected WebEngine engine;
1.14
1.15 + // transient - e.g. not cloneable
1.16 + private JSObject arraySize;
1.17 + private JSObject wrapArrImpl;
1.18 +
1.19 + @Override
1.20 + protected AbstractFXPresenter clone() {
1.21 + try {
1.22 + AbstractFXPresenter p = (AbstractFXPresenter) super.clone();
1.23 + p.arraySize = null;
1.24 + p.wrapArrImpl = null;
1.25 + return p;
1.26 + } catch (CloneNotSupportedException ex) {
1.27 + throw new IllegalStateException(ex);
1.28 + }
1.29 + }
1.30 +
1.31 @Override
1.32 public Fn defineFn(String code, String... names) {
1.33 return defineJSFn(code, names);
1.34 @@ -111,19 +126,20 @@
1.35 sb.append(l).append('\n');
1.36 }
1.37 final String script = sb.toString();
1.38 - if (scripts != null) {
1.39 - scripts.add(script);
1.40 - }
1.41 engine.executeScript(script);
1.42 }
1.43
1.44 protected final void onPageLoad() {
1.45 - if (scripts != null) {
1.46 - for (String s : scripts) {
1.47 - engine.executeScript(s);
1.48 + Closeable c = Fn.activate(this.clone());
1.49 + try {
1.50 + onLoad.run();
1.51 + } finally {
1.52 + try {
1.53 + c.close();
1.54 + } catch (IOException ex) {
1.55 + LOG.log(Level.SEVERE, null, ex);
1.56 }
1.57 }
1.58 - onLoad.run();
1.59 }
1.60
1.61 @Override
1.62 @@ -131,19 +147,21 @@
1.63 this.onLoad = onLoad;
1.64 final WebView view = findView(resource);
1.65 this.engine = view.getEngine();
1.66 + boolean inspectOn = false;
1.67 try {
1.68 if (FXInspect.initialize(engine)) {
1.69 - scripts = new ArrayList<String>();
1.70 + inspectOn = true;
1.71 }
1.72 } catch (Throwable ex) {
1.73 ex.printStackTrace();
1.74 }
1.75 + final boolean isInspectOn = inspectOn;
1.76
1.77 class Run implements Runnable {
1.78
1.79 @Override
1.80 public void run() {
1.81 - if (scripts != null) {
1.82 + if (isInspectOn) {
1.83 view.setContextMenuEnabled(true);
1.84 }
1.85 engine.load(resource.toExternalForm());
1.86 @@ -172,7 +190,6 @@
1.87 return wrapArr;
1.88 }
1.89
1.90 - private JSObject wrapArrImpl;
1.91 private final JSObject wrapArrFn() {
1.92 if (wrapArrImpl == null) {
1.93 try {
1.94 @@ -198,7 +215,6 @@
1.95 arraySizeFn().call("array", val, arr);
1.96 return arr;
1.97 }
1.98 - private JSObject arraySize;
1.99 private final JSObject arraySizeFn() {
1.100 if (arraySize == null) {
1.101 try {
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/ReloadTest.java Thu Jul 17 18:01:03 2014 +0200
2.3 @@ -0,0 +1,157 @@
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 java.util.concurrent.CountDownLatch;
2.49 +import java.util.concurrent.Executors;
2.50 +import javafx.application.Platform;
2.51 +import net.java.html.BrwsrCtx;
2.52 +import net.java.html.boot.BrowserBuilder;
2.53 +import net.java.html.js.JavaScriptBody;
2.54 +import org.apidesign.html.boot.spi.Fn;
2.55 +import static org.testng.Assert.*;
2.56 +import org.testng.annotations.Test;
2.57 +
2.58 +/**
2.59 + *
2.60 + * @author Jaroslav Tulach <jtulach@netbeans.org>
2.61 + */
2.62 +public class ReloadTest {
2.63 + private static Runnable whenInitialized;
2.64 +
2.65 + public ReloadTest() {
2.66 + }
2.67 +
2.68 + @JavaScriptBody(args = { "a", "b" }, body = "return a + b;")
2.69 + private static native int plus(int a, int b);
2.70 +
2.71 + @Test public void checkReload() throws Throwable {
2.72 + final Throwable[] arr = { null };
2.73 +
2.74 + final BrowserBuilder bb = BrowserBuilder.newBrowser().loadClass(ReloadTest.class).
2.75 + loadPage("empty.html").
2.76 + invoke("initialized");
2.77 +
2.78 + class ShowBrowser implements Runnable {
2.79 + @Override
2.80 + public void run() {
2.81 + bb.showAndWait();
2.82 + }
2.83 + }
2.84 +
2.85 + class WhenInitialized implements Runnable {
2.86 + CountDownLatch cdl = new CountDownLatch(1);
2.87 + AbstractFXPresenter p;
2.88 + BrwsrCtx ctx;
2.89 +
2.90 + @Override
2.91 + public void run() {
2.92 + try {
2.93 + whenInitialized = null;
2.94 + doCheckReload();
2.95 + p = (AbstractFXPresenter) Fn.activePresenter();
2.96 + assertNotNull(p, "Presenter is defined");
2.97 + ctx = BrwsrCtx.findDefault(WhenInitialized.class);
2.98 + } catch (Throwable ex) {
2.99 + arr[0] = ex;
2.100 + } finally {
2.101 + cdl.countDown();
2.102 + }
2.103 + }
2.104 + }
2.105 + WhenInitialized when = new WhenInitialized();
2.106 + whenInitialized = when;
2.107 + Executors.newSingleThreadExecutor().submit(new ShowBrowser());
2.108 + when.cdl.await();
2.109 + if (arr[0] != null) throw arr[0];
2.110 +
2.111 + class ReloadPage implements Runnable {
2.112 + final CountDownLatch cdl = new CountDownLatch(1);
2.113 + private final AbstractFXPresenter p;
2.114 +
2.115 + public ReloadPage(AbstractFXPresenter p) {
2.116 + this.p = p;
2.117 + }
2.118 +
2.119 + @Override
2.120 + public void run() {
2.121 + p.engine.reload();
2.122 + cdl.countDown();
2.123 + }
2.124 + }
2.125 + ReloadPage relPage = new ReloadPage(when.p);
2.126 +
2.127 + class SecondInit implements Runnable {
2.128 + CountDownLatch cdl = new CountDownLatch(1);
2.129 +
2.130 + @Override
2.131 + public void run() {
2.132 + try {
2.133 + whenInitialized = null;
2.134 + doCheckReload();
2.135 + } catch (Throwable ex) {
2.136 + arr[0] = ex;
2.137 + } finally {
2.138 + cdl.countDown();
2.139 + }
2.140 +
2.141 + }
2.142 + }
2.143 + SecondInit second = new SecondInit();
2.144 + whenInitialized = second;
2.145 +
2.146 + Platform.runLater(relPage);
2.147 +
2.148 + second.cdl.await();
2.149 + if (arr[0] != null) throw arr[0];
2.150 + }
2.151 +
2.152 + final void doCheckReload() throws Exception {
2.153 + int res = plus(30, 12);
2.154 + assertEquals(res, 42, "Meaning of world computed");
2.155 + }
2.156 +
2.157 + public static synchronized void initialized() throws Exception {
2.158 + whenInitialized.run();
2.159 + }
2.160 +}
3.1 --- a/boot/src/main/java/net/java/html/boot/BrowserBuilder.java Thu Jul 17 17:22:41 2014 +0200
3.2 +++ b/boot/src/main/java/net/java/html/boot/BrowserBuilder.java Thu Jul 17 18:01:03 2014 +0200
3.3 @@ -293,78 +293,83 @@
3.4 FImpl impl = new FImpl(myCls.getClassLoader());
3.5 loader = FnUtils.newLoader(impl, dfnr, myCls.getClassLoader().getParent());
3.6 }
3.7 +
3.8 + final Fn.Presenter dP = dfnr;
3.9
3.10 - final Fn.Presenter currentP = dfnr;
3.11 class OnPageLoad implements Runnable {
3.12 - Class<?> newClazz;
3.13 @Override
3.14 public void run() {
3.15 try {
3.16 - if (newClazz == null) {
3.17 - Thread.currentThread().setContextClassLoader(loader);
3.18 - newClazz = Class.forName(myCls.getName(), true, loader);
3.19 - if (browserClass != null) {
3.20 - browserClass[0] = newClazz;
3.21 + final Fn.Presenter aP = Fn.activePresenter();
3.22 + final Fn.Presenter currentP = aP != null ? aP : dP;
3.23 +
3.24 + Thread.currentThread().setContextClassLoader(loader);
3.25 + final Class<?> newClazz = Class.forName(myCls.getName(), true, loader);
3.26 + if (browserClass != null) {
3.27 + browserClass[0] = newClazz;
3.28 + }
3.29 + Contexts.Builder cb = Contexts.newBuilder();
3.30 + if (!Contexts.fillInByProviders(newClazz, cb)) {
3.31 + LOG.log(Level.WARNING, "Using empty technology for {0}", newClazz);
3.32 + }
3.33 + if (currentP instanceof Executor) {
3.34 + cb.register(Executor.class, (Executor)currentP, 1000);
3.35 + }
3.36 + cb.register(Fn.Presenter.class, currentP, 1000);
3.37 + BrwsrCtx c = cb.build();
3.38 +
3.39 + class CallInitMethod implements Runnable {
3.40 + @Override
3.41 + public void run() {
3.42 + Throwable firstError = null;
3.43 + if (onLoad != null) {
3.44 + try {
3.45 + FnContext.currentPresenter(currentP);
3.46 + onLoad.run();
3.47 + } catch (Throwable ex) {
3.48 + firstError = ex;
3.49 + } finally {
3.50 + FnContext.currentPresenter(null);
3.51 + }
3.52 + }
3.53 + INIT: if (methodName != null) {
3.54 + if (methodArgs.length == 0) {
3.55 + try {
3.56 + Method m = newClazz.getMethod(methodName);
3.57 + FnContext.currentPresenter(currentP);
3.58 + m.invoke(null);
3.59 + firstError = null;
3.60 + break INIT;
3.61 + } catch (Throwable ex) {
3.62 + firstError = ex;
3.63 + } finally {
3.64 + FnContext.currentPresenter(null);
3.65 + }
3.66 + }
3.67 + try {
3.68 + Method m = newClazz.getMethod(methodName, String[].class);
3.69 + FnContext.currentPresenter(currentP);
3.70 + m.invoke(m, (Object) methodArgs);
3.71 + firstError = null;
3.72 + } catch (Throwable ex) {
3.73 + LOG.log(Level.SEVERE, "Can't call " + methodName + " with args " + Arrays.toString(methodArgs), ex);
3.74 + } finally {
3.75 + FnContext.currentPresenter(null);
3.76 + }
3.77 + }
3.78 + if (firstError != null) {
3.79 + LOG.log(Level.SEVERE, "Can't initialize the view", firstError);
3.80 + }
3.81 }
3.82 - Contexts.Builder cb = Contexts.newBuilder();
3.83 - if (!Contexts.fillInByProviders(newClazz, cb)) {
3.84 - LOG.log(Level.WARNING, "Using empty technology for {0}", newClazz);
3.85 - }
3.86 - if (currentP instanceof Executor) {
3.87 - cb.register(Executor.class, (Executor)currentP, 1000);
3.88 - }
3.89 - cb.register(Fn.Presenter.class, currentP, 1000);
3.90 - BrwsrCtx c = cb.build();
3.91 - c.execute(this);
3.92 - return;
3.93 }
3.94
3.95 - Throwable firstError = null;
3.96 - if (onLoad != null) {
3.97 - try {
3.98 - FnContext.currentPresenter(currentP);
3.99 - onLoad.run();
3.100 - } catch (Throwable ex) {
3.101 - firstError = ex;
3.102 - } finally {
3.103 - FnContext.currentPresenter(null);
3.104 - }
3.105 - }
3.106 - INIT: if (methodName != null) {
3.107 - if (methodArgs.length == 0) {
3.108 - try {
3.109 - Method m = newClazz.getMethod(methodName);
3.110 - FnContext.currentPresenter(currentP);
3.111 - m.invoke(null);
3.112 - firstError = null;
3.113 - break INIT;
3.114 - } catch (Throwable ex) {
3.115 - firstError = ex;
3.116 - } finally {
3.117 - FnContext.currentPresenter(null);
3.118 - }
3.119 - }
3.120 - try {
3.121 - Method m = newClazz.getMethod(methodName, String[].class);
3.122 - FnContext.currentPresenter(currentP);
3.123 - m.invoke(m, (Object) methodArgs);
3.124 - firstError = null;
3.125 - } catch (Throwable ex) {
3.126 - LOG.log(Level.SEVERE, "Can't call " + methodName + " with args " + Arrays.toString(methodArgs), ex);
3.127 - } finally {
3.128 - FnContext.currentPresenter(null);
3.129 - }
3.130 - }
3.131 - if (firstError != null) {
3.132 - LOG.log(Level.SEVERE, "Can't initialize the view", firstError);
3.133 - }
3.134 + c.execute(new CallInitMethod());
3.135 } catch (ClassNotFoundException ex) {
3.136 LOG.log(Level.SEVERE, "Can't load " + myCls.getName(), ex);
3.137 }
3.138 }
3.139 }
3.140 dfnr.displayPage(url, new OnPageLoad());
3.141 - return;
3.142 }
3.143
3.144 private static final class FImpl implements FindResources {