Sample usage of @JavaScriptBody annotation. Preprocessing classes and adding a Js/Java interoperability test
authorJaroslav Tulach <jaroslav.tulach@netbeans.org>
Tue, 04 Feb 2014 09:46:12 +0100
changeset 5210bac6ee0a6af
parent 520 bd9a54a9b958
child 522 e5dc7cf92ce4
Sample usage of @JavaScriptBody annotation. Preprocessing classes and adding a Js/Java interoperability test
ko-archetype/src/main/resources/archetype-resources/pom.xml
ko-archetype/src/main/resources/archetype-resources/src/main/java/DataModel.java
ko-archetype/src/main/resources/archetype-resources/src/test/java/JsInteractionTest.java
     1.1 --- a/ko-archetype/src/main/resources/archetype-resources/pom.xml	Mon Feb 03 15:12:45 2014 +0100
     1.2 +++ b/ko-archetype/src/main/resources/archetype-resources/pom.xml	Tue Feb 04 09:46:12 2014 +0100
     1.3 @@ -39,10 +39,24 @@
     1.4    <properties>
     1.5      <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
     1.6      <net.java.html.version>${project.version}</net.java.html.version>
     1.7 +    <netbeans.compile.on.save>none</netbeans.compile.on.save>
     1.8    </properties>
     1.9    <build>
    1.10        <plugins>
    1.11            <plugin>
    1.12 +              <groupId>org.netbeans.html</groupId>
    1.13 +              <artifactId>html4j-maven-plugin</artifactId>
    1.14 +              <version>${net.java.html.version}</version>
    1.15 +              <executions>
    1.16 +                  <execution>
    1.17 +                      <id>js-classes</id>
    1.18 +                      <goals>
    1.19 +                          <goal>process-js-annotations</goal>
    1.20 +                      </goals>
    1.21 +                  </execution>
    1.22 +              </executions>
    1.23 +          </plugin>          
    1.24 +          <plugin>
    1.25                <groupId>org.apache.maven.plugins</groupId>
    1.26                <artifactId>maven-compiler-plugin</artifactId>
    1.27                <version>2.3.2</version>
     2.1 --- a/ko-archetype/src/main/resources/archetype-resources/src/main/java/DataModel.java	Mon Feb 03 15:12:45 2014 +0100
     2.2 +++ b/ko-archetype/src/main/resources/archetype-resources/src/main/java/DataModel.java	Tue Feb 04 09:46:12 2014 +0100
     2.3 @@ -25,7 +25,21 @@
     2.4      @Function static void turnOn(Data model) {
     2.5          model.setOn(true);
     2.6      }
     2.7 -    @Function static void turnOff(Data model) {
     2.8 -        model.setOn(false);
     2.9 +    
    2.10 +    @Function static void turnOff(final Data model) {
    2.11 +        confirmByUser("Really turn off?", new Runnable() {
    2.12 +            @Override
    2.13 +            public void run() {
    2.14 +                model.setOn(false);
    2.15 +            }
    2.16 +        });
    2.17      }
    2.18 +    
    2.19 +    /** Shows direct interaction with JavaScript */
    2.20 +    @net.java.html.js.JavaScriptBody(
    2.21 +        args = { "msg", "callback" }, 
    2.22 +        javacall = true, 
    2.23 +        body = "alert(msg); callback.@java.lang.Runnable::run()();"
    2.24 +    )
    2.25 +    static native void confirmByUser(String msg, Runnable callback);
    2.26  }
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/ko-archetype/src/main/resources/archetype-resources/src/test/java/JsInteractionTest.java	Tue Feb 04 09:46:12 2014 +0100
     3.3 @@ -0,0 +1,103 @@
     3.4 +package ${package};
     3.5 +
     3.6 +import java.io.Closeable;
     3.7 +import java.io.Reader;
     3.8 +import java.net.URL;
     3.9 +import java.util.ArrayList;
    3.10 +import java.util.List;
    3.11 +import javax.script.Invocable;
    3.12 +import javax.script.ScriptEngine;
    3.13 +import javax.script.ScriptEngineManager;
    3.14 +import javax.script.ScriptException;
    3.15 +import org.apidesign.html.boot.spi.Fn;
    3.16 +import static org.testng.Assert.assertEquals;
    3.17 +import org.testng.annotations.AfterMethod;
    3.18 +import org.testng.annotations.BeforeMethod;
    3.19 +import org.testng.annotations.Test;
    3.20 +
    3.21 +/** Tests for behavior of @JavaScriptBody methods. Set your JavaScript 
    3.22 + * environment up (for example define <code>alert</code> or use some
    3.23 + * emulation library like <em>env.js</em>), register script presenter 
    3.24 + * and then you can call methods that deal with JavaScript in your tests.
    3.25 + */
    3.26 +public class JsInteractionTest {
    3.27 +    private Closeable jsEngine;
    3.28 +    @BeforeMethod public void initializeJSEngine() throws Exception {
    3.29 +        jsEngine = Fn.activate(new ScriptPresenter());
    3.30 +    }
    3.31 +    
    3.32 +    @AfterMethod public void shutdownJSEngine() throws Exception {
    3.33 +        jsEngine.close();
    3.34 +    }
    3.35 +    
    3.36 +    @Test public void testCallbackFromJavaScript() throws Exception {
    3.37 +        class R implements Runnable {
    3.38 +            int called;
    3.39 +
    3.40 +            @Override
    3.41 +            public void run() {
    3.42 +                called++;
    3.43 +            }
    3.44 +        }
    3.45 +        R callback = new R();
    3.46 +        
    3.47 +        DataModel.confirmByUser("Hello", callback);
    3.48 +        
    3.49 +        assertEquals(callback.called, 1, "One immediate callback");
    3.50 +    }
    3.51 +
    3.52 +    private static class ScriptPresenter implements Fn.Presenter {
    3.53 +        private final ScriptEngine eng;
    3.54 +        
    3.55 +        public ScriptPresenter() throws ScriptException {
    3.56 +            eng = new ScriptEngineManager().getEngineByName("javascript");
    3.57 +            eng.eval("function alert(msg) { Packages.java.lang.System.out.println(msg); };");
    3.58 +        }
    3.59 +
    3.60 +        @Override
    3.61 +        public Fn defineFn(String code, String... names) {
    3.62 +            StringBuilder sb = new StringBuilder();
    3.63 +            sb.append("(function() {");
    3.64 +            sb.append("  return function(");
    3.65 +            String sep = "";
    3.66 +            for (String n : names) {
    3.67 +                sb.append(sep).append(n);
    3.68 +                sep = ",";
    3.69 +            }
    3.70 +            sb.append(") {\n");
    3.71 +            sb.append(code);
    3.72 +            sb.append("};");
    3.73 +            sb.append("})()");
    3.74 +            
    3.75 +            final Object fn;
    3.76 +            try {
    3.77 +                fn = eng.eval(sb.toString());
    3.78 +            } catch (ScriptException ex) {
    3.79 +                throw new IllegalStateException(ex);
    3.80 +            }
    3.81 +            return new Fn(this) {
    3.82 +                @Override
    3.83 +                public Object invoke(Object thiz, Object... args) throws Exception {
    3.84 +                    List<Object> all = new ArrayList<Object>(args.length + 1);
    3.85 +                    all.add(thiz == null ? fn : thiz);
    3.86 +                    for (int i = 0; i < args.length; i++) {
    3.87 +                        all.add(args[i]);
    3.88 +                    }
    3.89 +                    Object ret = ((Invocable)eng).invokeMethod(fn, "call", all.toArray()); // NOI18N
    3.90 +                    return fn.equals(ret) ? null : thiz;
    3.91 +                }
    3.92 +            };
    3.93 +        }
    3.94 +
    3.95 +        @Override
    3.96 +        public void displayPage(URL page, Runnable onPageLoad) {
    3.97 +            // not really displaying anything
    3.98 +            onPageLoad.run();
    3.99 +        }
   3.100 +
   3.101 +        @Override
   3.102 +        public void loadScript(Reader code) throws Exception {
   3.103 +            eng.eval(code);
   3.104 +        }
   3.105 +    }
   3.106 +}