This is an automated email from the ASF dual-hosted git repository.

jtulach pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-netbeans-html4j.git

commit 4171d02183e27c19cbdbf92a14dec78b8211df0d
Author: Jaroslav Tulach <[email protected]>
AuthorDate: Sun Feb 17 20:17:22 2019 +0100

    Scripts.newPresenter() is a builder to create presenter
---
 boot-script/pom.xml                                |   3 +-
 .../java/net/java/html/boot/script/Sanitizer.java  |  80 ++++++++++++
 .../net/java/html/boot/script/ScriptPresenter.java |  17 ++-
 .../java/net/java/html/boot/script/Scripts.java    | 133 ++++++++++++++++----
 .../html/boot/script/Jsr223JavaScriptTest.java     |  24 +++-
 .../java/html/boot/script/KnockoutEnvJSTest.java   |   6 +-
 .../net/java/html/boot/script/ScriptsTest.java     | 139 +++++++++++++++++++++
 pom.xml                                            |  10 +-
 src/main/javadoc/overview.html                     |   3 +
 9 files changed, 369 insertions(+), 46 deletions(-)

diff --git a/boot-script/pom.xml b/boot-script/pom.xml
index ab65024..5a16110 100644
--- a/boot-script/pom.xml
+++ b/boot-script/pom.xml
@@ -31,7 +31,7 @@
     <version>2.0-SNAPSHOT</version>
     <packaging>bundle</packaging>
     <properties>
-        <netbeans.compile.on.save>NONE</netbeans.compile.on.save>
+        <netbeans.compile.on.save>none</netbeans.compile.on.save>
         <publicPackages>net.java.html.boot.script</publicPackages>
     </properties>
     <build>
@@ -108,7 +108,6 @@
             <groupId>javax.servlet</groupId>
             <artifactId>javax.servlet-api</artifactId>
             <scope>test</scope>
-            <version>3.1.0</version>
         </dependency>
         <dependency>
             <groupId>org.netbeans.html</groupId>
diff --git a/boot-script/src/main/java/net/java/html/boot/script/Sanitizer.java 
b/boot-script/src/main/java/net/java/html/boot/script/Sanitizer.java
new file mode 100644
index 0000000..2d3c57a
--- /dev/null
+++ b/boot-script/src/main/java/net/java/html/boot/script/Sanitizer.java
@@ -0,0 +1,80 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package net.java.html.boot.script;
+
+import javax.script.Invocable;
+import javax.script.ScriptEngine;
+import javax.script.ScriptException;
+
+final class Sanitizer {
+    private Sanitizer() {
+    }
+
+    private static final String[] ALLOWED_GLOBALS = (""
+    + "Object,Function,Array,String,Date,Number,BigInt,"
+    + "Boolean,RegExp,Math,JSON,NaN,Infinity,undefined,"
+    + "isNaN,isFinite,parseFloat,parseInt,encodeURI,"
+    + "encodeURIComponent,decodeURI,decodeURIComponent,eval,"
+    + "escape,unescape,"
+    + "Error,EvalError,RangeError,ReferenceError,SyntaxError,"
+    + "TypeError,URIError,ArrayBuffer,Int8Array,Uint8Array,"
+    + "Uint8ClampedArray,Int16Array,Uint16Array,Int32Array,"
+    + "Uint32Array,Float32Array,Float64Array,BigInt64Array,"
+    + "BigUint64Array,DataView,Map,Set,WeakMap,"
+    + "WeakSet,Symbol,Reflect,Proxy,Promise,SharedArrayBuffer,"
+    + "Atomics,console,performance,"
+    + "arguments,load").split(",");
+
+
+    static void clean(ScriptEngine engine) throws ScriptException {
+        try {
+            Object cleaner = engine.eval(""
+                + "(function(allowed) {\n"
+                + "   var names = Object.getOwnPropertyNames(this);\n"
+                + "   MAIN: for (var i = 0; i < names.length; i++) {\n"
+                + "     for (var j = 0; j < allowed.length; j++) {\n"
+                + "       if (names[i] === allowed[j]) {\n"
+                + "         continue MAIN;\n"
+                + "       }\n"
+                + "     }\n"
+                + "     delete this[names[i]];\n"
+                + "   }\n"
+                + "})"
+            );
+            ((Invocable) engine).invokeMethod(cleaner, "call", null, 
ALLOWED_GLOBALS);
+        } catch (NoSuchMethodException ex) {
+            throw new ScriptException(ex);
+        }
+    }
+
+    static void defineAlert(ScriptEngine engine) throws ScriptException {
+        try {
+            Object defineAlert = engine.eval(""
+                + "(function(out) {\n"
+                + "  this.alert = function(msg) {\n"
+                + "    out.println(msg);\n"
+                + " };"
+                + "});"
+            );
+            ((Invocable) engine).invokeMethod(defineAlert, "call", null, 
System.out);
+        } catch (NoSuchMethodException ex) {
+            throw new ScriptException(ex);
+        }
+    }
+}
diff --git 
a/boot-script/src/main/java/net/java/html/boot/script/ScriptPresenter.java 
b/boot-script/src/main/java/net/java/html/boot/script/ScriptPresenter.java
index 289e625..dee6415 100644
--- a/boot-script/src/main/java/net/java/html/boot/script/ScriptPresenter.java
+++ b/boot-script/src/main/java/net/java/html/boot/script/ScriptPresenter.java
@@ -20,7 +20,6 @@ package net.java.html.boot.script;
 
 import java.io.Closeable;
 import java.io.IOException;
-import java.io.ObjectOutput;
 import java.io.Reader;
 import java.lang.ref.WeakReference;
 import java.lang.reflect.Array;
@@ -72,19 +71,19 @@ Presenter, Fn.FromJavaScript, Fn.ToJavaScript, Executor {
     private final Set<Class<?>> jsReady;
     private final CallbackImpl callback;
 
-    ScriptPresenter(Executor exc) {
-        this(new ScriptEngineManager().getEngineByName("javascript"), exc);
-    }
-
-    ScriptPresenter(ScriptEngine eng, Executor exc) {
+    ScriptPresenter(ScriptEngine eng, Executor exc, boolean sanitize) {
+        if (eng == null) {
+            eng = new ScriptEngineManager().getEngineByName("javascript");
+        }
         this.eng = eng;
         this.exc = exc;
         try {
-            eng.eval("function alert(msg) { 
Packages.java.lang.System.out.println(msg); };");
-            eng.eval("function confirm(msg) { 
Packages.java.lang.System.out.println(msg); return true; };");
-            eng.eval("function prompt(msg, txt) { 
Packages.java.lang.System.out.println(msg + ':' + txt); return txt; };");
             Object undef = new UndefinedCallback().undefined(eng);
             this.undefined = undef;
+            if (sanitize) {
+                Sanitizer.clean(eng);
+            }
+            Sanitizer.defineAlert(eng);
         } catch (ScriptException ex) {
             throw new IllegalStateException(ex);
         }
diff --git a/boot-script/src/main/java/net/java/html/boot/script/Scripts.java 
b/boot-script/src/main/java/net/java/html/boot/script/Scripts.java
index 4df7086..4e8633f 100644
--- a/boot-script/src/main/java/net/java/html/boot/script/Scripts.java
+++ b/boot-script/src/main/java/net/java/html/boot/script/Scripts.java
@@ -18,52 +18,47 @@
  */
 package net.java.html.boot.script;
 
-import java.io.Closeable;
 import java.util.concurrent.Executor;
 import javax.script.ScriptEngine;
-import net.java.html.boot.BrowserBuilder;
 import net.java.html.js.JavaScriptBody;
-import org.netbeans.html.boot.spi.Fn;
 import org.netbeans.html.boot.spi.Fn.Presenter;
 
-/** Implementations of {@link Presenter}s that delegate
+/** Builder to create a {@link Presenter} that delegates
  * to Java {@link ScriptEngine scripting} API. Initialize your presenter
  * like this:
- * 
- * <pre>
- * 
- * {@link Runnable} <em>run</em> = ...; // your own init code
- * {@link Presenter Fn.Presenter} <b>p</b> = Scripts.{@link 
Scripts#createPresenter()};
- * BrowserBuilder.{@link BrowserBuilder#newBrowser(java.lang.Object...) 
newBrowser(<b>p</b>)}.
- *      {@link BrowserBuilder#loadFinished(java.lang.Runnable) 
loadFinished(run)}.
- *      {@link BrowserBuilder#showAndWait()};
- * </pre>
+ * <p>
+ * {@codesnippet ScriptsTest#initViaBrowserBuilder}
  * 
  * and your runnable can make extensive use of {@link JavaScriptBody} directly 
or
  * indirectly via APIs using {@link JavaScriptBody such annotation} themselves.
  * <p>
  * Alternatively one can manipulate the presenter manually, which is
  * especially useful when writing tests:
- * <pre>
- * {@code @Test} public void runInASimulatedBrowser() throws Exception {
- *   {@link Presenter Fn.Presenter} <b>p</b> = Scripts.{@link 
Scripts#createPresenter()};
- *   try ({@link Closeable} c = {@link 
Fn#activate(org.netbeans.html.boot.spi.Fn.Presenter) Fn.activate}(<b>p</b>)) {
- *     // your code operating in context of <b>p</b>
- *   }
- * }
- * </pre>
- * The previous code snippet requires Java 7 language syntax, as it relies
- * on try-with-resources language syntactic sugar feature. The same block
+ * <p>
+ * {@codesnippet ScriptsTest#activatePresenterDirectly}
+ * <p>
+ * The previous code snippet relies
+ * on try-with-resources <em>Java7</em> syntax. The same block
  * of code can be used on older versions of Java, but it is slightly more
  * verbose.
  * 
  * @author Jaroslav Tulach
  */
 public final class Scripts {
+
+    private Executor exc;
+    private ScriptEngine engine;
+    private boolean sanitize = true;
+    
     private Scripts() {
     }
     
-    /** Simple implementation of {@link Presenter} that delegates
+    /** {@linkplain #sanitize(boolean) Non-sanitized} version of the presenter.
+     * Rather use following code to obtain safer version of the engine:
+     * <p> 
+     * {@codesnippet ScriptsTest#testNewPresenterNoExecutor}
+     * <p>
+     * Simple implementation of {@link Presenter} that delegates
      * to Java {@link ScriptEngine scripting} API. The presenter runs headless
      * without appropriate simulation of browser APIs. Its primary usefulness
      * is inside testing environments. The presenter implements {@link 
Executor}
@@ -72,12 +67,19 @@ public final class Scripts {
      * 
      * @return new instance of a presenter that is using its own
      *   {@link ScriptEngine} for <code>text/javascript</code> mimetype
+     * @deprecated use {@link #newPresenter()} builder
      */
+    @Deprecated
     public static Presenter createPresenter() {
-        return new ScriptPresenter(null);
+        return newPresenter().sanitize(false).build();
     }
 
-    /** Implementation of {@link Presenter} that delegates
+    /** {@linkplain #sanitize(boolean) Non-sanitized} version of the presenter.
+     * Rather use following code to obtain safer version of the engine:
+     * <p> 
+     * {@codesnippet Jsr223JavaScriptTest#createPresenter}
+     * <p>
+     * Implementation of {@link Presenter} that delegates
      * to Java {@link ScriptEngine scripting} API and can control execution
      * thread. The presenter runs headless
      * without appropriate simulation of browser APIs. Its primary usefulness
@@ -88,8 +90,85 @@ public final class Scripts {
      * @param exc the executor to re-schedule all asynchronous requests to
      * @return new instance of a presenter that is using its own
      *   {@link ScriptEngine} for <code>text/javascript</code> mimetype
+     * @deprecated use {@link #newPresenter()} builder
      */
+    @Deprecated
     public static Presenter createPresenter(Executor exc) {
-        return new ScriptPresenter(exc);
+        return newPresenter().sanitize(false).executor(exc).build();
+    }
+    
+    /** Creates new scripting {@link Presenter} builder. Simplest way
+     * to use is:
+     * <p>
+     * {@codesnippet ScriptsTest#testNewPresenterNoExecutor}
+     * <p>
+     * It is possible to specify own 
+     * {@link #engine(javax.script.ScriptEngine) scripting engine}
+     * and {@link #executor(java.util.concurrent.Executor)}
+     * and control the thread that executes the scripts:
+     * <p>
+     * {@codesnippet Jsr223JavaScriptTest#createPresenter}
+     * <p>
+     * By default the created presenters are {@linkplain #sanitize(boolean) 
sanitized}.
+     * 
+     * @return instance of the new builder
+     * @since 1.6.1
+     */
+    public static Scripts newPresenter() {
+        return new Scripts();
+    }
+    
+    /** Associates new executor.
+     * The {@linkplain #build() to be created presenter} will implement {@link 
Executor}
+     * interface, and passes all runnables from its own
+     * {@link Executor#execute(java.lang.Runnable)} method
+     * to here in provided {@code exc} instance of executor.
+     * 
+     * @param exc dedicated executor to use
+     * @return instance of the new builder
+     * @since 1.6.1
+     */
+    public Scripts executor(Executor exc) {
+        this.exc = exc;
+        return this;
+    }
+    
+    /** Associates a scripting engine.
+     * The engine is used to {@link #build() build} an 
+     * implementation of {@link Presenter} that delegates
+     * to Java {@link ScriptEngine scripting} API. The presenter runs headless
+     * without appropriate simulation of browser APIs. 
+     * 
+     * @param engine dedicated script engine to use
+     * @return instance of the new builder
+     * @since 1.6.1
+     */
+    public Scripts engine(ScriptEngine engine) {
+        this.engine = engine;
+        return this;
+    }
+    
+    /** Turn sandboxing of the engine on or off. When sanitization is on
+     * a special care is taken to remove all global symbols not present
+     * in the EcmaScript specification. By default the sanitization is on
+     * to increase security.
+     * 
+     * @param yesOrNo do the sanitization or not
+     * @return instance of the new builder
+     * @since 1.6.1
+     */
+    public Scripts sanitize(boolean yesOrNo) {
+        this.sanitize = yesOrNo;
+        return this;
+    }
+    
+    /** Builds new instance of the scripting presenter. Use
+     * arguments of this builder and creates new instance.
+     * 
+     * @return creates new instance of the presenter
+     * @since 1.6.1
+     */
+    public Presenter build() {
+        return new ScriptPresenter(engine, exc, sanitize);
     }
 }
diff --git 
a/boot-script/src/test/java/net/java/html/boot/script/Jsr223JavaScriptTest.java 
b/boot-script/src/test/java/net/java/html/boot/script/Jsr223JavaScriptTest.java
index d405490..bfa5f21 100644
--- 
a/boot-script/src/test/java/net/java/html/boot/script/Jsr223JavaScriptTest.java
+++ 
b/boot-script/src/test/java/net/java/html/boot/script/Jsr223JavaScriptTest.java
@@ -22,6 +22,7 @@ import java.lang.annotation.Annotation;
 import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.concurrent.Executor;
 import java.util.concurrent.Executors;
 import javax.script.ScriptEngine;
 import javax.script.ScriptEngineManager;
@@ -61,10 +62,11 @@ public class Jsr223JavaScriptTest {
             ""
         );
         assertEquals(left.toString().toLowerCase().indexOf("java"), -1, "No 
Java symbols " + left);
-        final BrowserBuilder bb = BrowserBuilder.newBrowser(new 
ScriptPresenter(engine, SingleCase.JS)).
-            loadClass(Jsr223JavaScriptTest.class).
+        
+        Fn.Presenter presenter = createPresenter(engine);
+        final BrowserBuilder bb = BrowserBuilder.newBrowser(presenter).
             loadPage("empty.html").
-            invoke("initialized");
+            loadFinished(Jsr223JavaScriptTest::initialized);
 
         Executors.newSingleThreadExecutor().submit(new Runnable() {
             @Override
@@ -73,7 +75,7 @@ public class Jsr223JavaScriptTest {
             }
         });
 
-        List<Object> res = new ArrayList<Object>();
+        List<Object> res = new ArrayList<>();
         Class<? extends Annotation> test = 
             loadClass().getClassLoader().loadClass(KOTest.class.getName()).
             asSubclass(Annotation.class);
@@ -89,6 +91,16 @@ public class Jsr223JavaScriptTest {
         return res.toArray();
     }
 
+    private static Fn.Presenter createPresenter(ScriptEngine engine) {
+        final Executor someExecutor = SingleCase.JS;
+        // BEGIN: Jsr223JavaScriptTest#createPresenter
+        return Scripts.newPresenter()
+            .engine(engine)
+            .executor(someExecutor)
+            .build();
+        // END: Jsr223JavaScriptTest#createPresenter
+    }
+
     static synchronized Class<?> loadClass() throws InterruptedException {
         while (browserClass == null) {
             Jsr223JavaScriptTest.class.wait();
@@ -96,13 +108,13 @@ public class Jsr223JavaScriptTest {
         return browserClass;
     }
     
-    public static synchronized void ready(Class<?> browserCls) throws 
Exception {
+    private static synchronized void ready(Class<?> browserCls) {
         browserClass = browserCls;
         browserPresenter = Fn.activePresenter();
         Jsr223JavaScriptTest.class.notifyAll();
     }
     
-    public static void initialized() throws Exception {
+    private static void initialized() {
         Assert.assertSame(
             Jsr223JavaScriptTest.class.getClassLoader(),
             ClassLoader.getSystemClassLoader(),
diff --git 
a/boot-script/src/test/java/net/java/html/boot/script/KnockoutEnvJSTest.java 
b/boot-script/src/test/java/net/java/html/boot/script/KnockoutEnvJSTest.java
index 4ad97bb..6316f10 100644
--- a/boot-script/src/test/java/net/java/html/boot/script/KnockoutEnvJSTest.java
+++ b/boot-script/src/test/java/net/java/html/boot/script/KnockoutEnvJSTest.java
@@ -84,7 +84,11 @@ public final class KnockoutEnvJSTest extends KnockoutTCK {
 
         baseUri = DynamicHTTP.initServer();
 
-        final Fn.Presenter p = new ScriptPresenter(eng, KOCase.JS);
+        final Fn.Presenter p = Scripts.newPresenter()
+            .engine(eng)
+            .sanitize(false)
+            .executor(KOCase.JS)
+            .build();
         try {
             Class.forName("java.lang.Module");
         } catch (ClassNotFoundException oldJDK) {
diff --git 
a/boot-script/src/test/java/net/java/html/boot/script/ScriptsTest.java 
b/boot-script/src/test/java/net/java/html/boot/script/ScriptsTest.java
new file mode 100644
index 0000000..d7c8947
--- /dev/null
+++ b/boot-script/src/test/java/net/java/html/boot/script/ScriptsTest.java
@@ -0,0 +1,139 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package net.java.html.boot.script;
+
+import java.io.Closeable;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executor;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import net.java.html.boot.BrowserBuilder;
+import net.java.html.js.JavaScriptBody;
+import org.netbeans.html.boot.spi.Fn;
+import static org.testng.Assert.*;
+import org.testng.annotations.Test;
+
+public class ScriptsTest {
+
+    public ScriptsTest() {
+    }
+
+    @Test
+    public void testNewPresenterNoExecutor() throws Exception {
+        // BEGIN: ScriptsTest#testNewPresenterNoExecutor
+        Fn.Presenter presenter = Scripts.newPresenter().build();
+        // END: ScriptsTest#testNewPresenterNoExecutor
+        assertNotNull(presenter);
+        Fn fn = presenter.defineFn("return a * b", "a", "b");
+        Object fourtyTwo = fn.invoke(null, 6, 7);
+        assertTrue(fourtyTwo instanceof Number);
+        assertEquals(((Number)fourtyTwo).intValue(), 42);
+    }
+
+    @Test
+    public void testActivatePresenterDirectly() throws Exception {
+        int fortyTwo = activatePresenterDirectly();
+        assertEquals(fortyTwo, 42);
+    }
+
+    // BEGIN: ScriptsTest#activatePresenterDirectly
+    @JavaScriptBody(args = { "a", "b" }, body = "return a * b;")
+    private static native int mul(int a, int b);
+
+    private static int activatePresenterDirectly() throws Exception {
+        Fn.Presenter p = Scripts.newPresenter().build();
+        try (Closeable c = Fn.activate(p)) {
+            int fortyTwo = mul(2, mul(7, 3));
+            assert fortyTwo == 42;
+            return fortyTwo;
+        }
+    }
+    // END: ScriptsTest#activatePresenterDirectly
+
+    @Test
+    public void initViaBrowserBuilder() throws Exception {
+        String[] executed = { null };
+        // BEGIN: ScriptsTest#initViaBrowserBuilder
+        Runnable run = () -> {
+            executed[0] = "OK";
+        };
+        Fn.Presenter p = Scripts.newPresenter().build();
+        BrowserBuilder.newBrowser(p)
+            .loadFinished(run)
+            .loadPage("empty.html")
+            .showAndWait();
+        // END: ScriptsTest#initViaBrowserBuilder
+        assertEquals(executed[0], "OK", "Executed without issues");
+    }
+
+    @Test
+    public void isSanitizationOnByDefault() throws Exception {
+        assertSanitized(Scripts.newPresenter());
+    }
+
+    @Test
+    public void isSanitizationOnExplicitly() throws Exception {
+        assertSanitized(Scripts.newPresenter().sanitize(true));
+    }
+
+    @Test
+    public void noSanitization() throws Exception {
+        assertNotSanitized(Scripts.newPresenter().sanitize(false));
+    }
+
+    private void assertSanitized(Scripts newPresenter) throws Exception {
+        Fn.Presenter p = newPresenter.build();
+        awaitPresenter(p);
+        try (Closeable c = Fn.activate(p)) {
+            Object Java = p.defineFn("return typeof Java;").invoke(null);
+            Object engine = p.defineFn("return typeof engine;").invoke(null);
+            Object Packages = p.defineFn("return typeof 
Packages;").invoke(null);
+            Object alert = p.defineFn("return typeof alert;").invoke(null);
+            assertEquals(Java, "undefined", "No Java symbol");
+            assertEquals(engine, "undefined", "No engine symbol");
+            assertEquals(Packages, "undefined", "No Packages symbol");
+            assertEquals(alert, "function", "alert is defined symbol");
+        }
+    }
+
+    private void assertNotSanitized(Scripts builder) throws Exception {
+        Fn.Presenter p = builder.build();
+        try (Closeable c = Fn.activate(p)) {
+            Object Java = p.defineFn("return typeof Java;").invoke(null);
+            Object engine = p.defineFn("return typeof engine;").invoke(null);
+            Object Packages = p.defineFn("return typeof 
Packages;").invoke(null);
+            Object alert = p.defineFn("return typeof alert;").invoke(null);
+            assertEquals(Java, "object", "Java symbol found");
+            assertEquals(engine, "object", "Engine symbol found");
+            assertEquals(Packages, "object", "Packages symbol found");
+            assertEquals(alert, "function", "alert is defined symbol");
+        }
+    }
+
+    private static void awaitPresenter(Fn.Presenter p) {
+        Executor e = (Executor) p;
+        CountDownLatch cdl = new CountDownLatch(1);
+        e.execute(cdl::countDown);
+        try {
+            cdl.await();
+        } catch (InterruptedException ex) {
+            throw new IllegalStateException(ex);
+        }
+    }
+}
diff --git a/pom.xml b/pom.xml
index bbe30d8..4954d94 100644
--- a/pom.xml
+++ b/pom.xml
@@ -148,7 +148,13 @@ 
org.netbeans.html.boot.impl:org.netbeans.html.boot.fx:org.netbeans.html.context.
                     <artifactId>codesnippet-doclet</artifactId>
                     <version>0.23</version>
                 </docletArtifact>
-                <additionalparam>-snippetpath json/src/test -snippetpath 
boot-fx/src/test ${javadoc.allowjs} -hiddingannotation 
java.lang.Deprecated</additionalparam>
+                <additionalparam>
+                    -snippetpath boot-fx/src/test 
+                    -snippetpath boot-script/src/test
+                    -snippetpath json/src/test
+                    ${javadoc.allowjs}
+                    -hiddingannotation java.lang.Deprecated
+                </additionalparam>
               </configuration>
             </plugin>
             <plugin>
@@ -268,6 +274,8 @@ 
org.netbeans.html.boot.impl:org.netbeans.html.boot.fx:org.netbeans.html.context.
                 <configuration>
                     <source>1.6</source>
                     <target>1.6</target>
+                    <testSource>1.8</testSource>
+                    <testTarget>1.8</testTarget>
                 </configuration>
               </plugin>
               <plugin>
diff --git a/src/main/javadoc/overview.html b/src/main/javadoc/overview.html
index 13f6c70..3e4a06c 100644
--- a/src/main/javadoc/overview.html
+++ b/src/main/javadoc/overview.html
@@ -167,6 +167,9 @@ $ mvn -f client/pom.xml process-classes exec:exec
         <p>
             One model instance can be used in two views
             (<a target="_blank" 
href="https://github.com/apache/incubator-netbeans-html4j/pull/14";>PR #14</a>).
+            Safe and {@link net.java.html.boot.script.Scripts sanitized 
builder} to
+            create {@link javax.script.ScriptEngine}-based execution 
environment
+            (<a target="_blank" 
href="https://github.com/apache/incubator-netbeans-html4j/pull/15";>PR #15</a>).
         </p>
 
         <h3>New in version 1.6</h3>


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

For further information about the NetBeans mailing lists, visit:
https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists

Reply via email to