source: Dev/trunk/src/client/dojox/rpc/Service.js @ 529

Last change on this file since 529 was 483, checked in by hendrikvanantwerpen, 11 years ago

Added Dojo 1.9.3 release.

File size: 9.6 KB
Line 
1define("dojox/rpc/Service", ["dojo", "dojox", "dojo/AdapterRegistry", "dojo/_base/url"], function(dojo, dojox) {
2
3dojo.declare("dojox.rpc.Service", null, {
4        constructor: function(smd, options){
5                // summary:
6                //              Take a string as a url to retrieve an smd or an object that is an smd or partial smd to use
7                //              as a definition for the service
8                // description:
9                //              dojox.rpc.Service must be loaded prior to any plugin services like dojox.rpc.Rest
10                //              dojox.rpc.JsonRpc in order for them to register themselves, otherwise you get
11                //              a "No match found" error.
12                // smd: object
13                //              Takes a number of properties as kwArgs for defining the service.  It also
14                //              accepts a string.  When passed a string, it is treated as a url from
15                //              which it should synchronously retrieve an smd file.  Otherwise it is a kwArgs
16                //              object.  It accepts serviceUrl, to manually define a url for the rpc service
17                //              allowing the rpc system to be used without an smd definition. strictArgChecks
18                //              forces the system to verify that the # of arguments provided in a call
19                //              matches those defined in the smd.  smdString allows a developer to pass
20                //              a jsonString directly, which will be converted into an object or alternatively
21                //              smdObject is accepts an smdObject directly.
22
23                var url;
24                var self = this;
25                function processSmd(smd){
26                        smd._baseUrl = new dojo._Url((dojo.isBrowser ? location.href : dojo.config.baseUrl) ,url || '.') + '';
27                        self._smd = smd;
28
29                        //generate the methods
30                        for(var serviceName in self._smd.services){
31                                var pieces = serviceName.split("."); // handle "namespaced" services by breaking apart by .
32                                var current = self;
33                                for(var i=0; i< pieces.length-1; i++){
34                                        // create or reuse each object as we go down the chain
35                                        current = current[pieces[i]] || (current[pieces[i]] = {});
36                                }
37                                current[pieces[pieces.length-1]]=       self._generateService(serviceName, self._smd.services[serviceName]);
38                        }
39                }
40                if(smd){
41                        //ifthe arg is a string, we assume it is a url to retrieve an smd definition from
42                        if( (dojo.isString(smd)) || (smd instanceof dojo._Url)){
43                                if(smd instanceof dojo._Url){
44                                        url = smd + "";
45                                }else{
46                                        url = smd;
47                                }
48
49                                var text = dojo._getText(url);
50                                if(!text){
51                                        throw new Error("Unable to load SMD from " + smd);
52                                }else{
53                                        processSmd(dojo.fromJson(text));
54                                }
55                        }else{
56                                processSmd(smd);
57                        }
58                }
59
60                this._options = (options ? options : {});
61                this._requestId = 0;
62        },
63
64        _generateService: function(serviceName, method){
65                if(this[method]){
66                        throw new Error("WARNING: "+ serviceName+ " already exists for service. Unable to generate function");
67                }
68                method.name = serviceName;
69                var func = dojo.hitch(this, "_executeMethod",method);
70                var transport = dojox.rpc.transportRegistry.match(method.transport || this._smd.transport);
71                if(transport.getExecutor){
72                        func = transport.getExecutor(func,method,this);
73                }
74                var schema = method.returns || (method._schema = {}); // define the schema
75                var servicePath = '/' + serviceName +'/';
76                // schemas are minimally used to track the id prefixes for the different services
77                schema._service = func;
78                func.servicePath = servicePath;
79                func._schema = schema;
80                func.id = dojox.rpc.Service._nextId++;
81                return func;
82        },
83        _getRequest: function(method,args){
84                var smd = this._smd;
85                var envDef = dojox.rpc.envelopeRegistry.match(method.envelope || smd.envelope || "NONE");
86                var parameters = (method.parameters || []).concat(smd.parameters || []);
87                if(envDef.namedParams){
88                        // the serializer is expecting named params
89                        if((args.length==1) && dojo.isObject(args[0])){
90                                // looks like we have what we want
91                                args = args[0];
92                        }else{
93                                // they provided ordered, must convert
94                                var data={};
95                                for(var i=0;i<method.parameters.length;i++){
96                                        if(typeof args[i] != "undefined" || !method.parameters[i].optional){
97                                                data[method.parameters[i].name]=args[i];
98                                        }
99                                }
100                                args = data;
101                        }
102                        if(method.strictParameters||smd.strictParameters){
103                                //remove any properties that were not defined
104                                for(i in args){
105                                        var found=false;
106                                        for(var j=0; j<parameters.length;j++){
107                                                if(parameters[j].name==i){ found=true; }
108                                        }
109                                        if(!found){
110                                                delete args[i];
111                                        }
112                                }
113
114                        }
115                        // setting default values
116                        for(i=0; i< parameters.length; i++){
117                                var param = parameters[i];
118                                if(!param.optional && param.name && !args[param.name]){
119                                        if(param["default"]){
120                                                args[param.name] = param["default"];
121                                        }else if(!(param.name in args)){
122                                                throw new Error("Required parameter " + param.name + " was omitted");
123                                        }
124                                }
125                        }
126                }else if(parameters && parameters[0] && parameters[0].name && (args.length==1) && dojo.isObject(args[0])){
127                        // looks like named params, we will convert
128                        if(envDef.namedParams === false){
129                                // the serializer is expecting ordered params, must be ordered
130                                args = dojox.rpc.toOrdered(parameters, args);
131                        }else{
132                                // named is ok
133                                args = args[0];
134                        }
135                }
136
137                if(dojo.isObject(this._options)){
138                        args = dojo.mixin(args, this._options);
139                }
140
141                var schema = method._schema || method.returns; // serialize with the right schema for the context;
142                var request = envDef.serialize.apply(this, [smd, method, args]);
143                request._envDef = envDef;// save this for executeMethod
144                var contentType = (method.contentType || smd.contentType || request.contentType);
145
146                // 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
147                return dojo.mixin(request, {
148                        sync: dojox.rpc._sync,
149                        contentType: contentType,
150                        headers: method.headers || smd.headers || request.headers || {},
151                        target: request.target || dojox.rpc.getTarget(smd, method),
152                        transport: method.transport || smd.transport || request.transport,
153                        envelope: method.envelope || smd.envelope || request.envelope,
154                        timeout: method.timeout || smd.timeout,
155                        callbackParamName: method.callbackParamName || smd.callbackParamName,
156                        rpcObjectParamName: method.rpcObjectParamName || smd.rpcObjectParamName,
157                        schema: schema,
158                        handleAs: request.handleAs || "auto",
159                        preventCache: method.preventCache || smd.preventCache,
160                        frameDoc: this._options.frameDoc || undefined
161                });
162        },
163        _executeMethod: function(method){
164                var args = [];
165                var i;
166                for(i=1; i< arguments.length; i++){
167                        args.push(arguments[i]);
168                }
169                var request = this._getRequest(method,args);
170                var deferred = dojox.rpc.transportRegistry.match(request.transport).fire(request);
171
172                deferred.addBoth(function(results){
173                        return request._envDef.deserialize.call(this,results);
174                });
175                return deferred;
176        }
177});
178
179dojox.rpc.getTarget = function(smd, method){
180        var dest=smd._baseUrl;
181        if(smd.target){
182                dest = new dojo._Url(dest,smd.target) + '';
183        }
184        if(method.target){
185                dest = new dojo._Url(dest,method.target) + '';
186        }
187        return dest;
188};
189
190dojox.rpc.toOrdered=function(parameters, args){
191        if(dojo.isArray(args)){ return args; }
192        var data=[];
193        for(var i=0;i<parameters.length;i++){
194                data.push(args[parameters[i].name]);
195        }
196        return data;
197};
198
199dojox.rpc.transportRegistry = new dojo.AdapterRegistry(true);
200dojox.rpc.envelopeRegistry = new dojo.AdapterRegistry(true);
201//Built In Envelopes
202
203dojox.rpc.envelopeRegistry.register(
204        "URL",
205        function(str){ return str == "URL"; },
206        {
207                serialize:function(smd, method, data ){
208                        var d = dojo.objectToQuery(data);
209                        return {
210                                data: d,
211                                transport:"POST"
212                        };
213                },
214                deserialize:function(results){
215                        return results;
216                },
217                namedParams: true
218        }
219);
220
221dojox.rpc.envelopeRegistry.register(
222        "JSON",
223        function(str){ return str == "JSON"; },
224        {
225                serialize: function(smd, method, data){
226                        var d = dojo.toJson(data);
227
228                        return {
229                                data: d,
230                                handleAs: 'json',
231                                contentType : 'application/json'
232                        };
233                },
234                deserialize: function(results){
235                        return results;
236                }
237        }
238);
239dojox.rpc.envelopeRegistry.register(
240        "PATH",
241        function(str){ return str == "PATH"; },
242        {
243                serialize:function(smd, method, data){
244                        var i;
245                        var target = dojox.rpc.getTarget(smd, method);
246                        if(dojo.isArray(data)){
247                                for(i = 0; i < data.length;i++){
248                                        target += '/' + data[i];
249                                }
250                        }else{
251                                for(i in data){
252                                        target += '/' + i + '/' + data[i];
253                                }
254                        }
255
256                        return {
257                                data:'',
258                                target: target
259                        };
260                },
261                deserialize:function(results){
262                        return results;
263                }
264        }
265);
266
267
268
269//post is registered first because it is the default;
270dojox.rpc.transportRegistry.register(
271        "POST",
272        function(str){ return str == "POST"; },
273        {
274                fire:function(r){
275                        r.url = r.target;
276                        r.postData = r.data;
277                        return dojo.rawXhrPost(r);
278                }
279        }
280);
281
282dojox.rpc.transportRegistry.register(
283        "GET",
284        function(str){ return str == "GET"; },
285        {
286                fire: function(r){
287                        r.url=  r.target + (r.data ? '?' + ((r.rpcObjectParamName) ? r.rpcObjectParamName + '=' : '') + r.data : '');
288                        return dojo.xhrGet(r);
289                }
290        }
291);
292
293
294//only works ifyou include dojo.io.script
295dojox.rpc.transportRegistry.register(
296        "JSONP",
297        function(str){ return str == "JSONP"; },
298        {
299                fire: function(r){
300                        r.url = r.target + ((r.target.indexOf("?") == -1) ? '?' : '&') + ((r.rpcObjectParamName) ? r.rpcObjectParamName + '=' : '') + r.data;
301                        r.callbackParamName = r.callbackParamName || "callback";
302                        return dojo.io.script.get(r);
303                }
304        }
305);
306dojox.rpc.Service._nextId = 1;
307
308dojo._contentHandlers.auto = function(xhr){
309        // automatically choose the right handler based on the returned content type
310        var handlers = dojo._contentHandlers;
311        var retContentType = xhr.getResponseHeader("Content-Type");
312        var results = !retContentType ? handlers.text(xhr) :
313                retContentType.match(/\/.*json/) ? handlers.json(xhr) :
314                retContentType.match(/\/javascript/) ? handlers.javascript(xhr) :
315                retContentType.match(/\/xml/) ? handlers.xml(xhr) : handlers.text(xhr);
316        return results;
317};
318
319return dojox.rpc.Service;
320
321});
Note: See TracBrowser for help on using the repository browser.