Bringing up-to-date and adding a TCK test to check behavior of asynchronous callback async
authorJaroslav Tulach <jaroslav.tulach@netbeans.org>
Wed, 05 Mar 2014 00:11:49 +0100
branchasync
changeset 577f23fdccd1827
parent 576 fef447226358
parent 570 0e831501e072
child 578 ec78a6d57560
Bringing up-to-date and adding a TCK test to check behavior of asynchronous callback
boot/src/main/java/org/apidesign/html/boot/spi/Fn.java
json-tck/src/main/java/net/java/html/js/tests/Bodies.java
json-tck/src/main/java/net/java/html/js/tests/JavaScriptBodyTest.java
ko4j/src/main/java/org/netbeans/html/ko4j/Knockout.java
     1.1 --- a/boot/src/main/java/net/java/html/js/JavaScriptBody.java	Tue Mar 04 21:57:50 2014 +0100
     1.2 +++ b/boot/src/main/java/net/java/html/js/JavaScriptBody.java	Wed Mar 05 00:11:49 2014 +0100
     1.3 @@ -93,4 +93,6 @@
     1.4       *   syntax
     1.5       */
     1.6      public boolean javacall() default false;
     1.7 +    
     1.8 +    public boolean wait4js() default true;
     1.9  }
     2.1 --- a/boot/src/main/java/org/apidesign/html/boot/spi/Fn.java	Tue Mar 04 21:57:50 2014 +0100
     2.2 +++ b/boot/src/main/java/org/apidesign/html/boot/spi/Fn.java	Wed Mar 05 00:11:49 2014 +0100
     2.3 @@ -52,6 +52,8 @@
     2.4  import java.util.Map;
     2.5  import java.util.Set;
     2.6  import java.util.concurrent.Executor;
     2.7 +import java.util.logging.Level;
     2.8 +import java.util.logging.Logger;
     2.9  import net.java.html.js.JavaScriptBody;
    2.10  import org.netbeans.html.boot.impl.FnContext;
    2.11  
    2.12 @@ -140,6 +142,17 @@
    2.13          return new Fn(fn.presenter()) {
    2.14              @Override
    2.15              public Object invoke(Object thiz, Object... args) throws Exception {
    2.16 +                loadResource();
    2.17 +                return fn.invoke(thiz, args);
    2.18 +            }
    2.19 +
    2.20 +            @Override
    2.21 +            public void invokeLater(Object thiz, Object... args) throws Exception {
    2.22 +                loadResource();
    2.23 +                fn.invokeLater(thiz, args);
    2.24 +            }
    2.25 +            
    2.26 +            private void loadResource() throws Exception {
    2.27                  Presenter p = presenter();
    2.28                  if (p == null) {
    2.29                      p = FnContext.currentPresenter(false);
    2.30 @@ -160,10 +173,10 @@
    2.31                          }
    2.32                      }
    2.33                  }
    2.34 -                return fn.invoke(thiz, args);
    2.35              }
    2.36          };
    2.37      }
    2.38 +
    2.39      
    2.40      /** The currently active presenter.
    2.41       * 
    2.42 @@ -190,6 +203,10 @@
    2.43          return FnContext.activate(p);
    2.44      }
    2.45      
    2.46 +    public void invokeLater(Object thiz, Object... args) throws Exception {
    2.47 +        invoke(this, args);
    2.48 +    }
    2.49 +    
    2.50      /** Invokes the defined function with specified <code>this</code> and
    2.51       * appropriate arguments.
    2.52       * 
     3.1 --- a/boot/src/main/java/org/netbeans/html/boot/impl/FnUtils.java	Tue Mar 04 21:57:50 2014 +0100
     3.2 +++ b/boot/src/main/java/org/netbeans/html/boot/impl/FnUtils.java	Wed Mar 05 00:11:49 2014 +0100
     3.3 @@ -467,31 +467,38 @@
     3.4                      FindInMethod.super.visitInsn(Opcodes.AASTORE);
     3.5                  }
     3.6  
     3.7 -                super.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
     3.8 -                        "org/apidesign/html/boot/spi/Fn", "invoke", "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;"
     3.9 -                );
    3.10 -                switch (sv.returnType.getSort()) {
    3.11 -                    case Type.VOID:
    3.12 -                        super.visitInsn(Opcodes.RETURN);
    3.13 -                        break;
    3.14 -                    case Type.ARRAY:
    3.15 -                    case Type.OBJECT:
    3.16 -                        super.visitTypeInsn(Opcodes.CHECKCAST, sv.returnType.getInternalName());
    3.17 -                        super.visitInsn(Opcodes.ARETURN);
    3.18 -                        break;
    3.19 -                    case Type.BOOLEAN:
    3.20 -                        super.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/Boolean");
    3.21 -                        super.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
    3.22 -                                "java/lang/Boolean", "booleanValue", "()Z"
    3.23 -                        );
    3.24 -                        super.visitInsn(Opcodes.IRETURN);
    3.25 -                        break;
    3.26 -                    default:
    3.27 -                        super.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/Number");
    3.28 -                        super.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
    3.29 -                                "java/lang/Number", sv.returnType.getClassName() + "Value", "()" + sv.returnType.getDescriptor()
    3.30 -                        );
    3.31 -                        super.visitInsn(sv.returnType.getOpcode(Opcodes.IRETURN));
    3.32 +                if (fia.wait4js) {
    3.33 +                    super.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
    3.34 +                            "org/apidesign/html/boot/spi/Fn", "invoke", "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;"
    3.35 +                    );
    3.36 +                    switch (sv.returnType.getSort()) {
    3.37 +                        case Type.VOID:
    3.38 +                            super.visitInsn(Opcodes.RETURN);
    3.39 +                            break;
    3.40 +                        case Type.ARRAY:
    3.41 +                        case Type.OBJECT:
    3.42 +                            super.visitTypeInsn(Opcodes.CHECKCAST, sv.returnType.getInternalName());
    3.43 +                            super.visitInsn(Opcodes.ARETURN);
    3.44 +                            break;
    3.45 +                        case Type.BOOLEAN:
    3.46 +                            super.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/Boolean");
    3.47 +                            super.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
    3.48 +                                    "java/lang/Boolean", "booleanValue", "()Z"
    3.49 +                            );
    3.50 +                            super.visitInsn(Opcodes.IRETURN);
    3.51 +                            break;
    3.52 +                        default:
    3.53 +                            super.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/Number");
    3.54 +                            super.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
    3.55 +                                    "java/lang/Number", sv.returnType.getClassName() + "Value", "()" + sv.returnType.getDescriptor()
    3.56 +                            );
    3.57 +                            super.visitInsn(sv.returnType.getOpcode(Opcodes.IRETURN));
    3.58 +                    }
    3.59 +                } else {
    3.60 +                    super.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
    3.61 +                            "org/apidesign/html/boot/spi/Fn", "invokeLater", "(Ljava/lang/Object;[Ljava/lang/Object;)V"
    3.62 +                    );
    3.63 +                    super.visitInsn(Opcodes.RETURN);
    3.64                  }
    3.65                  if (hasCode) {
    3.66                      super.visitLabel(noPresenter);
    3.67 @@ -522,6 +529,7 @@
    3.68                  List<String> args = new ArrayList<String>();
    3.69                  String body;
    3.70                  boolean javacall = false;
    3.71 +                boolean wait4js = true;
    3.72  
    3.73                  public FindInAnno() {
    3.74                      super(Opcodes.ASM4);
    3.75 @@ -537,6 +545,10 @@
    3.76                          javacall = (Boolean) value;
    3.77                          return;
    3.78                      }
    3.79 +                    if (name.equals("wait4js")) { // NOI18N
    3.80 +                        wait4js = (Boolean) value;
    3.81 +                        return;
    3.82 +                    }
    3.83                      assert name.equals("body");
    3.84                      body = (String) value;
    3.85                  }
     4.1 --- a/boot/src/main/java/org/netbeans/html/boot/impl/JavaScriptProcesor.java	Tue Mar 04 21:57:50 2014 +0100
     4.2 +++ b/boot/src/main/java/org/netbeans/html/boot/impl/JavaScriptProcesor.java	Wed Mar 05 00:11:49 2014 +0100
     4.3 @@ -129,6 +129,9 @@
     4.4              if (params.size() != arr.length) {
     4.5                  msg.printMessage(Diagnostic.Kind.ERROR, "Number of args arguments does not match real arguments!", e);
     4.6              }
     4.7 +            if (!jsb.wait4js() && ee.getReturnType().getKind() != TypeKind.VOID) {
     4.8 +                msg.printMessage(Diagnostic.Kind.ERROR, "Methods that don't wait for JavaScript to finish must return void!", e);
     4.9 +            }
    4.10              if (!jsb.javacall() && jsb.body().contains(".@")) {
    4.11                  msg.printMessage(Diagnostic.Kind.WARNING, "Usage of .@ usually requires javacall=true", e);
    4.12              }
     5.1 --- a/json-tck/src/main/java/net/java/html/js/tests/Bodies.java	Tue Mar 04 21:57:50 2014 +0100
     5.2 +++ b/json-tck/src/main/java/net/java/html/js/tests/Bodies.java	Wed Mar 05 00:11:49 2014 +0100
     5.3 @@ -56,6 +56,9 @@
     5.4      @JavaScriptBody(args = {"r"}, javacall = true, body = "r.@java.lang.Runnable::run()();")
     5.5      static native void callback(Runnable r);
     5.6  
     5.7 +    @JavaScriptBody(args = {"r"}, wait4js = false, javacall = true, body = "r.@java.lang.Runnable::run()();")
     5.8 +    static native void asyncCallback(Runnable r);
     5.9 +
    5.10      @JavaScriptBody(args = {"c"}, javacall = true, body = "return c.@java.util.concurrent.Callable::call()();")
    5.11      static native Object callback(Callable<? extends Object> c);
    5.12  
     6.1 --- a/json-tck/src/main/java/net/java/html/js/tests/JavaScriptBodyTest.java	Tue Mar 04 21:57:50 2014 +0100
     6.2 +++ b/json-tck/src/main/java/net/java/html/js/tests/JavaScriptBodyTest.java	Wed Mar 05 00:11:49 2014 +0100
     6.3 @@ -77,6 +77,18 @@
     6.4          assert run.cnt == 1 : "Can call even private implementation classes: " + run.cnt;
     6.5      }
     6.6      
     6.7 +    private R asyncRun;
     6.8 +    @KOTest public void asyncCallbackToRunnable() throws InterruptedException {
     6.9 +        if (asyncRun == null) {
    6.10 +            asyncRun = new R();
    6.11 +            Bodies.asyncCallback(asyncRun);
    6.12 +        }
    6.13 +        if (asyncRun.cnt == 0) {
    6.14 +            throw new InterruptedException();
    6.15 +        }
    6.16 +        assert asyncRun.cnt == 1 : "Even async callback must arrive once: " + asyncRun.cnt;
    6.17 +    }
    6.18 +    
    6.19      @KOTest public void typeOfCharacter() {
    6.20          String charType = Bodies.typeof('a', false);
    6.21          assert "number".equals(charType) : "Expecting number type: " + charType;
     7.1 --- a/ko4j/src/main/java/org/netbeans/html/ko4j/Knockout.java	Tue Mar 04 21:57:50 2014 +0100
     7.2 +++ b/ko4j/src/main/java/org/netbeans/html/ko4j/Knockout.java	Wed Mar 05 00:11:49 2014 +0100
     7.3 @@ -59,7 +59,9 @@
     7.4   */
     7.5  @JavaScriptResource("knockout-2.2.1.js")
     7.6  final class Knockout {
     7.7 -    @JavaScriptBody(args = { "model", "prop", "oldValue", "newValue" }, body =
     7.8 +    @JavaScriptBody(args = { "model", "prop", "oldValue", "newValue" }, 
     7.9 +        wait4js = false,
    7.10 +        body =
    7.11            "if (model) {\n"
    7.12          + "  var koProp = model[prop];\n"
    7.13          + "  if (koProp && koProp['valueHasMutated']) {\n"
    7.14 @@ -75,7 +77,9 @@
    7.15          Object model, String prop, Object oldValue, Object newValue
    7.16      );
    7.17  
    7.18 -    @JavaScriptBody(args = { "bindings" }, body = "ko.applyBindings(bindings);\n")
    7.19 +    @JavaScriptBody(args = { "bindings" }, wait4js = false, body = 
    7.20 +        "ko.applyBindings(bindings);\n"
    7.21 +    )
    7.22      native static void applyBindings(Object bindings);
    7.23      
    7.24      @JavaScriptBody(args = { "cnt" }, body = 
    7.25 @@ -87,8 +91,9 @@
    7.26      
    7.27      @JavaScriptBody(
    7.28          javacall = true,
    7.29 +        wait4js = false,
    7.30          args = {"ret", "model", "propNames", "propReadOnly", "propValues", "propArr", "funcNames", "funcArr"},
    7.31 -        body =
    7.32 +        body = 
    7.33            "ret['ko-fx.model'] = model;\n"
    7.34          + "function koComputed(name, readOnly, value, prop) {\n"
    7.35          + "  function realGetter() {\n"
    7.36 @@ -140,5 +145,8 @@
    7.37      );
    7.38      
    7.39      @JavaScriptBody(args = { "o" }, body = "return o['ko-fx.model'] ? o['ko-fx.model'] : o;")
    7.40 -    static native Object toModel(Object wrapper);
    7.41 +    private static native Object toModelImpl(Object wrapper);
    7.42 +    static Object toModel(Object wrapper) {
    7.43 +        return toModelImpl(wrapper);
    7.44 +    }
    7.45  }