1.1 --- a/json/src/main/java/org/apidesign/html/json/impl/Bindings.java Mon Apr 22 21:36:07 2013 +0200
1.2 +++ b/json/src/main/java/org/apidesign/html/json/impl/Bindings.java Mon Apr 22 22:30:30 2013 +0200
1.3 @@ -24,6 +24,7 @@
1.4 import java.util.List;
1.5 import org.apidesign.html.json.spi.PropertyBinding;
1.6 import net.java.html.json.Context;
1.7 +import org.apidesign.html.json.impl.PropertyBindingAccessor.FBData;
1.8 import org.apidesign.html.json.impl.PropertyBindingAccessor.PBData;
1.9 import org.apidesign.html.json.spi.FunctionBinding;
1.10 import org.apidesign.html.json.spi.Technology;
1.11 @@ -46,31 +47,22 @@
1.12 bp.bind(pb, model, data);
1.13 return pb;
1.14 }
1.15 +
1.16 + public <M> FunctionBinding registerFunction(String name, M model, Callback<M> access) {
1.17 + FunctionBinding fb = PropertyBindingAccessor.createFunction(new FBData<>(name, model, access));
1.18 + bp.expose(fb, model, data);
1.19 + return fb;
1.20 + }
1.21
1.22 - public static Bindings<?> apply(Context c, Object model, String[] functions) {
1.23 + public static Bindings<?> apply(Context c, Object model) {
1.24 Technology<?> bp = ContextAccessor.findTechnology(c);
1.25 - return apply(bp, model, null, functions);
1.26 + return apply(bp, model);
1.27 }
1.28
1.29 private static <Data> Bindings<Data> apply(
1.30 - Technology<Data> bp, Object model,
1.31 - PropertyBinding[] propBindings, String[] methodsAndSignatures
1.32 + Technology<Data> bp, Object model
1.33 ) {
1.34 Data d = bp.wrapModel(model);
1.35 -
1.36 - if (propBindings != null) {
1.37 - for (int i = 0; i < propBindings.length; i++) {
1.38 - PropertyBinding pb = propBindings[i];
1.39 - bp.bind(pb, model, d);
1.40 - }
1.41 - }
1.42 -
1.43 - List<String> arr = Arrays.asList(methodsAndSignatures);
1.44 - for (int i = 0; i < methodsAndSignatures.length; i += 2) {
1.45 - FunctionBinding fb = PropertyBindingAccessor.createFunction(arr.subList(i, i + 2));
1.46 - bp.expose(fb, model, d);
1.47 - }
1.48 -
1.49 return new Bindings<>(d, bp);
1.50 }
1.51
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2.2 +++ b/json/src/main/java/org/apidesign/html/json/impl/Callback.java Mon Apr 22 22:30:30 2013 +0200
2.3 @@ -0,0 +1,30 @@
2.4 +/**
2.5 + * HTML via Java(tm) Language Bindings
2.6 + * Copyright (C) 2013 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
2.7 + *
2.8 + * This program is free software: you can redistribute it and/or modify
2.9 + * it under the terms of the GNU General Public License as published by
2.10 + * the Free Software Foundation, version 2 of the License.
2.11 + *
2.12 + * This program is distributed in the hope that it will be useful,
2.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
2.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2.15 + * GNU General Public License for more details. apidesign.org
2.16 + * designates this particular file as subject to the
2.17 + * "Classpath" exception as provided by apidesign.org
2.18 + * in the License file that accompanied this code.
2.19 + *
2.20 + * You should have received a copy of the GNU General Public License
2.21 + * along with this program. Look for COPYING file in the top folder.
2.22 + * If not, see http://wiki.apidesign.org/wiki/GPLwithClassPathException
2.23 + */
2.24 +
2.25 +package org.apidesign.html.json.impl;
2.26 +
2.27 +/**
2.28 + *
2.29 + * @author Jaroslav Tulach <jtulach@netbeans.org>
2.30 + */
2.31 +public interface Callback<Data> {
2.32 + public void call(Data model, Object data, Object ev);
2.33 +}
3.1 --- a/json/src/main/java/org/apidesign/html/json/impl/ModelProcessor.java Mon Apr 22 21:36:07 2013 +0200
3.2 +++ b/json/src/main/java/org/apidesign/html/json/impl/ModelProcessor.java Mon Apr 22 22:30:30 2013 +0200
3.3 @@ -197,16 +197,19 @@
3.4 w.append(" };\n");
3.5 w.append(" private org.apidesign.html.json.impl.Bindings intKnckt() {\n");
3.6 w.append(" if (ko != null) return ko;\n");
3.7 - w.append(" ko = org.apidesign.html.json.impl.Bindings.apply(context, this, ");
3.8 - writeStringArray(functions, w);
3.9 - w.append(" );\n");
3.10 + w.append(" ko = org.apidesign.html.json.impl.Bindings.apply(context, this);\n");
3.11 for (int i = 0; i < propsGetSet.size(); i += 5) {
3.12 w.append(" ko.registerProperty(\"").append(propsGetSet.get(i)).append("\", this, new P(");
3.13 w.append((i / 5) + "), " + (propsGetSet.get(i + 2) == null) + ");\n");
3.14 }
3.15 + for (int i = 0; i < functions.size(); i += 2) {
3.16 + w.append(" ko.registerFunction(\"").append(functions.get(i)).append("\", this, new P(");
3.17 + w.append((i / 2) + "));\n");
3.18 + }
3.19 w.append(" return ko;\n");
3.20 w.append(" };\n");
3.21 - w.append(" private static final class P implements org.apidesign.html.json.impl.SetAndGet<" + className + "> {\n");
3.22 + w.append(" private static final class P implements org.apidesign.html.json.impl.SetAndGet<" + className + ">,\n");
3.23 + w.append(" org.apidesign.html.json.impl.Callback<" + className + "> {\n");
3.24 w.append(" private final int type;\n");
3.25 w.append(" P(int t) { type = t; };\n");
3.26 w.append(" public void setValue(" + className + " data, Object value) {\n");
3.27 @@ -231,6 +234,15 @@
3.28 w.append(" }\n");
3.29 w.append(" throw new UnsupportedOperationException();\n");
3.30 w.append(" }\n");
3.31 + w.append(" public void call(" + className + " model, Object data, Object ev) {\n");
3.32 + w.append(" switch (type) {\n");
3.33 + for (int i = 0; i < functions.size(); i += 2) {
3.34 + final String name = functions.get(i);
3.35 + w.append(" case " + (i / 2) + ": model." + name + "(data, ev); return;\n");
3.36 + }
3.37 + w.append(" }\n");
3.38 + w.append(" throw new UnsupportedOperationException();\n");
3.39 + w.append(" }\n");
3.40 w.append(" }\n");
3.41 w.append(" ").append(className).append("(Object json) {\n");
3.42 int values = 0;
4.1 --- a/json/src/main/java/org/apidesign/html/json/impl/PropertyBindingAccessor.java Mon Apr 22 21:36:07 2013 +0200
4.2 +++ b/json/src/main/java/org/apidesign/html/json/impl/PropertyBindingAccessor.java Mon Apr 22 22:30:30 2013 +0200
4.3 @@ -48,20 +48,20 @@
4.4 }
4.5
4.6 protected abstract <M> PropertyBinding newBinding(PBData<M> d);
4.7 - protected abstract FunctionBinding newFunction(List<String> params);
4.8 + protected abstract <M> FunctionBinding newFunction(FBData<M> d);
4.9
4.10 static <M> PropertyBinding create(PBData<M> d) {
4.11 return DEFAULT.newBinding(d);
4.12 }
4.13 - static FunctionBinding createFunction(List<String> subList) {
4.14 - return DEFAULT.newFunction(subList);
4.15 + static <M> FunctionBinding createFunction(FBData<M> d) {
4.16 + return DEFAULT.newFunction(d);
4.17 }
4.18
4.19 public static final class PBData<M> {
4.20 public final String name;
4.21 - public final M model;
4.22 - public final SetAndGet<M> access;
4.23 public final boolean readOnly;
4.24 + private final M model;
4.25 + private final SetAndGet<M> access;
4.26
4.27 public PBData(String name, M model, SetAndGet<M> access, boolean readOnly) {
4.28 this.name = name;
4.29 @@ -81,5 +81,22 @@
4.30 public boolean isReadOnly() {
4.31 return readOnly;
4.32 }
4.33 - }
4.34 + } // end of PBData
4.35 +
4.36 + public static final class FBData<M> {
4.37 + public final String name;
4.38 + private final M model;
4.39 + private final Callback<M> access;
4.40 +
4.41 + public FBData(String name, M model, Callback<M> access) {
4.42 + this.name = name;
4.43 + this.model = model;
4.44 + this.access = access;
4.45 + }
4.46 +
4.47 +
4.48 + public void call(Object data, Object ev) {
4.49 + access.call(model, data, ev);
4.50 + }
4.51 + } // end of FBData
4.52 }
5.1 --- a/json/src/main/java/org/apidesign/html/json/spi/FunctionBinding.java Mon Apr 22 21:36:07 2013 +0200
5.2 +++ b/json/src/main/java/org/apidesign/html/json/spi/FunctionBinding.java Mon Apr 22 22:30:30 2013 +0200
5.3 @@ -20,9 +20,9 @@
5.4 */
5.5 package org.apidesign.html.json.spi;
5.6
5.7 -import java.util.List;
5.8 import net.java.html.json.Function;
5.9 import net.java.html.json.Model;
5.10 +import org.apidesign.html.json.impl.PropertyBindingAccessor.FBData;
5.11
5.12 /** Describes a function provided by the {@link Model} and
5.13 * annotated by {@link Function} annotation.
5.14 @@ -30,13 +30,23 @@
5.15 * @author Jaroslav Tulach <jtulach@netbeans.org>
5.16 */
5.17 public final class FunctionBinding {
5.18 - private final List<String> params;
5.19 + private final FBData<?> fb;
5.20
5.21 - FunctionBinding(List<String> p) {
5.22 - this.params = p;
5.23 + FunctionBinding(FBData<?> fb) {
5.24 + this.fb = fb;
5.25 }
5.26
5.27 public String getFunctionName() {
5.28 - return params.get(0);
5.29 + return fb.name;
5.30 + }
5.31 +
5.32 + /** Calls the function provided data associated with current element,
5.33 + * as well as information about the event that triggered the event.
5.34 + *
5.35 + * @param data data associated with selected element
5.36 + * @param ev event (with additional properties) that triggered the event
5.37 + */
5.38 + public void call(Object data, Object ev) {
5.39 + fb.call(data, ev);
5.40 }
5.41 }
6.1 --- a/json/src/main/java/org/apidesign/html/json/spi/PropertyBinding.java Mon Apr 22 21:36:07 2013 +0200
6.2 +++ b/json/src/main/java/org/apidesign/html/json/spi/PropertyBinding.java Mon Apr 22 22:30:30 2013 +0200
6.3 @@ -45,8 +45,8 @@
6.4 }
6.5
6.6 @Override
6.7 - protected FunctionBinding newFunction(List<String> params) {
6.8 - return new FunctionBinding(params);
6.9 + protected <M> FunctionBinding newFunction(FBData<M> d) {
6.10 + return new FunctionBinding(d);
6.11 }
6.12 };
6.13 }
7.1 --- a/json/src/test/java/net/java/html/json/MapModelTest.java Mon Apr 22 21:36:07 2013 +0200
7.2 +++ b/json/src/test/java/net/java/html/json/MapModelTest.java Mon Apr 22 22:30:30 2013 +0200
7.3 @@ -21,7 +21,6 @@
7.4 package net.java.html.json;
7.5
7.6 import java.lang.reflect.InvocationTargetException;
7.7 -import java.lang.reflect.Method;
7.8 import java.util.HashMap;
7.9 import java.util.Map;
7.10 import org.apidesign.html.json.impl.WrapperObject;
7.11 @@ -85,16 +84,28 @@
7.12 Map m = (Map)WrapperObject.find(p);
7.13 Object o = m.get("changeSex");
7.14 assertNotNull(o, "Function registered in the model");
7.15 -
7.16 - // TBD: invoke
7.17 + assertEquals(o.getClass(), One.class);
7.18 +
7.19 + One one = (One)o;
7.20 + assertNotNull(one.fb, "Function binding specified");
7.21 +
7.22 + one.fb.call("Hello", new Object());
7.23 +
7.24 + assertEquals(p.getSex(), Sex.FEMALE, "Changed");
7.25 }
7.26
7.27 private static final class One {
7.28 int changes;
7.29 final PropertyBinding pb;
7.30 + final FunctionBinding fb;
7.31
7.32 One(Object m, PropertyBinding pb) throws NoSuchMethodException {
7.33 this.pb = pb;
7.34 + this.fb = null;
7.35 + }
7.36 + One(Object m, FunctionBinding fb) throws NoSuchMethodException {
7.37 + this.pb = null;
7.38 + this.fb = fb;
7.39 }
7.40
7.41 Object get() throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
7.42 @@ -134,7 +145,7 @@
7.43 @Override
7.44 public void expose(FunctionBinding fb, Object model, Map<String, One> data) {
7.45 try {
7.46 - data.put(fb.getFunctionName(), new One(model, null));
7.47 + data.put(fb.getFunctionName(), new One(model, fb));
7.48 } catch (NoSuchMethodException ex) {
7.49 throw new IllegalStateException(ex);
7.50 }