123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772 |
- /*
- * Buffalo Web Remoting, An amowa infrastructure facility, a web remoting library.
- *
- * Author: Michael Chen (mechiland AT gmail DoT com, http://michael.nona.name)
- *
- * Version: 1.0
- *
- */
- /**
- * @fileoverview Buffalo.js is the core component of the Buffalo web remoting.
- * This file encapuslate the Buffalo, BuffaloCall, BuffaloReply object, and
- * most of it's methods.
- *
- * @author Michael Chen mechiland@gmail.com http://michael.nona.name
- * @version 1.0
- */
- /**
- * BuffaloCall object.
- * In most case, you don't need to construct a BuffaloCall yourself. just use
- * buffalo.remoteCall(...) to make common use.
- *
- * @constructor
- * @param {String} methodname the remote call method name.
- * note: this method name is ONLY the method name, not the service name.
- * Buffalo will take care of the service name and url.
- */
- //window.onerror = function(){return false};
- function BuffaloCall(methodname){
-
- /**
- * The method name
- * @type String
- * @private
- */
- this.method = methodname;
- /**
- * The parameters.
- * @type Array
- * @private
- */
- this.params = [];
-
- return this;
- }
- /**
- * Set the remote call method name.
- *
- * @param {String} methodName the method name to set.
- */
- BuffaloCall.prototype.setMethod = function(methodName){
- if (!methodName) return;
- this.method = methodName;
- }
- /**
- * Add one paramter to this buffalo call. Buffalo will try to find type
- * of the data.
- *
- * @param {varient} data the param to be added.
- */
- BuffaloCall.prototype.addParameter = function(data){
- if (arguments.length==0) return;
- this.params[this.params.length] = data;
- }
- /**
- * Construct the call informatiton to a XML format,
- * prepare to be sent to the buffalo end point.
- *
- * @type String
- * @returns the xml format of this call.
- */
- BuffaloCall.prototype.xml = function(){
- var method = this.method;
-
- var xml = "";
- xml += "<burlap:call>\n";
- xml += "<method>" + method+ "</method>\n";
-
- for (var i = 0; i < this.params.length; i++){
- var data = this.params[i];
- xml += BuffaloCall.getParamXML(BuffaloCall.dataTypeOf(data),data) + "\n";
- }
-
- xml += "</burlap:call>";
-
- return xml; // for now
- }
- /**
- * Judge the type of the paramter. should never be invoked by outside.
- *
- * @private
- * @type String
- * @returns the type of the object.
- */
- BuffaloCall.dataTypeOf = function (o){
- var type = typeof(o);
- type = type.toLowerCase();
- switch(type){
- case "number":
- if (Math.round(o) == o) type = "int";
- else type = "double";
- break;
- case "object":
- var con = o.constructor;
- if (con == Date) type = "date";
- else if (con == Array) type = "list";
- else type = "map";
- break;
- }
- return type;
- }
- /**
- * Process the common value to a xml.
- * @private
- * @returns the xml format of the data
- */
- BuffaloCall.doValueXML = function(type,data){
-
- var xml = "<" + type + ">" + xmlEncode(data) + "</" + type + ">";
- return xml;
- }
- function xmlEncode(data) {
- var str = "";
- if (typeof(data) == "string") {
- str = data;
- } else {
- return data;
- }
-
- str = str.replace("&","&");
- str = str.replace("<","<");
- str = str.replace(">",">");
-
- return str;
- }
- /**
- * Process the boolean paramter to xml.
- * @private
- */
- BuffaloCall.doBooleanXML = function(data){
- var value = (data==true)?1:0;
- var xml = "<boolean>" + value + "</boolean>";
- return xml;
- }
- /**
- * @private
- */
- BuffaloCall.doDateXML = function(data){
- var xml = "<date>";
- xml += dateToISO8609(data);
- xml += "</date>";
- return xml;
- }
- /**
- * @private
- */
- BuffaloCall.doArrayXML = function(data){
- var xml = "<list>\n";
- xml += "<type>" +""+ "</type>\n";
- xml += "<length>" +data.length+ "</length>\n";
- for (var i = 0; i < data.length; i++){
- xml += BuffaloCall.getParamXML(BuffaloCall.dataTypeOf(data[i]),data[i]) + "\n";
- }
- xml += "</list>\n";
- return xml;
- }
- /**
- * @private
- */
- BuffaloCall.doStructXML = function(data){
- var boClass = data[Buffalo.BOCLASS];
- // Default to hashMap
- var boType = "java.util.HashMap";
- if (typeof(boClass) != 'undefined' || boClass != null) {
- boType = boClass;
- }
- var xml = "<map>\n";
- xml += "<type>" +boType+ "</type>\n";
- for (var i in data){
- if (data[i] != boType) {
- xml += BuffaloCall.getParamXML(BuffaloCall.dataTypeOf(i),i)+"\n";
- xml += BuffaloCall.getParamXML(BuffaloCall.dataTypeOf(data[i]),data[i]) + "\n";
- }
- }
- xml += "</map>\n";
- return xml;
- }
- /**
- * @private
- */
- BuffaloCall.getParamXML = function(type,data){
- var xml;
- switch (type){
- case "date":
- xml = BuffaloCall.doDateXML(data);
- break;
- case "list":
- xml = BuffaloCall.doArrayXML(data);
- break;
- case "map":
- xml = BuffaloCall.doStructXML(data);
- break;
- case "boolean":
- xml = BuffaloCall.doBooleanXML(data);
- break;
- default:
- xml = BuffaloCall.doValueXML(type,data);
- break;
- }
- return xml;
- }
- /**
- * Convenient function to convert a Date object to a ISO8609 string format.
- * @private
- */
- function dateToISO8609(date){
- var year = new String(date.getYear());
- var month = leadingZero(new String(date.getMonth()+1));
- var day = leadingZero(new String(date.getDate()));
- var time = leadingZero(new String(date.getHours())) + leadingZero(new String(date.getMinutes())) + leadingZero(new String(date.getSeconds()));
- var converted = year+month+day+"T"+time+"Z";
- return converted;
- }
- /**
- * leading zero.
- * @private
- */
- function leadingZero(n){
- // pads a single number with a leading zero. Heh.
- if (n.length==1) n = "0" + n;
- return n;
- }
- /**
- * A burlap reply object hold the remote call's result, and convert the
- * result xml to a object. This is one of the core object in the buffalo
- * web remoting. You should know the methods and properties very clearly.
- *
- * @constructor
- * @param {String} sourceXML the reply sourceXML
- */
- function BuffaloReply(sourceXML) {
-
- // define the primary properties
- /**@private*/
- this._source = sourceXML;
- /**@private*/
- this._isFault = false;
- /**@private*/
- this._type = "null";
- /**@private*/
- this._objects = [];
- /**@private*/
- this._objectNodes = [];
-
- var xmldoc = XmlDocument.create();
- xmldoc.async=false;
- xmldoc.loadXML(sourceXML);
- var root = xmldoc.documentElement;
- /**@private*/
- this._root = root;
- var dataNode = root.firstChild;
- /**@private*/
- this._type = BuffaloReply._getType(dataNode);
-
- /**
- * get the reply data type. The reply type will be:
- * boolean, date, double, int, long, list, map, null, ref, string, xml or fault.
- * base64 is not supported. (do you want to use base64 at the client side?)
- *
- * @type String
- * @returns the reply's data type
- *
- */
- this.getType = function() {
- return this._type;
- }
-
- /**
- * Get the result object. the returned type is differed by the type,
- * such as: if type=="boolean", then getResult() is a boolean value.
- * the types are the same as burlap protocal.
- * here is the convert table:
- * <ul>
- * <li>boolean: a java script boolean value
- * <li>date: a javascript Date value
- * <li>double: a javascript float value, use parseFloat to convert
- * <li>int,long: a javascript int value, use parseInt to convert
- * <li>list: a javascript Array object
- * <li>map: a javascript Object
- * <li>null: javascript null
- * <li>ref: a reference(pointer) to the specified javascript obejct.
- * <li>string, xml: a javascript string
- * <li>fault: a Fault object(NOT IMPLEMENTATED YET)
- * </ul>
- * @type varient
- * @returns the result object
- */
- this.getResult = function() {
- return this.deserialize(dataNode);
- }
-
- /**
- * if this is a fault reply
- * @type boolean
- * @return if this is a fault reply
- */
- this.isFault = function() {
- return (this._type == "fault");
- }
-
- /**
- * indicate if this a null reply
- * @type boolean
- * @returns if this is a null reply
- */
- this.isNull = function() {
- return (this._type == "null");
- }
-
- /**
- * get the source xml, the source xml is capable with the burlap reply.
- * @type String
- * @returns the reply source xml
- */
- this.getSource = function() {
- return this._source;
- }
- }
- /**
- * Deserialize the xml data node to a javascript object
- *
- * @private
- * @param {DOMElement} dataNode the dataNode
- * @returns the value of the dataNode
- */
- BuffaloReply.prototype.deserialize = function(dataNode) {
- var ret;
-
- type = BuffaloReply._getType(dataNode);
- switch (type) {
- case "boolean":
- ret = this.doBoolean(dataNode);
- break;
- case "date":
- ret = this.doDate(dataNode);
- break;
- case "double":
- ret = this.doDouble(dataNode);
- break;
- case "int":
- case "long":
- ret = this.doInt(dataNode);
- break;
- case "list":
- ret = this.doList(dataNode);
- break;
- case "map":
- ret = this.doMap(dataNode);
- break;
- case "null":
- ret = this.doNull(dataNode);
- break;
- case "ref":
- ret = this.doRef(dataNode);
- break;
- case "string":
- ret = this.doString(dataNode);
- break;
- case "xml":
- ret = this.doXML(dataNode);
- break;
- case "fault":
- ret = this.doFault(dataNode);
- break;
- default:
- ;
- }
- return ret;
- }
- /**
- * get the data type of the dataNode
- * @private
- */
- BuffaloReply._getType = function(dataNode) {
- return dataNode.tagName;
- }
- /**
- * Get the dataNode value. for cross browser use.
- * @private
- */
- BuffaloReply.getNodeText = function(dataNode) {
-
- if (dataNode.childNodes.length == 0) {
- return null;
- } else
- return dataNode.firstChild.nodeValue;
- }
- /**
- * @private
- */
- BuffaloReply.prototype.doBoolean = function (dataNode) {
- var value = BuffaloReply.getNodeText(dataNode);
- return (value == "1");
- }
- /**
- * @private
- */
- BuffaloReply.prototype.doDate = function (dataNode) {
- var dateStr = BuffaloReply.getNodeText(dataNode);
- //parseInt will be strange if the first char is '0', so set the radix.
- var year = parseInt(dateStr.substring(0,4),"10");
- var month = parseInt(dateStr.substring(4,6),"10") - 1;
- var day = parseInt(dateStr.substring(6,8),"10");
- var hour = parseInt(dateStr.substring(9,11),"10");
- var minute = parseInt(dateStr.substring(11,13),"10");
- var second = parseInt(dateStr.substring(13,15),"10");
-
- var d = new Date(year, month, day, hour, minute, second);
- return d;
- }
- /**
- * @private
- */
- BuffaloReply.prototype.doDouble = function (dataNode) {
- var value = BuffaloReply.getNodeText(dataNode);
- return parseFloat(value);
- }
- /**
- * @private
- */
- BuffaloReply.prototype.doInt = function (dataNode) {
- var value = BuffaloReply.getNodeText(dataNode);
- return parseInt(value);
- }
- /**
- * @private
- */
- BuffaloReply.prototype.doList = function (dataNode) {
- var arr = new Array();
- this._objects[this._objects.length] = arr;
- var children = dataNode.childNodes;
- for (var i=2; i < children.length; i++) {
- arr[arr.length] = this.deserialize(children[i]);
- }
- return arr;
- }
- /**
- * @private
- */
- BuffaloReply.prototype.doMap = function (dataNode) {
-
- var obj = new Object();
- this._objects[this._objects.length] = obj;
- var attrs = dataNode.childNodes;
- for (var i = 1; i < attrs.length; i+=2) {
- if (attrs[i+1].hasChildNodes() ) {
- obj[BuffaloReply.getNodeText(attrs[i])] = this.deserialize(attrs[i+1]);
- } else {
- obj[BuffaloReply.getNodeText(attrs[i])] = attrs[i+1].text;
- }
- }
-
- return obj;
- }
- /**
- * @private
- */
- BuffaloReply.prototype.doNull = function (dataNode) {
- return null;
- }
- /**
- * @private
- */
- BuffaloReply.prototype.doRef = function (dataNode) {
- var value = BuffaloReply.getNodeText(dataNode);
- var idx = parseInt(value);
-
- return this._objects[idx];
- }
- /**
- * @private
- */
- BuffaloReply.prototype.doString = function (dataNode) {
- var value = BuffaloReply.getNodeText(dataNode);
- if (value == null) {
- return "";
- }
- return (value);
- }
- /**
- * @private
- */
- BuffaloReply.prototype.doXML = function (dataNode) {
- var value = BuffaloReply.getNodeText(dataNode);
- return unescape(value);
- }
- /**
- * TODO: add Fault object.
- * @private
- */
- BuffaloReply.prototype.doFault = function (dataNode) {
- /*
- var value = BuffaloReply.getNodeText(dataNode);*/
- //TODO: need more attention.
- //return BuffaloReply.getNodeText(dataNode);
- var code = BuffaloReply.getNodeText(dataNode.childNodes[1]);
- var msg = BuffaloReply.getNodeText(dataNode.childNodes[3]);
- var detail = this.deserialize(dataNode.childNodes[5]);
- return new BuffaloFault(code, msg, detail);
- //return this.doMap(dataNode);
- }
- function BuffaloFault(code, message, detail) {
- this.code = code;
- this.message = message;
- this.detail = detail;
- this.toString = function() {
- return "code:" + this.code + ", message" + this.message + ", detail: " + this.detail;
- }
- }
- /**
- * The main entry class. User use like this:
- *
- * <pre class="code">
- * var buffalo = new Buffalo("/buffalo/BUFFALO");
- * buffalo.remoteCall("simpleService.divide", [1.0,2.0], function(reply) {
- * alert(reply.getResult());
- * }
- * );
- * </pre>
- * @param {String} gateway the gateway url.
- * @constructor
- */
- function Buffalo(gateway, async) {
- /**
- * The gate way.
- * @type String
- * @private
- */
- this.gateway = gateway;
- this.async = (async != null) ? async : true;
- this.onWaiting = Buffalo.showLoading;
- this.onFault = new Function();
- this.onError = new Function();
- }
- /**
- * Set the gateway(end point url) of this buffalo object.
- * The url can be absolute or relative, such as http://host:port/BUFFALO or /BUFFALO
- *
- * @param {String} gateway the gateway (end point url)
- *
- */
- Buffalo.prototype.setGateway = function(gateway) {
- this.gateway = gateway;
- }
- /**
- * Get the gate way of this buffalo object.
- * @type String
- * @returns the gateway of this buffalo object.
- */
- Buffalo.prototype.getGateway = function() {
- return this.gateway;
- }
- Buffalo.BOCLASS = "_BUFFALO_OBJECT_CLASS_";
- /**
- * The loading pane.
- * @type HTMLDOMElement
- * @private
- */
- Buffalo.loadingPane = null;
- /**
- * The exception pane
- * @type HTMLDOMElement
- * @private
- */
- Buffalo.exceptionPane = null;
- /**
- * the error pane
- * @type HTMLDOMElement
- * @private
- */
- Buffalo.errorPane = null;
- /**
- * Display or hide the loading pane.
- * You don't need to call this function directly. Buffalo will take care of it when
- * invoking remote functions.
- *
- * @param {boolean} state the state of the loading pane, if true, show it, otherwise hide it.
- */
- Buffalo.showLoading = function(state) {
- Buffalo.loadingPane = document.getElementById("buffalo_loading");
- if (Buffalo.loadingPane == null) {
- var el = document.createElement('DIV');
- el.setAttribute("id","buffalo_loading");
- el.style.cssText="display:none;font-family:Verdana;font-size:11px;border:1px solid #00CC00;background-color:#A4FFA4;padding:1px;position:absolute; right:1px; top:1px; width:110px; height:14px; z-index:1";
- el.innerHTML="Buffalo loading... ";
- document.body.appendChild(el);
- Buffalo.loadingPane = el;
- }
- if (state) {
- Buffalo.loadingPane.style.display="block";
- Buffalo.loadingPane.style.top = document.body.scrollTop+1;
- } else {
- Buffalo.loadingPane.style.display="none";
- }
-
- }
- /**
- * Display the exception pane.
- * TODO: not implemented yet.
- * @param {String} ex the exception string
- */
- Buffalo.showException = function(ex) {
-
- }
- /**
- * Hide the exception pane.
- * TODO: not implemented yet.
- *
- */
- Buffalo.hideException = function() {
-
- }
- Buffalo.instance = null;
- /**
- * Invoke the remote Call, innerMethod.
- *
- * @private
- * @param <String> url The end point of the remote call
- * @param <BurlapCall> burlapCall The burlap call object
- * @param <Function> callback if the call returns, invoke the callback function
- */
- Buffalo.prototype._remoteCall = function(url, burlapCall, callback) {
- Buffalo.instance = this;
- var xmlhttp = XmlHttp.create();
- xmlhttp.open("POST", url, this.async);
- xmlhttp.send(burlapCall.xml());
- //xmlhttp.onWaiting = this.onWaiting;
- // 异步方式
- if (this.async) {
- Buffalo.showLoading(true);
- //xmlhttp.onWaiting(true);
- //Buffalo.instance.onWaiting(true);
- xmlhttp.onreadystatechange = function() {
- if (xmlhttp.readyState == 4) {
- if (xmlhttp.status == '200') {
- var data = xmlhttp.responseText;
- //alert(data);
- // 标准的burlap返回的不是正常xml, 为了兼容普通burlap调用,需要进行调整
- if (data.indexOf("xmlns:burlap") == -1) {
- data.replace("<burlap:reply>", "<burlap:reply xmlns:burlap=\"http://www.amowa.net/buffalo/\">")
- }
- var reply = new BuffaloReply(data);
- Buffalo.showLoading(false);
- //Buffalo.instance.onWaiting(false);
- //xmlhttp.onWaiting(false);
- callback(reply);
-
- } else {
- var win = window.open("about:blank");
- win.document.open();
- win.document.write(xmlhttp.responseText);
- win.document.close();
- }
- }
- }
- } else { // 同步方式
- if (xmlhttp.status == '200') {
- var data = xmlhttp.responseText;
- // 标准的burlap返回的不是正常xml, 为了兼容普通burlap调用,需要进行调整
- if (data.indexOf("xmlns:burlap") == -1) {
- data.replace("<burlap:reply>", "<burlap:reply xmlns:burlap=\"http://www.amowa.net/buffalo/\">")
- }
-
- var reply = new BuffaloReply(data);
-
- callback(reply);
-
- } else {
- var win = window.open("about:blank");
- win.document.open();
- win.document.write(xmlhttp.responseText);
- win.document.close();
- }
-
- }
-
- }
- /**
- * Call like this: remoteCall("someService.someMethod", arrayOfParams, callbackFunction)
- *
- * @param <String> service string the service name, like someService.someMethod
- * @param <Array> params array the service call parameters
- * @param <Function> callback the call back function
- */
- Buffalo.prototype.remoteCall = function(service, params, callback) {
- var idx = service.indexOf(".");
-
- var serviceId = service.substring(0,idx);
- var method = service.substring(idx+1,service.length);
- var newUrl = this.gateway+"?sid="+serviceId;
-
- var call = new BuffaloCall(method);
- for (var i = 0; i < params.length; i++) {
- call.addParameter(params[i]);
- }
- this._remoteCall(newUrl, call, callback);
- }
- /**
- * Help method to get the element reference for the elementId.
- * for cross browser use.
- * @param {String} elementId the element id
- * @type HTMLDOMElement
- * @returns the dom element of the specified element id.
- */
- Buffalo.getElementById = function(elementId) {
- return document.getElementById(elementId);
- }
|