Package ru.yandex.strictweb.scriptjava.base.ajax

Source Code of ru.yandex.strictweb.scriptjava.base.ajax.Ajax

package ru.yandex.strictweb.scriptjava.base.ajax;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import ru.yandex.strictweb.scriptjava.base.ActiveXObject;
import ru.yandex.strictweb.scriptjava.base.CommonDelegate;
import ru.yandex.strictweb.scriptjava.base.DOMBuilder;
import ru.yandex.strictweb.scriptjava.base.DOMEvent;
import ru.yandex.strictweb.scriptjava.base.JsException;
import ru.yandex.strictweb.scriptjava.base.MayBeExcluded;
import ru.yandex.strictweb.scriptjava.base.Native;
import ru.yandex.strictweb.scriptjava.base.NativeCode;
import ru.yandex.strictweb.scriptjava.base.Node;
import ru.yandex.strictweb.scriptjava.base.NodeBuilder;
import ru.yandex.strictweb.scriptjava.base.StrictWeb;
import ru.yandex.strictweb.scriptjava.base.VoidDelegate;
import ru.yandex.strictweb.scriptjava.base.util.Log;
import ru.yandex.strictweb.scriptjava.compiler.Compiler;
import ru.yandex.strictweb.scriptjava.plugins.AjaxServiceHelperCompilerPlugin;
import ru.yandex.strictweb.scriptjava.plugins.EntityCompilerPlugin;

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);
  }
}
TOP

Related Classes of ru.yandex.strictweb.scriptjava.base.ajax.Ajax

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.