diff options
Diffstat (limited to 'js/dojo/dojox/rpc/Service.js')
| -rw-r--r-- | js/dojo/dojox/rpc/Service.js | 323 |
1 files changed, 323 insertions, 0 deletions
diff --git a/js/dojo/dojox/rpc/Service.js b/js/dojo/dojox/rpc/Service.js new file mode 100644 index 0000000..15b7d60 --- /dev/null +++ b/js/dojo/dojox/rpc/Service.js @@ -0,0 +1,323 @@ +//>>built +define("dojox/rpc/Service", ["dojo", "dojox", "dojo/AdapterRegistry", "dojo/_base/url"], function(dojo, dojox) { + +dojo.declare("dojox.rpc.Service", null, { + constructor: function(smd, options){ + // summary: + // Take a string as a url to retrieve an smd or an object that is an smd or partial smd to use + // as a definition for the service + // + // smd: object + // Takes a number of properties as kwArgs for defining the service. It also + // accepts a string. When passed a string, it is treated as a url from + // which it should synchronously retrieve an smd file. Otherwise it is a kwArgs + // object. It accepts serviceUrl, to manually define a url for the rpc service + // allowing the rpc system to be used without an smd definition. strictArgChecks + // forces the system to verify that the # of arguments provided in a call + // matches those defined in the smd. smdString allows a developer to pass + // a jsonString directly, which will be converted into an object or alternatively + // smdObject is accepts an smdObject directly. + // + // description: + // dojox.rpc.Service must be loaded prior to any plugin services like dojox.rpc.Rest + // dojox.rpc.JsonRpc in order for them to register themselves, otherwise you get + // a "No match found" error. + var url; + var self = this; + function processSmd(smd){ + smd._baseUrl = new dojo._Url((dojo.isBrowser ? location.href : dojo.config.baseUrl) ,url || '.') + ''; + self._smd = smd; + + //generate the methods + for(var serviceName in self._smd.services){ + var pieces = serviceName.split("."); // handle "namespaced" services by breaking apart by . + var current = self; + for(var i=0; i< pieces.length-1; i++){ + // create or reuse each object as we go down the chain + current = current[pieces[i]] || (current[pieces[i]] = {}); + } + current[pieces[pieces.length-1]]= self._generateService(serviceName, self._smd.services[serviceName]); + } + } + if(smd){ + //ifthe arg is a string, we assume it is a url to retrieve an smd definition from + if( (dojo.isString(smd)) || (smd instanceof dojo._Url)){ + if(smd instanceof dojo._Url){ + url = smd + ""; + }else{ + url = smd; + } + + var text = dojo._getText(url); + if(!text){ + throw new Error("Unable to load SMD from " + smd); + }else{ + processSmd(dojo.fromJson(text)); + } + }else{ + processSmd(smd); + } + } + + this._options = (options ? options : {}); + this._requestId = 0; + }, + + _generateService: function(serviceName, method){ + if(this[method]){ + throw new Error("WARNING: "+ serviceName+ " already exists for service. Unable to generate function"); + } + method.name = serviceName; + var func = dojo.hitch(this, "_executeMethod",method); + var transport = dojox.rpc.transportRegistry.match(method.transport || this._smd.transport); + if(transport.getExecutor){ + func = transport.getExecutor(func,method,this); + } + var schema = method.returns || (method._schema = {}); // define the schema + var servicePath = '/' + serviceName +'/'; + // schemas are minimally used to track the id prefixes for the different services + schema._service = func; + func.servicePath = servicePath; + func._schema = schema; + func.id = dojox.rpc.Service._nextId++; + return func; + }, + _getRequest: function(method,args){ + var smd = this._smd; + var envDef = dojox.rpc.envelopeRegistry.match(method.envelope || smd.envelope || "NONE"); + var parameters = (method.parameters || []).concat(smd.parameters || []); + if(envDef.namedParams){ + // the serializer is expecting named params + if((args.length==1) && dojo.isObject(args[0])){ + // looks like we have what we want + args = args[0]; + }else{ + // they provided ordered, must convert + var data={}; + for(var i=0;i<method.parameters.length;i++){ + if(typeof args[i] != "undefined" || !method.parameters[i].optional){ + data[method.parameters[i].name]=args[i]; + } + } + args = data; + } + if(method.strictParameters||smd.strictParameters){ + //remove any properties that were not defined + for(i in args){ + var found=false; + for(var j=0; j<parameters.length;j++){ + if(parameters[i].name==i){ found=true; } + } + if(!found){ + delete args[i]; + } + } + + } + // setting default values + for(i=0; i< parameters.length; i++){ + var param = parameters[i]; + if(!param.optional && param.name && !args[param.name]){ + if(param["default"]){ + args[param.name] = param["default"]; + }else if(!(param.name in args)){ + throw new Error("Required parameter " + param.name + " was omitted"); + } + } + } + }else if(parameters && parameters[0] && parameters[0].name && (args.length==1) && dojo.isObject(args[0])){ + // looks like named params, we will convert + if(envDef.namedParams === false){ + // the serializer is expecting ordered params, must be ordered + args = dojox.rpc.toOrdered(parameters, args); + }else{ + // named is ok + args = args[0]; + } + } + + if(dojo.isObject(this._options)){ + args = dojo.mixin(args, this._options); + } + + var schema = method._schema || method.returns; // serialize with the right schema for the context; + var request = envDef.serialize.apply(this, [smd, method, args]); + request._envDef = envDef;// save this for executeMethod + var contentType = (method.contentType || smd.contentType || request.contentType); + + // this allows to mandate synchronous behavior from elsewhere when necessary, this may need to be changed to be one-shot in FF3 new sync handling model + return dojo.mixin(request, { + sync: dojox.rpc._sync, + contentType: contentType, + headers: method.headers || smd.headers || request.headers || {}, + target: request.target || dojox.rpc.getTarget(smd, method), + transport: method.transport || smd.transport || request.transport, + envelope: method.envelope || smd.envelope || request.envelope, + timeout: method.timeout || smd.timeout, + callbackParamName: method.callbackParamName || smd.callbackParamName, + rpcObjectParamName: method.rpcObjectParamName || smd.rpcObjectParamName, + schema: schema, + handleAs: request.handleAs || "auto", + preventCache: method.preventCache || smd.preventCache, + frameDoc: this._options.frameDoc || undefined + }); + }, + _executeMethod: function(method){ + var args = []; + var i; + for(i=1; i< arguments.length; i++){ + args.push(arguments[i]); + } + var request = this._getRequest(method,args); + var deferred = dojox.rpc.transportRegistry.match(request.transport).fire(request); + + deferred.addBoth(function(results){ + return request._envDef.deserialize.call(this,results); + }); + return deferred; + } +}); + +dojox.rpc.getTarget = function(smd, method){ + var dest=smd._baseUrl; + if(smd.target){ + dest = new dojo._Url(dest,smd.target) + ''; + } + if(method.target){ + dest = new dojo._Url(dest,method.target) + ''; + } + return dest; +}; + +dojox.rpc.toOrdered=function(parameters, args){ + if(dojo.isArray(args)){ return args; } + var data=[]; + for(var i=0;i<parameters.length;i++){ + data.push(args[parameters[i].name]); + } + return data; +}; + +dojox.rpc.transportRegistry = new dojo.AdapterRegistry(true); +dojox.rpc.envelopeRegistry = new dojo.AdapterRegistry(true); +//Built In Envelopes + +dojox.rpc.envelopeRegistry.register( + "URL", + function(str){ return str == "URL"; }, + { + serialize:function(smd, method, data ){ + var d = dojo.objectToQuery(data); + return { + data: d, + transport:"POST" + }; + }, + deserialize:function(results){ + return results; + }, + namedParams: true + } +); + +dojox.rpc.envelopeRegistry.register( + "JSON", + function(str){ return str == "JSON"; }, + { + serialize: function(smd, method, data){ + var d = dojo.toJson(data); + + return { + data: d, + handleAs: 'json', + contentType : 'application/json' + }; + }, + deserialize: function(results){ + return results; + } + } +); +dojox.rpc.envelopeRegistry.register( + "PATH", + function(str){ return str == "PATH"; }, + { + serialize:function(smd, method, data){ + var i; + var target = dojox.rpc.getTarget(smd, method); + if(dojo.isArray(data)){ + for(i = 0; i < data.length;i++){ + target += '/' + data[i]; + } + }else{ + for(i in data){ + target += '/' + i + '/' + data[i]; + } + } + + return { + data:'', + target: target + }; + }, + deserialize:function(results){ + return results; + } + } +); + + + +//post is registered first because it is the default; +dojox.rpc.transportRegistry.register( + "POST", + function(str){ return str == "POST"; }, + { + fire:function(r){ + r.url = r.target; + r.postData = r.data; + return dojo.rawXhrPost(r); + } + } +); + +dojox.rpc.transportRegistry.register( + "GET", + function(str){ return str == "GET"; }, + { + fire: function(r){ + r.url= r.target + (r.data ? '?' + ((r.rpcObjectParamName) ? r.rpcObjectParamName + '=' : '') + r.data : ''); + return dojo.xhrGet(r); + } + } +); + + +//only works ifyou include dojo.io.script +dojox.rpc.transportRegistry.register( + "JSONP", + function(str){ return str == "JSONP"; }, + { + fire: function(r){ + r.url = r.target + ((r.target.indexOf("?") == -1) ? '?' : '&') + ((r.rpcObjectParamName) ? r.rpcObjectParamName + '=' : '') + r.data; + r.callbackParamName = r.callbackParamName || "callback"; + return dojo.io.script.get(r); + } + } +); +dojox.rpc.Service._nextId = 1; + +dojo._contentHandlers.auto = function(xhr){ + // automatically choose the right handler based on the returned content type + var handlers = dojo._contentHandlers; + var retContentType = xhr.getResponseHeader("Content-Type"); + var results = !retContentType ? handlers.text(xhr) : + retContentType.match(/\/.*json/) ? handlers.json(xhr) : + retContentType.match(/\/javascript/) ? handlers.javascript(xhr) : + retContentType.match(/\/xml/) ? handlers.xml(xhr) : handlers.text(xhr); + return results; +}; + +return dojox.rpc.Service; + +}); |
