SPI for JSON and JSONP queries
authorJaroslav Tulach <jaroslav.tulach@apidesign.org>
Tue, 23 Apr 2013 10:15:46 +0200
changeset 24ae78a6f9d1d2
parent 23 54e266fb5c67
child 25 fa6010aedcdf
SPI for JSON and JSONP queries
json/src/main/java/org/apidesign/html/json/impl/JSON.java
json/src/main/java/org/apidesign/html/json/impl/ModelProcessor.java
json/src/main/java/org/apidesign/html/json/impl/PropertyBindingAccessor.java
json/src/main/java/org/apidesign/html/json/spi/ContextBuilder.java
json/src/main/java/org/apidesign/html/json/spi/JSONCall.java
json/src/main/java/org/apidesign/html/json/spi/PropertyBinding.java
json/src/main/java/org/apidesign/html/json/spi/Transfer.java
json/src/test/java/net/java/html/json/MapModelTest.java
json/src/test/java/net/java/html/json/ModelTest.java
     1.1 --- a/json/src/main/java/org/apidesign/html/json/impl/JSON.java	Tue Apr 23 08:43:11 2013 +0200
     1.2 +++ b/json/src/main/java/org/apidesign/html/json/impl/JSON.java	Tue Apr 23 10:15:46 2013 +0200
     1.3 @@ -21,7 +21,7 @@
     1.4  package org.apidesign.html.json.impl;
     1.5  
     1.6  import net.java.html.json.Context;
     1.7 -import org.apidesign.html.json.spi.Technology;
     1.8 +import org.apidesign.html.json.spi.JSONCall;
     1.9  import org.apidesign.html.json.spi.Transfer;
    1.10  
    1.11  /**
    1.12 @@ -79,11 +79,12 @@
    1.13      }
    1.14  
    1.15      
    1.16 -    public static String createJSONP(Object[] res, Runnable callback) {
    1.17 -        return null;
    1.18 -    }
    1.19 -
    1.20 -    public static Object loadJSON(String url, Object[] res, Runnable callback, String jsonp) {
    1.21 -        return null;
    1.22 +    public static void loadJSON(
    1.23 +        Context c, Runnable whenDone, Object[] result, 
    1.24 +        String urlBefore, String urlAfter
    1.25 +    ) {
    1.26 +        JSONCall call = PropertyBindingAccessor.createCall(whenDone, result, urlBefore, urlAfter);
    1.27 +        Transfer t = ContextAccessor.findTransfer(c);
    1.28 +        t.loadJSON(call);
    1.29      }
    1.30  }
     2.1 --- a/json/src/main/java/org/apidesign/html/json/impl/ModelProcessor.java	Tue Apr 23 08:43:11 2013 +0200
     2.2 +++ b/json/src/main/java/org/apidesign/html/json/impl/ModelProcessor.java	Tue Apr 23 10:15:46 2013 +0200
     2.3 @@ -749,12 +749,13 @@
     2.4              }
     2.5              String n = e.getSimpleName().toString();
     2.6              body.append("public void ").append(n).append("(");
     2.7 -            StringBuilder assembleURL = new StringBuilder();
     2.8 +            StringBuilder urlBefore = new StringBuilder();
     2.9 +            StringBuilder urlAfter = new StringBuilder();
    2.10              String jsonpVarName = null;
    2.11              {
    2.12                  String sep = "";
    2.13                  boolean skipJSONP = onR.jsonp().isEmpty();
    2.14 -                for (String p : findParamNames(e, onR.url(), assembleURL)) {
    2.15 +                for (String p : findParamNames(e, onR.url(), onR.jsonp(), urlBefore, urlAfter)) {
    2.16                      if (!skipJSONP && p.equals(onR.jsonp())) {
    2.17                          skipJSONP = true;
    2.18                          jsonpVarName = p;
    2.19 @@ -807,13 +808,14 @@
    2.20                  "  }\n"
    2.21              );
    2.22              body.append("  ProcessResult pr = new ProcessResult();\n");
    2.23 +            body.append("  org.apidesign.html.json.impl.JSON.loadJSON(context, pr, result,\n      ");
    2.24 +            body.append(urlBefore).append(", ");
    2.25              if (jsonpVarName != null) {
    2.26 -                body.append("  String ").append(jsonpVarName).
    2.27 -                    append(" = org.apidesign.html.json.impl.JSON.createJSONP(result, pr);\n");
    2.28 +                body.append(urlAfter);
    2.29 +            } else {
    2.30 +                body.append("null");
    2.31              }
    2.32 -            body.append("  org.apidesign.html.json.impl.JSON.loadJSON(\n      ");
    2.33 -            body.append(assembleURL);
    2.34 -            body.append(", result, pr, ").append(jsonpVarName).append("\n  );\n");
    2.35 +            body.append(");\n");
    2.36  //            body.append("  ").append(clazz.getSimpleName()).append(".").append(n).append("(");
    2.37  //            body.append(wrapParams(e, null, className, "ev", "data"));
    2.38  //            body.append(");\n");
    2.39 @@ -1084,13 +1086,16 @@
    2.40          return false;
    2.41      }
    2.42  
    2.43 -    private Iterable<String> findParamNames(Element e, String url, StringBuilder assembleURL) {
    2.44 +    private Iterable<String> findParamNames(
    2.45 +        Element e, String url, String jsonParam, StringBuilder... both
    2.46 +    ) {
    2.47          List<String> params = new ArrayList<>();
    2.48 +        int wasJSON = 0;
    2.49  
    2.50          for (int pos = 0; ;) {
    2.51              int next = url.indexOf('{', pos);
    2.52              if (next == -1) {
    2.53 -                assembleURL.append('"')
    2.54 +                both[wasJSON].append('"')
    2.55                      .append(url.substring(pos))
    2.56                      .append('"');
    2.57                  return params;
    2.58 @@ -1102,9 +1107,16 @@
    2.59              }
    2.60              final String paramName = url.substring(next + 1, close);
    2.61              params.add(paramName);
    2.62 -            assembleURL.append('"')
    2.63 -                .append(url.substring(pos, next))
    2.64 -                .append("\" + ").append(paramName).append(" + ");
    2.65 +            if (paramName.equals(jsonParam) && !jsonParam.isEmpty()) {
    2.66 +                both[wasJSON].append('"')
    2.67 +                    .append(url.substring(pos, next))
    2.68 +                    .append('"');
    2.69 +                wasJSON = 1;
    2.70 +            } else {
    2.71 +                both[wasJSON].append('"')
    2.72 +                    .append(url.substring(pos, next))
    2.73 +                    .append("\" + ").append(paramName).append(" + ");
    2.74 +            }
    2.75              pos = close + 1;
    2.76          }
    2.77      }
     3.1 --- a/json/src/main/java/org/apidesign/html/json/impl/PropertyBindingAccessor.java	Tue Apr 23 08:43:11 2013 +0200
     3.2 +++ b/json/src/main/java/org/apidesign/html/json/impl/PropertyBindingAccessor.java	Tue Apr 23 10:15:46 2013 +0200
     3.3 @@ -20,8 +20,8 @@
     3.4   */
     3.5  package org.apidesign.html.json.impl;
     3.6  
     3.7 -import java.util.List;
     3.8  import org.apidesign.html.json.spi.FunctionBinding;
     3.9 +import org.apidesign.html.json.spi.JSONCall;
    3.10  import org.apidesign.html.json.spi.PropertyBinding;
    3.11  
    3.12  /**
    3.13 @@ -49,6 +49,10 @@
    3.14  
    3.15      protected abstract <M> PropertyBinding newBinding(PBData<M> d);
    3.16      protected abstract <M> FunctionBinding newFunction(FBData<M> d);
    3.17 +    protected abstract JSONCall newCall(
    3.18 +        Runnable whenDone, Object[] result, String urlBefore, String urlAfter
    3.19 +    );
    3.20 +
    3.21      
    3.22      static <M> PropertyBinding create(PBData<M> d) {
    3.23          return DEFAULT.newBinding(d);
    3.24 @@ -56,6 +60,11 @@
    3.25      static <M> FunctionBinding createFunction(FBData<M> d) {
    3.26          return DEFAULT.newFunction(d);
    3.27      }
    3.28 +    static JSONCall createCall(
    3.29 +        Runnable whenDone, Object[] result, String urlBefore, String urlAfter
    3.30 +    ) {
    3.31 +        return DEFAULT.newCall(whenDone, result, urlBefore, urlAfter);
    3.32 +    }
    3.33  
    3.34      public static final class PBData<M> {
    3.35          public final String name;
     4.1 --- a/json/src/main/java/org/apidesign/html/json/spi/ContextBuilder.java	Tue Apr 23 08:43:11 2013 +0200
     4.2 +++ b/json/src/main/java/org/apidesign/html/json/spi/ContextBuilder.java	Tue Apr 23 10:15:46 2013 +0200
     4.3 @@ -112,6 +112,11 @@
     4.4                  values[i] = null;
     4.5              }
     4.6          }
     4.7 +
     4.8 +        @Override
     4.9 +        public void loadJSON(JSONCall call) {
    4.10 +            call.notifyError(new UnsupportedOperationException());
    4.11 +        }
    4.12      }
    4.13      
    4.14  }
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/json/src/main/java/org/apidesign/html/json/spi/JSONCall.java	Tue Apr 23 10:15:46 2013 +0200
     5.3 @@ -0,0 +1,66 @@
     5.4 +/**
     5.5 + * HTML via Java(tm) Language Bindings
     5.6 + * Copyright (C) 2013 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
     5.7 + *
     5.8 + * This program is free software: you can redistribute it and/or modify
     5.9 + * it under the terms of the GNU General Public License as published by
    5.10 + * the Free Software Foundation, version 2 of the License.
    5.11 + *
    5.12 + * This program is distributed in the hope that it will be useful,
    5.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    5.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    5.15 + * GNU General Public License for more details. apidesign.org
    5.16 + * designates this particular file as subject to the
    5.17 + * "Classpath" exception as provided by apidesign.org
    5.18 + * in the License file that accompanied this code.
    5.19 + *
    5.20 + * You should have received a copy of the GNU General Public License
    5.21 + * along with this program. Look for COPYING file in the top folder.
    5.22 + * If not, see http://wiki.apidesign.org/wiki/GPLwithClassPathException
    5.23 + */
    5.24 +
    5.25 +package org.apidesign.html.json.spi;
    5.26 +
    5.27 +/** Description of a JSON call request that is supposed to be processed
    5.28 + * by {@link Transfer#loadJSON(org.apidesign.html.json.spi.JSONCall)} implementors.
    5.29 + *
    5.30 + * @author Jaroslav Tulach <jtulach@netbeans.org>
    5.31 + */
    5.32 +public final class JSONCall {
    5.33 +    private final Runnable whenDone;
    5.34 +    private final Object[] result;
    5.35 +    private final String urlBefore;
    5.36 +    private final String urlAfter;
    5.37 +
    5.38 +    JSONCall(Runnable whenDone, Object[] result, String urlBefore, String urlAfter) {
    5.39 +        this.whenDone = whenDone;
    5.40 +        this.result = result;
    5.41 +        this.urlBefore = urlBefore;
    5.42 +        this.urlAfter = urlAfter;
    5.43 +    }
    5.44 +    
    5.45 +    public boolean isJSONP() {
    5.46 +        return urlAfter != null;
    5.47 +    }
    5.48 +    
    5.49 +    public String composeURL(String jsonpCallback) {
    5.50 +        if ((urlAfter == null) != (jsonpCallback == null)) {
    5.51 +            throw new IllegalStateException();
    5.52 +        }
    5.53 +        if (urlAfter != null) {
    5.54 +            return urlBefore + jsonpCallback + urlAfter;
    5.55 +        } else {
    5.56 +            return urlBefore;
    5.57 +        }
    5.58 +    }
    5.59 +
    5.60 +    public void notifySuccess(Object result) {
    5.61 +        this.result[0] = result;
    5.62 +        this.whenDone.run();
    5.63 +    }
    5.64 +    
    5.65 +    public void notifyError(Throwable error) {
    5.66 +        this.result[0] = error;
    5.67 +        this.whenDone.run();
    5.68 +    }
    5.69 +}
     6.1 --- a/json/src/main/java/org/apidesign/html/json/spi/PropertyBinding.java	Tue Apr 23 08:43:11 2013 +0200
     6.2 +++ b/json/src/main/java/org/apidesign/html/json/spi/PropertyBinding.java	Tue Apr 23 10:15:46 2013 +0200
     6.3 @@ -20,7 +20,6 @@
     6.4   */
     6.5  package org.apidesign.html.json.spi;
     6.6  
     6.7 -import java.util.List;
     6.8  import org.apidesign.html.json.impl.PropertyBindingAccessor;
     6.9  import org.apidesign.html.json.impl.PropertyBindingAccessor.PBData;
    6.10  import org.apidesign.html.json.impl.WrapperObject;
    6.11 @@ -48,6 +47,11 @@
    6.12              protected <M> FunctionBinding newFunction(FBData<M> d) {
    6.13                  return new FunctionBinding(d);
    6.14              }
    6.15 +
    6.16 +            @Override
    6.17 +            protected JSONCall newCall(Runnable whenDone, Object[] result, String urlBefore, String urlAfter) {
    6.18 +                return new JSONCall(whenDone, result, urlBefore, urlAfter);
    6.19 +            }
    6.20          };
    6.21      }
    6.22  
     7.1 --- a/json/src/main/java/org/apidesign/html/json/spi/Transfer.java	Tue Apr 23 08:43:11 2013 +0200
     7.2 +++ b/json/src/main/java/org/apidesign/html/json/spi/Transfer.java	Tue Apr 23 10:15:46 2013 +0200
     7.3 @@ -40,4 +40,10 @@
     7.4       */
     7.5      public void extract(Object obj, String[] props, Object[] values);
     7.6      
     7.7 +    /** Starts the JSON or JSONP query. 
     7.8 +     * 
     7.9 +     * @param call description of the call to make
    7.10 +     */
    7.11 +    public void loadJSON(JSONCall call);
    7.12 +    
    7.13  }
     8.1 --- a/json/src/test/java/net/java/html/json/MapModelTest.java	Tue Apr 23 08:43:11 2013 +0200
     8.2 +++ b/json/src/test/java/net/java/html/json/MapModelTest.java	Tue Apr 23 10:15:46 2013 +0200
     8.3 @@ -26,6 +26,7 @@
     8.4  import org.apidesign.html.json.impl.WrapperObject;
     8.5  import org.apidesign.html.json.spi.ContextBuilder;
     8.6  import org.apidesign.html.json.spi.FunctionBinding;
     8.7 +import org.apidesign.html.json.spi.JSONCall;
     8.8  import org.apidesign.html.json.spi.PropertyBinding;
     8.9  import org.apidesign.html.json.spi.Technology;
    8.10  import org.apidesign.html.json.spi.Transfer;
    8.11 @@ -193,5 +194,10 @@
    8.12                  }
    8.13              }
    8.14          }
    8.15 +
    8.16 +        @Override
    8.17 +        public void loadJSON(JSONCall call) {
    8.18 +            call.notifyError(new UnsupportedOperationException());
    8.19 +        }
    8.20      }
    8.21  }
     9.1 --- a/json/src/test/java/net/java/html/json/ModelTest.java	Tue Apr 23 08:43:11 2013 +0200
     9.2 +++ b/json/src/test/java/net/java/html/json/ModelTest.java	Tue Apr 23 10:15:46 2013 +0200
     9.3 @@ -168,6 +168,13 @@
     9.4          m.applyBindings();
     9.5          m.loadPeople("http", "apidesign.org", "query");
     9.6      }
     9.7 +
     9.8 +    @OnReceive(url = "{protocol}://{host}?callback={back}&query={query}", jsonp = "back")
     9.9 +    static void loadPeopleViaJSONP(Modelik thiz, People p) {
    9.10 +        Modelik m = null;
    9.11 +        m.applyBindings();
    9.12 +        m.loadPeopleViaJSONP("http", "apidesign.org", "query");
    9.13 +    }
    9.14      
    9.15      @Function 
    9.16      static void doSomething() {