Ejemplo n.º 1
0
 public void makeBatchRequests() {
   if (requestQueue.size() > 0) {
     List<AjaxRequest> queue = requestQueue;
     requestQueue = StrictWeb.jsNewList();
     makeRequest(true, queue, null);
   }
   autoRequest = true;
 }
Ejemplo n.º 2
0
  public Object call(
      String clazz,
      final String method,
      Object[] args,
      final VoidDelegate<Object> callBack,
      final VoidDelegate<Throwable> errorHandler)
      throws Throwable {
    if (errorHandler != null) errorHandler.voidDelegate(null);
    else onError(null);

    boolean async = callBack != null;
    if (!async || autoRequest) {
      List<AjaxRequest> requests = StrictWeb.jsNewList();
      requests.add(new AjaxRequest(clazz, method, args, callBack, errorHandler));
      return makeRequest(async, requests, errorHandler);
    } else {
      requestQueue.add(new AjaxRequest(clazz, method, args, callBack, errorHandler));
      return null;
    }
  }
Ejemplo n.º 3
0
public class Ajax {
  public static final String FIELD_MULTISELECT = "field.multiselect";
  private static final String MICROSOFT_XMLHTTP = "Microsoft.XMLHTTP";
  private static final String EV_ONREADYSTATECHANGE = "onreadystatechange";
  public static Ajax helper;

  boolean autoRequest = true;
  List<AjaxRequest> requestQueue = StrictWeb.jsNewList();

  public String getRequestUrl(List<AjaxRequest> requests) {
    return "/ajax";
  }

  //    public String getQueryString(List<AjaxRequest> requests) {
  //        String query = "_rnd="+Math.random();
  //
  //        for(int i=0; i<requests.size(); i++) {
  //            AjaxRequest r = requests.get(i);
  //            query += "&" + BEAN_NAME_PARAM+i+"="+r.clazz + "&"+METHOD_NAME_PARAM+i+"="+r.method;
  //        }
  //
  //        return query;
  //    }

  public String getLoadingImageUrl() {
    return null;
  }

  public XMLHttpRequest getHttpRequest() {
    if (StrictWeb.window.XMLHttpRequest != null) {
      return new XMLHttpRequest();
    }

    return (XMLHttpRequest) (Object) new ActiveXObject(MICROSOFT_XMLHTTP);
  }

  /** this method handles error events. If null is passed - this means reset errors */
  public void onError(Throwable exception) {
    if (exception == null) return;
    Log.error("Ajax call exception: " + exception.getMessage());
    if (exception.getStackTrace() != null)
      for (StackTraceElement ste : exception.getStackTrace()) {
        Log.error(
            " at " + ste.getClassName() + "." + ste.getMethodName() + " : " + ste.getLineNumber());
      }
    if (exception.getCause() != null) {
      Log.error("Caused by:");
      onError(exception.getCause());
    }
  }

  public void beginBatch() {
    autoRequest = false;
  }

  public void makeBatchRequests() {
    if (requestQueue.size() > 0) {
      List<AjaxRequest> queue = requestQueue;
      requestQueue = StrictWeb.jsNewList();
      makeRequest(true, queue, null);
    }
    autoRequest = true;
  }

  public Object call(
      String clazz,
      final String method,
      Object[] args,
      final VoidDelegate<Object> callBack,
      final VoidDelegate<Throwable> errorHandler)
      throws Throwable {
    if (errorHandler != null) errorHandler.voidDelegate(null);
    else onError(null);

    boolean async = callBack != null;
    if (!async || autoRequest) {
      List<AjaxRequest> requests = StrictWeb.jsNewList();
      requests.add(new AjaxRequest(clazz, method, args, callBack, errorHandler));
      return makeRequest(async, requests, errorHandler);
    } else {
      requestQueue.add(new AjaxRequest(clazz, method, args, callBack, errorHandler));
      return null;
    }
  }

  Object makeRequest(
      boolean async, final List<AjaxRequest> requests, final VoidDelegate<Throwable> errorHandler) {
    onError(null);

    XMLHttpRequest request = getHttpRequest();
    //        String postXml = "";
    //
    //        for(int i=0; i<requests.size(); i++) {
    //            AjaxRequest r = requests.get(i);
    //	        if(r.errorHandler != null) r.errorHandler.voidDelegate(null);
    //	        postXml += "&"+XML_DATA_PARAM+i+"="
    //	            + objectToXml(r.args, null).replaceAll("%", "%25").replaceAll("&",
    // "%26").replaceAll(";", "%3B").replaceAll("\\+", "%2B");
    //	    }

    String postJson = "[";
    for (int i = 0; i < requests.size(); i++) {
      AjaxRequest r = requests.get(i);
      postJson += objectToJson(r.clazz) + "," + objectToJson(r.method) + "," + arrayToJson(r.args);
      if (i != requests.size() - 1) postJson += ",";
    }
    postJson += "]";

    final String url = getRequestUrl(requests);

    final Node[] eventTargetNodes = new Node[3];

    eventTargetDisable(eventTargetNodes);

    if (async) {
      StrictWeb.setVoidEventCallback(
          request,
          EV_ONREADYSTATECHANGE,
          new VoidDelegate<XMLHttpRequest>() {
            public void voidDelegate(XMLHttpRequest request) {
              if (request.readyState == 4) {
                try {
                  StrictWeb.setVoidEventCallback(request, EV_ONREADYSTATECHANGE, null);
                } catch (Exception e) {
                  /*StrictWeb.window.alert(e);*/
                }
                eventTargetEnable(eventTargetNodes);

                if (request.status == 200) {
                  AjaxRequestResult[] results = parseRequestResult(request, url, requests);
                  for (int i = 0; i < results.length; i++) {
                    AjaxRequestResult res = results[i];
                    AjaxRequest req = requests.get(i);
                    Throwable error = res.getError();
                    if (error != null) {
                      throwError(
                          "Ajax.call(" + req.method + "): server-side exception",
                          error,
                          req.errorHandler);
                    } else {
                      req.callBack.voidDelegate(res.data);
                    }
                  }
                } else {
                  throwError("Error status: " + request.status, null, errorHandler);
                }
              }
            }
          });
    }

    //		postXml = getQueryString(requests) + postXml;
    request.open("POST", url, async, null, null);

    Log.info("POST URL : " + url);
    Log.info("POST JSON: " + postJson);
    Log.info("POST args:");
    Log.info(requests);

    setRequestHeaders(request);
    request.send(postJson);

    if (async) return null;

    // doing sync parse
    eventTargetEnable(eventTargetNodes);
    AjaxRequestResult res = parseRequestResult(request, url, requests)[0];
    AjaxRequest req = requests.get(0);
    Throwable error = res.getError();
    if (error != null) {
      throwError("Ajax.call(" + req.method + "): server-side exception", error, req.errorHandler);
    }
    return res.data;
  }

  public void setRequestHeaders(XMLHttpRequest request) {
    //		request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    request.setRequestHeader("Content-type", "application/json");
  }

  private AjaxRequestResult[] parseRequestResult(
      XMLHttpRequest request, String url, List<AjaxRequest> requests) {
    long status = request.status;
    String responseText = request.responseText;
    String statusText = request.statusText;
    request = null;
    AjaxRequestResult[] result = null;

    if (status == 200) {
      try {
        Object evalResult;
        if (responseText.charAt(0) == 'v') {
          evalResult = StrictWeb.evalFunction(responseText + "\nreturn o._a;");
        } else {
          evalResult = StrictWeb.evalFunction("return " + responseText);
        }
        result = (AjaxRequestResult[]) evalResult;
        Log.debug("Ajax result:");
        Log.debug(result);
      } catch (Throwable e) {
        throwError("Ajax.call(" + getMethodsNames(requests) + "): eval error", e, null);
      }
    } else {
      throwError(
          "Ajax.call("
              + getMethodsNames(requests)
              + "): http error:\n"
              + "URL: "
              + url
              + "\nCode: "
              + status
              + "\nMessage: "
              + statusText,
          null,
          null);
    }

    if (result == null) {
      throwError(
          "Ajax.call(" + getMethodsNames(requests) + "): result is null: " + responseText,
          null,
          null);
    }

    if (result.length != requests.size()) {
      throwError(
          "Ajax.call("
              + getMethodsNames(requests)
              + "): results count in not equal requests count: "
              + result.length
              + "!="
              + requests.size(),
          null,
          null);
    }

    return result;
  }

  public String getMethodsNames(List<AjaxRequest> requests) {
    String methods = "";
    for (int i = 0; i < requests.size(); i++) {
      AjaxRequest r = requests.get(i);
      methods += (i > 0 ? "," : "") + r.method;
    }
    return methods;
  }

  public void eventTargetDisable(Node[] eventTargetNodes) {
    DOMEvent ev = StrictWeb.globalEvent;

    Node el = StrictWeb.swTarget;
    if (el == null) {
      if (null == ev) return;
      el = ev.target;
    }
    try {
      if (el == null) el = ev.srcElement;
      if (el == null) el = ev.fromElement;
    } catch (Exception e) {
      /* NOP */
    }

    if (el == null || null == el.tagName || el.parentNode == null) return;

    // node
    eventTargetNodes[0] = el;
    // parent
    eventTargetNodes[1] = el.parentNode;
    // loading
    String loadingImgUrl = getLoadingImageUrl();
    eventTargetNodes[2] =
        (null != loadingImgUrl
                ? StrictWeb.EL("span")
                    .styleDisplay("inline-block")
                    .styleWidth(el.offsetWidth + "px")
                    .styleHeight(el.offsetHeight + "px")
                    .styleBackground("center center no-repeat url(" + loadingImgUrl + ")")
                : StrictWeb.EL("span").text("loading..."))
            .node;

    eventTargetNodes[1].insertBefore(eventTargetNodes[2], eventTargetNodes[0]);
    eventTargetNodes[1].removeChild(eventTargetNodes[0]);
  }

  public void eventTargetEnable(Node[] eventTargetNodes) {
    if (null == eventTargetNodes || eventTargetNodes.length != 3) return;

    eventTargetNodes[1].insertBefore(eventTargetNodes[0], eventTargetNodes[2]);
    eventTargetNodes[1].removeChild(eventTargetNodes[2]);

    eventTargetNodes[0] = eventTargetNodes[1] = eventTargetNodes[2] = null;
  }

  void throwError(String shortMsg, Throwable th, VoidDelegate<Throwable> errorHandler) {
    if (th == null) th = new JsException(shortMsg);

    if (errorHandler != null) {
      errorHandler.voidDelegate(th);
    } else {
      onError(th);
    }
  }

  @NativeCode("{throw th;}")
  private static <T> T nativeJsThrow(Object th) {
    return null;
  }

  @MayBeExcluded
  public static String objectToJson(Object obj) {
    if (StrictWeb.jsTypeOf(obj) == "undefined") return "null";
    if (StrictWeb.jsTypeOf(obj) == "string") return '"' + StrictWeb.toJSON((String) obj) + '"';
    if (StrictWeb.jsTypeOf(obj) == "boolean") return ((Boolean) obj) ? "1" : "0";
    if (StrictWeb.jsTypeOf(obj) == "number") return obj.toString();
    if (StrictWeb.jsTypeOf(obj) == "object") {
      if (obj == null) return "null";
      if (StrictWeb.isEnum(obj)) return obj.toString();
      if (StrictWeb.isInstanceOfDate(obj)) return StrictWeb.dateToStringSmart((Date) obj);
      if (StrictWeb.isInstanceOfArray(obj)) return arrayToJson((Object[]) obj);
      if (StrictWeb.isInstanceOfNode(obj)) {
        String json = formToJson((Node) obj);
        if (json != null && json.length() > 0 && json.charAt(0) == '{') return "[" + json + "]";
        return "{" + json + "}";
      }
      Map<String, String> map = (Map<String, String>) obj;
      String json = "";
      for (String key : map.keySet()) {
        String val = map.get(key);
        if (StrictWeb.jsTypeOf(val) == "function") continue;
        if (json.length() > 0) json += ",";
        json += objectToJson(key) + ":" + objectToJson(val);
      }
      return "{" + json + "}";
    }

    return nativeJsThrow("Unknown object type: " + StrictWeb.jsTypeOf(obj));
  }

  @MayBeExcluded
  public static String arrayToJson(Object[] a) {
    if (a == null) return "null";
    String json = "";
    for (int i = 0; i < a.length; i++) {
      Object val = a[i];
      if (StrictWeb.jsTypeOf(val) == "function") continue;

      if (json.length() > 0) json += ",";
      json += objectToJson(val);
    }
    return "[" + json + "]";
  }

  @MayBeExcluded
  public static String formToJson(Node start) {
    if (start.field == DOMBuilder.DISABLED) return "";

    String json = "";
    boolean asArray = false;

    for (Node el : start.childNodes) {
      if (el.field == DOMBuilder.DISABLED) continue;
      if (((Boolean) (Object) el.id || (Boolean) (Object) el.name)
          && (el.tagName == "INPUT" || el.tagName == "SELECT" || el.tagName == "TEXTAREA")) {
        if (el.type == "radio" && !el.checked) continue;
        if (json.length() > 0) json += ",";
        if (asArray) throw new RuntimeException("Form returned as array, not at map");
        json += objectToJson((Boolean) (Object) el.id || (Boolean) (Object) el.name) + ":";

        if (el.type == "checkbox") json += el.checked ? "1" : "0";
        else json += objectToJson(el.value);

      } else if (el.className != null && el.className.indexOf(FIELD_MULTISELECT) >= 0) {
        final List<Object> val = new ArrayList<Object>();
        NodeBuilder.wrap(el)
            .forEachSubchild(
                new CommonDelegate<Boolean, Node>() {
                  public Boolean delegate(Node n) {
                    if (n.field == DOMBuilder.DISABLED) return false;
                    if (n.tagName == "INPUT" || n.tagName == "SELECT") {
                      if (n.type == "checkbox") {
                        if (n.checked)
                          val.add((Boolean) (Object) n.id || (Boolean) (Object) n.name);
                      } else {
                        val.add((String) n.value);
                      }
                    }
                    return true;
                  }
                });

        if (json.length() > 0) json += ",";
        if (asArray) nativeJsThrow("Form returned as array, not as map 1");
        json += objectToJson(el.field) + ":" + arrayToJson((Object[]) (Object) val);
      } else {
        String childJson = formToJson(el);
        if (childJson != null && childJson.length() > 0) {
          if (childJson.charAt(0) == '{') asArray = true;
          else if (asArray) nativeJsThrow("Form returned as array, not as map 2");

          if (json.length() > 0) json += ",";
          json += childJson;
        }
      }
    }

    if (start.field != null) {
      String bra = asArray ? "[" : "{";
      String ket = asArray ? "]" : "}";

      if (StrictWeb.jsTypeOf(start.field) == "string") {
        return objectToJson(start.field) + ":" + bra + json + ket;
      } else return bra + json + ket;
    }

    return json;
  }

  @MayBeExcluded
  public static String objectToXml(Object obj, String _id) {
    String id = (_id != null ? " id=\"" + _id + "\"" : "");
    if (StrictWeb.jsTypeOf(obj) == "undefined") return "<null" + id + "/>";
    if (StrictWeb.jsTypeOf(obj) == "string")
      return "<s" + id + ">" + StrictWeb.toHTML((String) obj) + "</s>";
    if (StrictWeb.jsTypeOf(obj) == "boolean")
      return ((Boolean) obj) ? "<b" + id + ">1</b>" : "<b" + id + ">0</b>";
    if (StrictWeb.jsTypeOf(obj) == "number") return "<n" + id + ">" + obj + "</n>";
    if (StrictWeb.jsTypeOf(obj) == "object") {
      if (obj == null) return "<null" + id + "/>";
      if (StrictWeb.isEnum(obj)) return "<e" + id + ">" + obj.toString() + "</e>";
      if (StrictWeb.isInstanceOfDate(obj))
        return "<d" + id + ">" + StrictWeb.dateToStringSmart((Date) obj) + "</d>";
      if (StrictWeb.isInstanceOfArray(obj)) return arrayToXml((Object[]) obj, id);
      if (StrictWeb.isInstanceOfNode(obj)) {
        return "<form" + id + ">" + formToXml((Node) obj) + "</form>";
      }
      Map<String, String> map = (Map<String, String>) obj;
      String xml = "<o" + id + ">";
      for (String key : map.keySet()) {
        String val = map.get(key);
        if (StrictWeb.jsTypeOf(val) != "function") xml += objectToXml(val, key);
      }
      return xml + "</o>";
    }

    return "<" + StrictWeb.jsTypeOf(obj) + "/>";
  }

  @MayBeExcluded
  public static String formToXml(Node start) {
    String xml = "";

    if (start.field == DOMBuilder.DISABLED) return xml;

    if (start.field != null) {
      if (StrictWeb.jsTypeOf(start.field) == "string") {
        xml = "<f id=\"" + start.field + "\">";
      } else xml = "<f>";
    }

    for (Node el : start.childNodes) {
      if (el.field == DOMBuilder.DISABLED) continue;
      if (((Boolean) (Object) el.id || (Boolean) (Object) el.name)
          && (el.tagName == "INPUT" || el.tagName == "SELECT" || el.tagName == "TEXTAREA")) {
        if (el.type == "radio" && !el.checked) continue;

        xml += "<f id=\"" + ((Boolean) (Object) el.id || (Boolean) (Object) el.name) + "\">";

        if (el.type == "checkbox") xml += el.checked ? "1" : "0";
        else xml += StrictWeb.toHTML((String) el.value);

        xml += "</f>";

      } else if (el.className != null && el.className.indexOf(FIELD_MULTISELECT) >= 0) {
        final List<Object> val = new ArrayList<Object>();
        NodeBuilder.wrap(el)
            .forEachSubchild(
                new CommonDelegate<Boolean, Node>() {
                  public Boolean delegate(Node n) {
                    if (n.field == DOMBuilder.DISABLED) return false;
                    if (n.tagName == "INPUT" || n.tagName == "SELECT") {
                      if (n.type == "checkbox") {
                        if (n.checked)
                          val.add((Boolean) (Object) n.id || (Boolean) (Object) n.name);
                      } else {
                        val.add((String) n.value);
                      }
                    }
                    return true;
                  }
                });

        xml +=
            "<ms id=\""
                + el.field
                + "\">"
                + (val.size() > 0 ? "<q>" : "")
                + StrictWeb.jsJoinList(val, "</q><q>")
                + (val.size() > 0 ? "</q>" : "")
                + "</ms>";
      } else xml += formToXml(el);
    }

    if (start.field != null) xml += "</f>";

    return xml;
  }

  @MayBeExcluded
  public static String arrayToXml(Object[] a, String id) {
    String xml = "<a" + id + ">";
    for (int i = 0; i < a.length; i++) {
      if (StrictWeb.jsTypeOf(a[i]) != "function") xml += objectToXml(a[i], null);
    }
    return xml + "</a>";
  }

  /** Use this method to append all Ajax specific classes to StrictWeb compier */
  @Native
  public static void prepareCompiler(Compiler compiler) throws Exception {
    compiler
        .addPlugin(new EntityCompilerPlugin())
        .addPlugin(new AjaxServiceHelperCompilerPlugin())

        //		.parseClass(AjaxException.class)
        .parseClass(AjaxRequest.class)
        .parseClass(AjaxRequestResult.class)
        .parseClass(ActiveXObject.class)
        .parseClass(Log.class)
        .parseClass(XMLHttpRequest.class)
        .parseClass(Ajax.class);
  }
}