Reload of the HTML page from its popup menu works
authorJaroslav Tulach <jtulach@netbeans.org>
Thu, 17 Jul 2014 18:01:03 +0200
changeset 7368e6e4f811215
parent 735 d2f555dba114
child 737 8478a57cc613
Reload of the HTML page from its popup menu works
boot-fx/src/main/java/org/netbeans/html/boot/fx/AbstractFXPresenter.java
boot-fx/src/test/java/org/netbeans/html/boot/fx/ReloadTest.java
boot/src/main/java/net/java/html/boot/BrowserBuilder.java
     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 {