| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| * The JSON-RPC client code is based on Jan-Klaas' JavaScript |
| * o lait library (jsolait). |
| * |
| * $Id: jsonrpc.js,v 1.36.2.3 2006/03/08 15:09:37 mclark Exp $ |
| * |
| * Copyright (c) 2003-2004 Jan-Klaas Kollhof |
| * Copyright (c) 2005 Michael Clark, Metaparadigm Pte Ltd |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"). |
| */ |
| |
| /** |
| * Client component wiring API, supporting JSON and ATOM bindings. |
| */ |
| |
| var JSONClient = {}; |
| |
| /** |
| * Escape a character. |
| */ |
| JSONClient.escapeJSONChar = function(c) { |
| if(c == "\"" || c == "\\") return "\\" + c; |
| if(c == "\b") return "\\b"; |
| if(c == "\f") return "\\f"; |
| if(c == "\n") return "\\n"; |
| if(c == "\r") return "\\r"; |
| if(c == "\t") return "\\t"; |
| var hex = c.charCodeAt(0).toString(16); |
| if(hex.length == 1) return "\\u000" + hex; |
| if(hex.length == 2) return "\\u00" + hex; |
| if(hex.length == 3) return "\\u0" + hex; |
| return "\\u" + hex; |
| }; |
| |
| /** |
| * Encode a string into JSON format. |
| */ |
| JSONClient.escapeJSONString = function(s) { |
| // The following should suffice but Safari's regex is broken (doesn't support callback substitutions) |
| // return "\"" + s.replace(/([^\u0020-\u007f]|[\\\"])/g, JSONClient.escapeJSONChar) + "\""; |
| |
| // Rather inefficient way to do it |
| var parts = s.split(""); |
| for(var i = 0; i < parts.length; i++) { |
| var c = parts[i]; |
| if(c == '"' || c == '\\' || c.charCodeAt(0) < 32 || c.charCodeAt(0) >= 128) |
| parts[i] = JSONClient.escapeJSONChar(parts[i]); |
| } |
| return "\"" + parts.join("") + "\""; |
| }; |
| |
| /** |
| * Marshall objects to JSON format. |
| */ |
| JSONClient.toJSON = function(o) { |
| if(o == null) |
| return "null"; |
| if(o.constructor == String) |
| return JSONClient.escapeJSONString(o); |
| if(o.constructor == Number) |
| return o.toString(); |
| if(o.constructor == Boolean) |
| return o.toString(); |
| if(o.constructor == Date) |
| return '{javaClass: "java.util.Date", time: ' + o.valueOf() +'}'; |
| if(o.constructor == Array) { |
| var v = []; |
| for(var i = 0; i < o.length; i++) |
| v.push(JSONClient.toJSON(o[i])); |
| return "[" + v.join(", ") + "]"; |
| } |
| var v = []; |
| for(attr in o) { |
| if(o[attr] == null) |
| v.push("\"" + attr + "\": null"); |
| else if(typeof o[attr] == "function") |
| ; // Skip |
| else |
| v.push(JSONClient.escapeJSONString(attr) + ": " + JSONClient.toJSON(o[attr])); |
| } |
| return "{" + v.join(", ") + "}"; |
| }; |
| |
| /** |
| * Construct an HTTPBindingClient. |
| */ |
| function HTTPBindingClient(name, uri, domain) { |
| this.name = name; |
| this.domain = domain; |
| this.uri = uri; |
| this.apply = this.createApplyMethod(); |
| } |
| |
| /** |
| * HTTPBindingClient implementation |
| */ |
| |
| /** |
| * Generate client proxy apply method. |
| */ |
| HTTPBindingClient.prototype.createApplyMethod = function() { |
| var fn = function() { |
| var methodName = arguments[0]; |
| var args = []; |
| for(var i = 1; i < arguments.length; i++) |
| args.push(arguments[i]); |
| |
| var cb = null; |
| if(typeof args[args.length - 1] == "function") |
| cb = args.pop(); |
| |
| var req = HTTPBindingClient.makeJSONRequest(methodName, args, cb); |
| return fn.client.jsonApply(req); |
| }; |
| fn.client = this; |
| return fn; |
| }; |
| |
| /** |
| * JSON-RPC request counter. |
| */ |
| HTTPBindingClient.jsonrpcID = 1; |
| |
| /** |
| * Make a JSON-RPC request. |
| */ |
| HTTPBindingClient.makeJSONRequest = function(methodName, args, cb) { |
| var req = {}; |
| req.id = HTTPBindingClient.jsonrpcID++; |
| if(cb) |
| req.cb = cb; |
| var obj = {}; |
| obj.id = req.id; |
| obj.method = methodName; |
| obj.params = args; |
| req.data = JSONClient.toJSON(obj); |
| return req; |
| }; |
| |
| /** |
| * Return the JSON result from an XMLHttpRequest. |
| */ |
| HTTPBindingClient.jsonResult = function(http) { |
| // Get the charset |
| function httpCharset(http) { |
| try { |
| var contentType = http.getResponseHeader("Content-Type"); |
| var parts = contentType.split(/\s*;\s*/); |
| for(var i = 0; i < parts.length; i++) { |
| if(parts[i].substring(0, 8) == "charset=") |
| return parts[i].substring(8, parts[i].length); |
| } |
| } catch (e) {} |
| return "UTF-8"; |
| } |
| if(!HTTPBindingClient.charset) |
| HTTPBindingClient.charset = httpCharset(http); |
| |
| // Unmarshall the JSON response |
| var obj; |
| eval("obj = " + http.responseText); |
| if(obj.error) |
| throw new HTTPBindingClient.Exception(obj.error.code, obj.error.msg); |
| var res = obj.result; |
| return res; |
| }; |
| |
| /** |
| * Schedule async requests, limiting the number of concurrent running requests. |
| */ |
| HTTPBindingClient.queuedRequests = new Array(); |
| HTTPBindingClient.runningRequests = new Array(); |
| HTTPBindingClient.concurrentRequests = 2; |
| |
| HTTPBindingClient.scheduleAsyncRequest = function(f, cancelable) { |
| //debug('schedule async request, running ' + HTTPBindingClient.runningRequests.length + ' queued ' + HTTPBindingClient.queuedRequests.length); |
| |
| // Queue the request function |
| var req = new Object(); |
| req.f = f; |
| req.cancelable = cancelable; |
| req.canceled = false; |
| HTTPBindingClient.queuedRequests.push(req); |
| |
| // Execute any requests in the queue |
| setTimeout(function() { |
| HTTPBindingClient.runAsyncRequests(true); |
| }, 0); |
| return true; |
| }; |
| |
| HTTPBindingClient.forgetRequest = function(req) { |
| req.http = null; |
| |
| // Remove a request from the list of running requests |
| for (i in HTTPBindingClient.runningRequests) { |
| if (HTTPBindingClient.runningRequests[i] == req) { |
| HTTPBindingClient.runningRequests.splice(i, 1); |
| //debug('forget async request, running ' + HTTPBindingClient.runningRequests.length + ' queued ' + HTTPBindingClient.queuedRequests.length); |
| return true; |
| } |
| } |
| return false; |
| }; |
| |
| HTTPBindingClient.cancelRequests = function() { |
| //debug('cancel async requests, running ' + HTTPBindingClient.runningRequests.length + ' queued ' + HTTPBindingClient.queuedRequests.length); |
| |
| // Cancel any cancelable in flight HTTP requests |
| for (i in HTTPBindingClient.queuedRequests) { |
| var req = HTTPBindingClient.queuedRequests[i]; |
| if (req.cancelable) |
| req.canceled = true; |
| } |
| for (i in HTTPBindingClient.runningRequests) { |
| var req = HTTPBindingClient.runningRequests[i]; |
| if (req.cancelable) { |
| req.canceled = true; |
| if (req.http) { |
| req.http.abort(); |
| req.http = null; |
| //debug('abort async request, running ' + HTTPBindingClient.runningRequests.length + ' queued ' + HTTPBindingClient.queuedRequests.length); |
| } |
| } |
| } |
| |
| // Flush the queue |
| setTimeout(function() { |
| HTTPBindingClient.runAsyncRequests(true); |
| }, 0); |
| } |
| |
| HTTPBindingClient.runAsyncRequests = function(fromui) { |
| // Stop now if we already have enough requests running or there's no request in the queue |
| if(HTTPBindingClient.runningRequests.length >= HTTPBindingClient.concurrentRequests || HTTPBindingClient.queuedRequests.length == 0) |
| return true; |
| |
| // Run the first request in the queue |
| var req = HTTPBindingClient.queuedRequests.shift(); |
| if (!req.canceled) { |
| HTTPBindingClient.runningRequests.push(req); |
| //debug('run async request, running ' + HTTPBindingClient.runningRequests.length + ' queued ' + HTTPBindingClient.queuedRequests.length); |
| var runAsyncRequest = function() { |
| if (req.canceled) { |
| HTTPBindingClient.forgetRequest(req); |
| //debug('canceled timed async request, running ' + HTTPBindingClient.runningRequests.length + ' queued ' + HTTPBindingClient.queuedRequests.length); |
| return false; |
| } |
| try { |
| req.http = new XMLHttpRequest(); |
| return req.f(req.http, function asyncRequestDone() { |
| // Execute any requests left in the queue |
| HTTPBindingClient.forgetRequest(req); |
| //debug('done async request, running ' + HTTPBindingClient.runningRequests.length + ' queued ' + HTTPBindingClient.queuedRequests.length); |
| HTTPBindingClient.runAsyncRequests(false); |
| return true; |
| }); |
| } catch(e) { |
| // Execute any requests left in the queue |
| HTTPBindingClient.forgetRequest(req); |
| //debug('err async request, running ' + HTTPBindingClient.runningRequests.length + ' queued ' + HTTPBindingClient.queuedRequests.length); |
| HTTPBindingClient.runAsyncRequests(false); |
| } |
| return false; |
| }; |
| if (false) |
| setTimeout(runAsyncRequest, 0); |
| else |
| runAsyncRequest(); |
| } else { |
| //debug('canceled queued async request, running ' + HTTPBindingClient.runningRequests.length + ' queued ' + HTTPBindingClient.queuedRequests.length); |
| } |
| |
| // Execute any requests left in the queue |
| HTTPBindingClient.runAsyncRequests(fromui); |
| }; |
| |
| /** |
| * Get a cache item from local storage. |
| */ |
| HTTPBindingClient.getCacheItem = function(k) { |
| var ls = lstorage || localStorage; |
| return ls.getItem('cache.d.' + k); |
| }; |
| |
| /** |
| * Set a cache item in local storage. |
| */ |
| HTTPBindingClient.setCacheItem = function(k, v) { |
| HTTPBindingClient.collectCacheItems(); |
| var ls = lstorage || localStorage; |
| try { |
| var s = ls.getItem('cache.size'); |
| var size = parseInt(s); |
| var ov = ls.getItem('cache.d.' + k); |
| var nsize = size - (ov != null? ov.length : 0) + (v != null? v.length : 0); |
| if (nsize != size) |
| ls.setItem('cache.size', nsize.toString()); |
| } catch(e) {} |
| return ls.setItem('cache.d.' + k, v); |
| }; |
| |
| /** |
| * Remove a cache item from local storage. |
| */ |
| HTTPBindingClient.removeCacheItem = function(k) { |
| var ls = lstorage || localStorage; |
| try { |
| var s = ls.getItem('cache.size'); |
| var size = parseInt(s); |
| var ov = ls.getItem('cache.d' + k); |
| if (ov != null) { |
| var nsize = size - ov.length; |
| ls.setItem('cache.size', nsize.toString()); |
| } |
| } catch(e) {} |
| return ls.removeItem('cache.d.' + k); |
| }; |
| |
| /** |
| * Keep local storage cache entries under 2MB. |
| */ |
| HTTPBindingClient.maxCacheSize = /* 20000; */ 2097152; |
| HTTPBindingClient.collectCacheSize = /* 10000; */ 1048576; |
| HTTPBindingClient.collectCacheItems = function() { |
| var ls = window.lstorage || localStorage; |
| var nkeys = window.lstorage? function() { return ls.length(); } : function() { return ls.length; }; |
| try { |
| // Get the current cache size |
| var size = 0; |
| var s = ls.getItem('cache.size'); |
| if(s == null) { |
| // Calculate and store initial cache size |
| //debug('calculating cache size'); |
| var n = nkeys(); |
| for(var i = 0; i < n; i++) { |
| var k = ls.key(i); |
| if(k == null || k.substr(0, 8) != 'cache.d.') |
| continue; |
| var v = ls.getItem(k); |
| if(v == null) |
| continue; |
| size += v.length; |
| } |
| ls.setItem('cache.size', size.toString()); |
| } else |
| size = parseInt(s); |
| |
| // Nothing to do if it's below the max size |
| //debug('cache.size', size); |
| if (size <= HTTPBindingClient.maxCacheSize) |
| return false; |
| |
| // Collect random cache entries until we reach our min size |
| //debug('collecting cache items'); |
| var keys = new Array(); |
| var n = nkeys(); |
| for(var i = 0; i < n; i++) { |
| var k = ls.key(i); |
| if(k == null || k.substr(0, 8) != 'cache.d.') |
| continue; |
| keys.push(k); |
| } |
| while (keys.length != 0 && size >= HTTPBindingClient.collectCacheSize) { |
| var r = Math.floor(keys.length * Math.random()); |
| if (r == keys.length) |
| continue; |
| var k = keys[r]; |
| var v = ls.getItem(k); |
| //debug('collect cache item', k); |
| ls.removeItem(k); |
| keys.splice(r, 1); |
| if (v != null) |
| size = size - v.length; |
| } |
| |
| // Store the new cache size |
| //debug('updated cache.size', size); |
| ls.setItem('cache.size', size.toString()); |
| return true; |
| } catch(e) {} |
| return false; |
| }; |
| |
| /** |
| * Apply a function remotely using JSON-RPC. |
| */ |
| HTTPBindingClient.prototype.jsonApply = function(req) { |
| var hascb = req.cb? true : false; |
| |
| // Call asynchronously with a callback |
| if(hascb) { |
| var u = this.uri; |
| return HTTPBindingClient.scheduleAsyncRequest(function jsonApplyRequest(http, done) { |
| http.open("POST", u, true); |
| http.setRequestHeader("Accept", "*/*"); |
| http.setRequestHeader("Content-Type", "application/json-rpc"); |
| http.onreadystatechange = function() { |
| if(http.readyState == 4) { |
| // Pass the result or exception |
| if(http.status == 200) { |
| var res = null; |
| try { |
| res = HTTPBindingClient.jsonResult(http); |
| try { |
| req.cb(res); |
| } catch(cbe) {} |
| } catch(e) { |
| try { |
| req.cb(null, e); |
| } catch(cbe) {} |
| } |
| } else { |
| try { |
| req.cb(null, HTTPBindingClient.Exception(http.status, http.statusText)); |
| } catch(cbe) {} |
| } |
| return done(); |
| } |
| }; |
| |
| // Send the request |
| http.send(req.data); |
| return req.id; |
| }, false); |
| } |
| |
| // Call synchronously and return the result or exception |
| var http = new XMLHttpRequest(); |
| http.open("POST", this.uri, false); |
| http.setRequestHeader("Accept", "*/*"); |
| http.setRequestHeader("Content-Type", "application/json-rpc"); |
| http.send(req.data); |
| if(http.status == 200) |
| return HTTPBindingClient.jsonResult(http); |
| throw new HTTPBindingClient.Exception(http.status, http.statusText); |
| }; |
| |
| |
| /** |
| * REST GET method. |
| */ |
| HTTPBindingClient.prototype.get = function(id, cb, mode) { |
| var u = id? (this.uri? this.uri + '/' + id : id) : this.uri; |
| var hascb = cb? true : false; |
| |
| // Get from local storage first |
| var item = null; |
| if(mode != 'remote') { |
| item = HTTPBindingClient.getCacheItem(u); |
| if(item != null && item != '') { |
| if(!hascb) |
| return item; |
| |
| // Pass local result to callback |
| setTimeout(function() { |
| cb(item); |
| }, 0); |
| } |
| } |
| |
| // Call asynchronously with a callback |
| if(hascb) { |
| return HTTPBindingClient.scheduleAsyncRequest(function getRequest(http, done) { |
| http.open("GET", u, true); |
| http.setRequestHeader("Accept", "*/*"); |
| http.onreadystatechange = function() { |
| //debug('readystate', http.readyState, 'status', http.status, 'headers', http.getAllResponseHeaders()); |
| if(http.readyState == 4) { |
| // Pass result if different from local result |
| if(http.status == 200) { |
| var xl = http.getResponseHeader("X-Login"); |
| var ct = http.getResponseHeader("Content-Type"); |
| if(xl != null && xl != '' && ct != null && ct.indexOf('text/html') == 0) { |
| // Detect redirect to a login page |
| try { |
| var le = new HTTPBindingClient.Exception(403, 'X-Login'); |
| if(window.onloginredirect) |
| window.onloginredirect(le); |
| cb(null, le); |
| return done(); |
| } catch(cbe) {} |
| |
| } |
| if(http.responseText == '' || ct == null || ct == '') { |
| // Report empty response |
| try { |
| cb(null, new HTTPBindingClient.Exception(403, 'No-Content')); |
| return done(); |
| } catch(cbe) {} |
| |
| } else { |
| if(item == null || http.responseText != item) { |
| // Store retrieved entry in local storage |
| if(http.responseText != null) |
| HTTPBindingClient.setCacheItem(u, http.responseText); |
| try { |
| cb(http.responseText); |
| return done(); |
| } catch(cbe) {} |
| } |
| } |
| } |
| else { |
| // Pass exception if we didn't have a local result |
| if(item == null) { |
| try { |
| cb(null, new HTTPBindingClient.Exception(http.status, http.statusText)); |
| return done(); |
| } catch(cbe) {} |
| } |
| } |
| return done(); |
| } |
| }; |
| |
| // Send the request |
| http.send(null); |
| return true; |
| }, true); |
| } |
| |
| // Call synchronously and return the result or exception |
| var http = new XMLHttpRequest(); |
| http.open("GET", u, false); |
| http.setRequestHeader("Accept", "*/*"); |
| http.send(null); |
| if(http.status == 200) { |
| var xl = http.getResponseHeader("X-Login"); |
| var ct = http.getResponseHeader("Content-Type"); |
| if(xl != null && xl != '' && ct != null && ct.indexOf('text/html') == 0) { |
| // Detect redirect to a login page |
| var le = new HTTPBindingClient.Exception(403, 'X-Login'); |
| if(window.onloginredirect) |
| window.onloginredirect(le); |
| throw le; |
| |
| } |
| var ct = http.getResponseHeader("Content-Type"); |
| if(http.responseText == '' || ct == null || ct == '') { |
| // Report empty response |
| throw new HTTPBindingClient.Exception(403, 'No-Content'); |
| } |
| return http.responseText; |
| } |
| throw new HTTPBindingClient.Exception(http.status, http.statusText); |
| }; |
| |
| /** |
| * REST POST method. |
| */ |
| HTTPBindingClient.prototype.post = function (entry, cb) { |
| var hascb = cb? true : false; |
| |
| // Call asynchronously with a callback |
| if(hascb) { |
| var u = this.uri; |
| return HTTPBindingClient.scheduleAsyncRequest(function postRequest(http, done) { |
| http.open("POST", u, true); |
| http.setRequestHeader("Accept", "*/*"); |
| http.setRequestHeader("Content-Type", "application/atom+xml"); |
| http.onreadystatechange = function() { |
| if(http.readyState == 4) { |
| if(http.status == 201) { |
| // Successful result |
| try { |
| cb(http.responseText); |
| } catch(cbe) {} |
| } |
| else { |
| // Report status code as an exception |
| try { |
| cb(null, new HTTPBindingClient.Exception(http.status, http.statusText)); |
| } catch(cbe) {} |
| } |
| return done(); |
| } |
| }; |
| // Send the request |
| http.send(entry); |
| return true; |
| }, false); |
| } |
| |
| // Call synchronously |
| var http = new XMLHttpRequest(); |
| var hascb = cb? true : false; |
| http.open("POST", this.uri, false); |
| http.setRequestHeader("Accept", "*/*"); |
| http.setRequestHeader("Content-Type", "application/atom+xml"); |
| http.send(entry); |
| if(http.status == 201) |
| return http.responseText; |
| |
| // Return status code as an exception |
| throw new HTTPBindingClient.Exception(http.status, http.statusText); |
| }; |
| |
| /** |
| * REST PUT method. |
| */ |
| HTTPBindingClient.prototype.put = function(id, entry, cb, mode) { |
| var u = id? (this.uri? this.uri + '/' + id : id) : this.uri; |
| var hascb = cb? true : false; |
| |
| // Update local storage |
| var oentry = null; |
| if(mode != 'remote') { |
| oentry = HTTPBindingClient.getCacheItem(u); |
| HTTPBindingClient.setCacheItem(u, entry); |
| } |
| |
| // Call asynchronously with a callback |
| if(hascb) { |
| return HTTPBindingClient.scheduleAsyncRequest(function putRequest(http, done) { |
| http.open("PUT", u, true); |
| http.setRequestHeader("Accept", "*/*"); |
| http.setRequestHeader("Content-Type", "application/atom+xml"); |
| http.onreadystatechange = function() { |
| if(http.readyState == 4) { |
| if(http.status == 200) { |
| // Successful result |
| try { |
| cb(); |
| } catch(cbe) {} |
| } else { |
| if(http.status == 404) { |
| // Undo local storage update |
| if(mode != 'remote') { |
| try { |
| if(oentry != null) |
| HTTPBindingClient.setCacheItem(u, oentry); |
| else |
| HTTPBindingClient.removeCacheItem(u); |
| } catch(e) {} |
| } |
| } |
| |
| // Report status code as an exception |
| try { |
| cb(new HTTPBindingClient.Exception(http.status, http.statusText)); |
| } catch(cbe) {} |
| } |
| return done(); |
| } |
| }; |
| |
| // Send the request |
| http.send(entry); |
| return true; |
| }, false); |
| } |
| |
| // Call synchronously |
| var http = new XMLHttpRequest(); |
| http.open("PUT", u, false); |
| http.setRequestHeader("Accept", "*/*"); |
| http.setRequestHeader("Content-Type", "application/atom+xml"); |
| http.send(entry); |
| if(http.status == 200) |
| return true; |
| if(http.status == 404) { |
| // Undo local storage update |
| if(mode != 'remote') { |
| try { |
| if(oentry != null) |
| HTTPBindingClient.setCacheItem(u, oentry); |
| else |
| HTTPBindingClient.removeCacheItem(u); |
| } catch(e) {} |
| } |
| } |
| |
| // Return status code as an exception |
| throw new HTTPBindingClient.Exception(http.status, http.statusText); |
| }; |
| |
| /** |
| * REST DELETE method. |
| */ |
| HTTPBindingClient.prototype.del = function(id, cb, mode) { |
| var u = id? (this.uri? this.uri + '/' + id : id) : this.uri; |
| var hascb = cb? true : false; |
| |
| // Update local storage |
| var ls = window.lstorage || localStorage; |
| if(mode != 'remote') |
| HTTPBindingClient.removeCacheItem(u); |
| |
| // Call asynchronously with a callback |
| if(hascb) { |
| return HTTPBindingClient.scheduleAsyncRequest(function delRequest(http, done) { |
| http.open("DELETE", u, true); |
| http.setRequestHeader("Accept", "*/*"); |
| http.onreadystatechange = function() { |
| if(http.readyState == 4) { |
| if(http.status == 200) { |
| // Successful result |
| try { |
| cb(); |
| } catch(cbe) {} |
| } |
| else { |
| // Report status code as an exception |
| try { |
| cb(new HTTPBindingClient.Exception(http.status, http.statusText)); |
| } catch(cbe) {} |
| } |
| return done(); |
| } |
| }; |
| |
| // Send the request |
| http.send(null); |
| return true; |
| }, false); |
| } |
| |
| // Call synchronously |
| var http = new XMLHttpRequest(); |
| http.open("DELETE", u, false); |
| http.setRequestHeader("Accept", "*/*"); |
| http.send(null); |
| if(http.status == 200) |
| return true; |
| |
| // Report status code as an exception |
| throw new HTTPBindingClient.Exception(http.status, http.statusText); |
| }; |
| |
| /** |
| * HTTPBindingClient exceptions. |
| */ |
| HTTPBindingClient.Exception = function(code, message) { |
| this.name = "HTTPBindingClientException"; |
| this.code = code; |
| this.message = message; |
| }; |
| |
| HTTPBindingClient.Exception.prototype = new Error(); |
| |
| HTTPBindingClient.Exception.prototype.toString = function() { |
| return this.name + ": " + this.message; |
| }; |
| |
| /** |
| * Public API. |
| */ |
| |
| var sca = {}; |
| |
| /** |
| * Return an HTTP client proxy. |
| */ |
| sca.httpclient = function(name, uri, domain) { |
| return new HTTPBindingClient(name, uri, domain); |
| }; |
| |
| /** |
| * Return a component proxy. |
| */ |
| sca.component = function(name, domain) { |
| if(!domain) |
| return new HTTPBindingClient(name, '/c/' + name, domain); |
| return new HTTPBindingClient(name, '/' + domain + '/c/' + name, domain); |
| }; |
| |
| /** |
| * Return a reference proxy. |
| */ |
| sca.reference = function(comp, rname) { |
| if(!comp.domain) |
| return new HTTPBindingClient(comp.name + '/' + rname, '/r/' + comp.name + '/' + rname, comp.domain); |
| return new HTTPBindingClient(comp.name + '/' + rname, '/' + comp.domain + '/r/' + comp.name + '/' + rname, comp.domain); |
| }; |
| |
| /** |
| * Add proxy functions to a reference proxy. |
| */ |
| sca.defun = function(ref) { |
| function defapply(name) { |
| return function() { |
| var args = new Array(); |
| args[0] = name; |
| for(i = 0, n = arguments.length; i < n; i++) |
| args[i + 1] = arguments[i]; |
| return this.apply.apply(this, args); |
| }; |
| } |
| |
| for(f = 1; f < arguments.length; f++) { |
| var fn = arguments[f]; |
| ref[fn]= defapply(fn); |
| } |
| return ref; |
| }; |
| |