# HG changeset patch # User Jaroslav Tulach # Date 1391502747 -3600 # Node ID 3d696782eab923d673e40055600dcd3b1d00011f # Parent b5d60677fec75ed332789458770a68683ecc9205 Sample usage of @JavaScriptBody annotation. Preprocessing classes and adding a Js/Java interoperability test diff -r b5d60677fec7 -r 3d696782eab9 ko/archetype/src/main/resources/archetype-resources/pom.xml --- a/ko/archetype/src/main/resources/archetype-resources/pom.xml Thu Jan 23 20:03:25 2014 +0100 +++ b/ko/archetype/src/main/resources/archetype-resources/pom.xml Tue Feb 04 09:32:27 2014 +0100 @@ -43,6 +43,7 @@ ${project.version} MINIMAL pages/index.html + none @@ -64,6 +65,19 @@ + org.netbeans.html + html4j-maven-plugin + ${net.java.html.version} + + + js-classes + + process-js-annotations + + + + + org.apache.maven.plugins maven-compiler-plugin 2.3.2 @@ -110,7 +124,7 @@ org.testng testng - 6.5.2 + 6.7 test @@ -131,6 +145,12 @@ \${net.java.html.version} jar + + org.netbeans.html + net.java.html.boot + \${net.java.html.version} + jar + @@ -211,6 +231,9 @@ netbeans.ignore.jdk.bootclasspath + + **/JsInteractionTest* + diff -r b5d60677fec7 -r 3d696782eab9 ko/archetype/src/main/resources/archetype-resources/src/main/java/DataModel.java --- a/ko/archetype/src/main/resources/archetype-resources/src/main/java/DataModel.java Thu Jan 23 20:03:25 2014 +0100 +++ b/ko/archetype/src/main/resources/archetype-resources/src/main/java/DataModel.java Tue Feb 04 09:32:27 2014 +0100 @@ -25,7 +25,21 @@ @Function static void turnOn(Data model) { model.setOn(true); } - @Function static void turnOff(Data model) { - model.setOn(false); + + @Function static void turnOff(final Data model) { + confirmByUser("Really turn off?", new Runnable() { + @Override + public void run() { + model.setOn(false); + } + }); } + + /** Shows direct interaction with JavaScript */ + @net.java.html.js.JavaScriptBody( + args = { "msg", "callback" }, + javacall = true, + body = "alert(msg); callback.@java.lang.Runnable::run()();" + ) + static native void confirmByUser(String msg, Runnable callback); } diff -r b5d60677fec7 -r 3d696782eab9 ko/archetype/src/main/resources/archetype-resources/src/test/java/JsInteractionTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ko/archetype/src/main/resources/archetype-resources/src/test/java/JsInteractionTest.java Tue Feb 04 09:32:27 2014 +0100 @@ -0,0 +1,103 @@ +package ${package}; + +import java.io.Closeable; +import java.io.Reader; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; +import javax.script.Invocable; +import javax.script.ScriptEngine; +import javax.script.ScriptEngineManager; +import javax.script.ScriptException; +import org.apidesign.html.boot.spi.Fn; +import static org.testng.Assert.assertEquals; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +/** Tests for behavior of @JavaScriptBody methods. Set your JavaScript + * environment up (for example define alert or use some + * emulation library like env.js), register script presenter + * and then you can call methods that deal with JavaScript in your tests. + */ +public class JsInteractionTest { + private Closeable jsEngine; + @BeforeMethod public void initializeJSEngine() throws Exception { + jsEngine = Fn.activate(new ScriptPresenter()); + } + + @AfterMethod public void shutdownJSEngine() throws Exception { + jsEngine.close(); + } + + @Test public void testCallbackFromJavaScript() throws Exception { + class R implements Runnable { + int called; + + @Override + public void run() { + called++; + } + } + R callback = new R(); + + DataModel.confirmByUser("Hello", callback); + + assertEquals(callback.called, 1, "One immediate callback"); + } + + private static class ScriptPresenter implements Fn.Presenter { + private final ScriptEngine eng; + + public ScriptPresenter() throws ScriptException { + eng = new ScriptEngineManager().getEngineByName("javascript"); + eng.eval("function alert(msg) { Packages.java.lang.System.out.println(msg); };"); + } + + @Override + public Fn defineFn(String code, String... names) { + StringBuilder sb = new StringBuilder(); + sb.append("(function() {"); + sb.append(" return function("); + String sep = ""; + for (String n : names) { + sb.append(sep).append(n); + sep = ","; + } + sb.append(") {\n"); + sb.append(code); + sb.append("};"); + sb.append("})()"); + + final Object fn; + try { + fn = eng.eval(sb.toString()); + } catch (ScriptException ex) { + throw new IllegalStateException(ex); + } + return new Fn(this) { + @Override + public Object invoke(Object thiz, Object... args) throws Exception { + List all = new ArrayList(args.length + 1); + all.add(thiz == null ? fn : thiz); + for (int i = 0; i < args.length; i++) { + all.add(args[i]); + } + Object ret = ((Invocable)eng).invokeMethod(fn, "call", all.toArray()); // NOI18N + return fn.equals(ret) ? null : thiz; + } + }; + } + + @Override + public void displayPage(URL page, Runnable onPageLoad) { + // not really displaying anything + onPageLoad.run(); + } + + @Override + public void loadScript(Reader code) throws Exception { + eng.eval(code); + } + } +}